前言
SELinux是一种加强文件安全的一种策略,可以更好地保护我们的Android系统, 比如限制系统服务的访问权限、控制应用对数据和系统日志的访问等措施,这样就降低了恶意软件的影响,并且可以防止因代码存在的缺陷而产生的对系统安全的影响。
从系统安全方面考虑,SELinux是保护神,但是从软件开发方面,SELinux就是一道牵绊,这是一把双刃剑。SELinux默认开启,即使获得了该系统的root权限,也只能向相关策略中指定的设备写入数据,从而更好地保护和限制系统服务,保障系统和数据的安全。
环境
硬件平台:Google Pixel2
操作系统:Android10.0
selinux有两种工作模式
名称 | 作用 |
---|---|
permissive | 所有操作都被允许(即没有MAC),但是如果有违反权限的话,会记录日志 |
enforcing | 所有操作都会进行权限检查 |
标签、规则和域
SELinux 依靠标签来匹配操作和策略。标签用于决定允许的事项。套接字、文件和进程在 SELinux 中都有标签。SELinux 在做决定时需参照两点:一是为这些对象分配的标签,二是定义这些对象如何交互的策略。
在 SELinux 中,标签采用以下形式:user:role:type:mls_level,其中 type 是访问决定的主要组成部分,可通过构成标签的其他组成部分进行修改。对象会映射到类,对每个类的不同访问类型由权限表示。
策略规则采用以下形式:allow domains types:classes permissions;,其中:
名称 | 作用 |
---|---|
domain | 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。 |
type | 一个对象(例如,文件、套接字)或一组对象的标签。 |
class | 要访问的对象(例如,文件、套接字)的类型。Permission - 要执行的操作(例如,读取、写入)。 |
策略配置源文件
- external/sepolicy
这是独立于设备的配置,一般不能针对设备进行修改 - device///sepolicy
这是特定于设备的配置,基于 BOARD_SEPOLICY_* 变量来选择对应平台的策略配置。
Type Enforcement (TE) 配置文件
.te 文件中保存了对应对象的域和类型定义、规则。通常每个域一个 .te 文件,例如installd.te。在 device.te、file.te 中声明了设备和文件类型。在某些文件(例如domain.te、app.te)中则存储着共享规则。
标签配置文件
- file_contexts:文件安全上下文
- property_contexts:属性安全上下文
SEAndroid app分类
SELinux(或SEAndroid)将app划分为主要三种类型(根据user不同,也有其他的domain类型):
名称 | 作用 |
---|---|
untrusted_app | 第三方app,没有Android平台签名,没有system权限 |
platform_app | 有android平台签名,没有system权限 |
system_app | 有android平台签名和system权限 |
从上面划分,权限等级,理论上:untrusted_app < platform_app < system_app
user
user可以理解为UID。android的UID和linux的UID根本是两回事,Linux的UID是用于针对多用户操作系统中用于区分用户的,而Android中的UID是用于系统进行权限管理的。参考链接中的文章对于uid的产生讲的很清楚。
seinfo
不同签名会创建对应的selinux上下文。
Android.mk
LOCAL_CERTIFICATE := platform
有platform签名,所以seinfo是platform。
自定义安全策略
以上面两个运行的app来说,我们为这两个APP添加额外的权限,对应的TE配置文件分别就是system_app.te、untrusted_app.te,对应路径为:
java
$aosp/system/sepolicy/public/system_app.te
$aosp/system/sepolicy/public/untrusted_app.te
以longzhiye.example.app为例,我们为其添加can设备的执行权限:
java
longzhiye@longzhiye-laptop:~/mount/project/androidq$ vi system/sepolicy/public/system_app.te
java
......
allow system_app vendor_shell_exec:file { getattr open read execute execute_no_trans };
allow system_app shell_exec:file { getattr open read execute execute_no_trans };
allow system_app shell:file { getattr open read execute execute_no_trans };
......
以策略规则配置形式(allow domains types:classes permissions)
分析:
策略规则 | 示例 |
---|---|
domains | system_app |
types | vendor_shell_exec |
classes | file |
permissions | getattr open read execute execute_no_trans |
neverallow failures
有时我们增加的权限,系统默认的配置是不允许的,比如我们上面给forlinx.example.app增加的执行脚本的权限,报错如下:
java
libsepol.report_failure: neverallow on line 9 of system/sepolicy/private/system_app.te
(or line 41463 of policy.conf) violated by allow system_app shell:file { read open };
libsepol.report_failure: neverallow on line 22 of system/sepolicy/private/shell.te
(or line 40025 of policy.conf) violated by allow system_app shell:file { read open };
libsepol.check_assertions: 2 neverallow failures occurred
系统默认的安全策略的路径为system/sepolicy/,根据报错的提示,我们可以修改默认的配置,修改system/sepolicy/private/system_app.te和system/sepolicy/private/shell.te,从而完成权限的赋予。
安卓中快速编译sepolicy并验证(需要本地代码整编过一次,已经生成out目录)
java
$ mmm system/sepolicy/
$ adb push out/target/product/xxx/system/etc/selinux /system/etc/selinux
$ adb push out/target/product/xxx/vendor/etc/selinux /vendor/etc/selinux
也可单编systemimage,并刷机
java
$ make systemimage
$ adb reboot bootloader
$ fastboot flash system ./system.img
$ fastboot reboot
如何应对neverallow? 绕过CTS认证
在system/sepolicy/private/logpersist.te与system/sepolicy/prebuilts/api/29.0/private/logpersist.te中配置以下allow语句并编译,
会报neverallow的错。如下声明allow:
allow logpersist system_data_file:dir write;
这表示谷歌不允许我们使用allow语句,解除限制的最暴力方法就是将报错处的neverallow语句删掉,这样确实可行,但是会过不了cts。
由于我们要访问的目录path为/data/syslog,将该目录定义成自己的Type,可以自定义Type,如下:
在file.te中自定义一个type为file_type,data_file_type,core_data_file_type:
- type log_data_file, file_type, data_file_type, core_data_file_type;
在file_contexts中定义安全上下文: - /data/syslog(/.*)? u:object_r:log_data_file:s0
在logpersist.te将allow语句改为: - allow logpersist log_data_file write;
然后在logpersist.te中单独将自定义的log_data_file减去即可。(这里最好的是自定义一个service代替logpersist,那就要新建一个te文件了,比较麻烦)
java
neverallow logpersist {
file_type
userdebug_or_eng(`-misc_logd_file -coredump_file')
with_native_coverage(`-method_trace_data_file')
-log_data_file
}:file { create write append };
如何新增domian域?(一般在平台相关目录下添加)
例子如下
在device/平台名/system/private/file_contexts 文件添加
java
# tcontext=u:object_r:sysfs:s0
/sys/kernel/display/abcd u:object_r:wxl_abcd:s0 #wxl_abcd替换sysfs,wxl_abcd随便取
在device/平台名/system/public/file.te 中添加
java
type wxl_cabc, fs_type,sysfs_type;
在 device/平台名/system/private/system_server.te 文件中添加
java
allow system_server wxl_abcd:file { r_file_perms w_file_perms rw_file_perms };
添加 write 或者 read 的权限要注意 open 的权限,最后使用 r_file_perms、w_file_perms、rw_file_perms。
添加设备文件节点权限(sysfs gpio管脚节点权限)?
/sys/class/leds/green/brightness //快捷方式
/sys/devices/soc.0/gpio-leds.66/leds/green/brightness //实际节点
操作LED灯的设备文件节点为APP层system app进程开放该节点访问权限(读或写),权限配置主要修改(一般在/device/平台/sepolicy/common)目录下的file.te、file_contexts和system_app.te三个文件
(1)file.te修改如下:
GPIO accessed by system app
java
type sysfs_gpio, fs_type, sysfs_type;
(2)file_contexts修改如下:
java
/sys/devices/soc/1010000.pinctrl/gpio/gpio62/value u:object_r:sysfs_gpio:s0
/sys/devices/soc/1010000.pinctrl/gpio/gpio63/value u:object_r:sysfs_gpio:s0
(3)system_app.te修改如下:
java
allow system_app sysfs_gpio:file rw_file_perms;
如果通过以上添加SELinux之后,仍没有权限读写sys或proc节点,需要到/system/core/rootdir/init.rc里面配置如下:
(1)修改设备节点用户所有者和所属用户组,以及它们所对应的权限
chown system system 设备文件结点
chmod 777 设备文件结点
修改selinux没有生效???
将SELinux Policy 文件存放在下面目录
(1) Google 原生目录 /system/sepolicy
(2) 厂商配置目录 /device/厂商平台/sepolicy/
android将SELinux Policy 文件存放的te一般都是在device/平台/sepolicy 和 /system/sepolicy两个目录下
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀