Android系统SELinux详解

前言

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 - 要执行的操作(例如,读取、写入)。

策略配置源文件

  1. external/sepolicy
    这是独立于设备的配置,一般不能针对设备进行修改
  2. device///sepolicy
    这是特定于设备的配置,基于 BOARD_SEPOLICY_* 变量来选择对应平台的策略配置。

Type Enforcement (TE) 配置文件

.te 文件中保存了对应对象的域和类型定义、规则。通常每个域一个 .te 文件,例如installd.te。在 device.te、file.te 中声明了设备和文件类型。在某些文件(例如domain.te、app.te)中则存储着共享规则。

标签配置文件

  1. file_contexts:文件安全上下文
  2. 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:

  1. type log_data_file, file_type, data_file_type, core_data_file_type;
    在file_contexts中定义安全上下文:
  2. /data/syslog(/.*)? u:object_r:log_data_file:s0
    在logpersist.te将allow语句改为:
  3. 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老皮!!!欢迎大家来找我探讨交流👀

相关推荐
工业甲酰苯胺1 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
少说多做3431 小时前
Android 不同情况下使用 runOnUiThread
android·java
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯3 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey4 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!6 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟7 小时前
Android音频采集
android·音视频
小白也想学C8 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程8 小时前
初级数据结构——树
android·java·数据结构
闲暇部落10 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin