查看设备当前的SELinux方法
adb shell getenforce
临时切换SELinux模式:
Permissive: adb shell setenforce 0
Enforce: adb shell setenforce 1
在选择强制执行级别时只能二择其一,一般出厂的设备都要求强制模式,开发时在宽容模式解决完所有的权限问题后将会切换到强制模式。
SELinux是一种基于域-类型(domain-type)模型的强制访问控制(MAC)安全系统,它有几个概念我们先了解下:
对象(object):例如文件、进程、套接字、系统属性、IPC等系统资源
类型(type):SELinux中所有的对象都会有对应的类型,这样才能根据类型实施不同的策略。举例, 默认情况下,应用的类型为 untrusted_app.
域(daemain):对于进程而言,其类型也称为域
属性(attribute):属性是多个具有共性的类型的集合
上下文(context):也称为标签,SELinux给Linux的所有对象都分配一个安全上下文(Security Context), 描述成一个标准的字符串
通过ps -Z和ls -Z命令看到的所有的进程和文件的安全上下文
格式: user:role:type[:range]
举例: u:r:untrusted_app:s0
说明:
1、u为user的意思。SEAndroid中只定义了一个SELinux用户,值为u。
2、r为role的意思。role是角色之意,它是SELinux中一种比较高层次,更方便的权限管理思路,一个u可以属于多个role,不同的role具有不同的权限,SEAndroid也只定义了一个SELinux角色r。
3、untrusted_app,代表该进程所属的类型untrusted_app, 进程的类型称为Domain
4、S0和SELinux为了满足军用和教育行业,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问。
策略(policy): SEAndroid安全机制主要是使用对象安全上下文中的类型来定义安全策略,策略是具体实施的规则,策略文件位于各级sepolicy目录下,后缀为".te"的文件
SELinux 上下文标签,为了支持平台和供应商 sepolicy 之间的区别,系统以不同的方式构建上下文文件以使它们分开, 使用这些上下文给系统对象分配标签。SEAndroid主要的上下文有以下几种
文件上下文file_contexts:
作用:用于为文件分配标签,并且可供多种用户空间组件使用
属性上下文property_contexts
作用:用于声明属性的安全上下文,以便控制哪些进程可以设置这些属性
服务上下文service_contexts
作用:用于为 Android Binder 服务分配标签,以便控制哪些进程可以为相应服务添加(注册)和查找(查询)Binder 引用,service_contexts对应使用servicemanager(binder)的服务上下文,hwservice_contexts对应使用hwservicemanager(hwBinder)的服务上下文
Seapp 上下文 seapp_contexts
作用:用于为应用进程和 /data/data 目录分配标签。在每次应用启动时,zygote 进程都会读取此配置;在启动期间,installd 会读取此配置。
mac_permissions.xml
作用:用于根据应用签名和应用软件包名称(后者可选)为应用分配 seinfo 标记
值得注意的是vendor定制的目录下对应的上下文的名字一般都不会加前缀,和平台的对应文件保持一致,system的上下文和vendor的上下文会在init进程中一起加载。
系统为我们预定于了很对规则,可分类为:
这里主要是解决我们在开发中在日志获取到的avc denied的解决,因为selinux权限问题90%的场景都是在补足缺少的权限,这里有一个通用的方法帮我们解决此类问题,步骤如下:
首先获取avc的打印信息,可以通过logcat或者dmsg获取,一般logcat |grep avc就可以获取
举例:
type=1400 audit(0.0:1639): avc: denied { read } for name="u:object_r:hwservicemanager_prop:s0" dev="tmpfs" ino=2257 scontext=u:r:tcl_factory_service_default:s0 tcontext=u:object_r:hwservicemanager_prop:s0 tclass=file permissive=1
这里我们先介绍下对应的字段的概念:
操作权限 - action 具体缺少的权限,这个权限属于tclass组
源上下文 - scontext 发起者对象的类型
目前上下文 - tcontext 正在操作的对象类型
目标类 - tclass 正在操作的对象的类型
说的简单一点就是:
缺少什么权限: { read }权限,
谁缺少权限: scontext=u:r:tcl_factory_service_default:s0
对谁操作时缺少权限: tcontext=u:object_r:hwservicemanager_prop:s0
什么类型的权限: tclass=file
得出的权限解决语句:
# tcl_factory_service_default.te
allow tcl_factory_service_default hwservicemanager_prop:file { read };
总结出的通用公式:
要添加的权限语句: allow scontext tcontext:tclass { action };
要添加的目标文件: {scontext}.te
audit2allow是一个开源的工具,可帮助我们从avc日志中生成需要添加的权限语句。但是这个工具只是辅助,因为有时候它会给很泛的权限,虽然解决了问题,但是范围给的太大了,不安全。
使用前记得source lunch下环境就可以在根目录下使用。可执行文件的位置:
external/selinux/prebuilts/bin/audit2allow
使用方法1,从dmsg中提取:
(1) 提取所有的avc LOG.
adb shell "cat /proc/kmsg | grep avc" > avc_log.txt
(2) 使用 audit2allow tool直接生成policy.
audit2allow -i avc_log.txt 即可自动输出生成的policy
使用方法2,从系统专门的文件中提取(google推荐)
adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy
使用方法3,从logcat提取
adb logcat -b all -d | audit2allow -p policy
例子1:为一个system分区的native服务添加权限(google的例子)
service foo /system/bin/foo
class core
# foo service
type foo, domain;
type foo_exec, exec_type, file_type;
init_daemon_domain(foo)
/system/bin/foo u:object_r:foo_exec:s0
在device.mk中添加这个文件,或者拷贝对应的可执行文件(确保刷机起来后/system/bin/foo存在)
编译并烧录
根据avc denied提示,使用上面的通用公式添加缺少的权限
例子2: (HIDL|AIDL) HAL新服务添加selinux权限
例子3: JAVA 新服务添加selinux权限
例子4: 设备节点添加selinux服务
SELinux neverallow规则用于禁止在任何情况下都不应该发生的行为, 即会影响安全性的绝不允许的规则,删除neverallow节点将无法通过CTS认证。但是有时候我们的定制需求又需要解决某个权限被neverallow的情况,那么我们就得尝试如何绕开这个规则限制,只是争取绕开,没有什么万能的方法。
例子:logpersist访问data/p1路径
由于我们要访问的目录path为/data/p1,将该目录定义成自己的Type,可以自定义Type,如下:
在file.te中自定义一个type:
type p1_data_file, file_type, data_file_type, core_data_file_type;
在file_contexts中定义安全上下文:
/data/p1(/.*)? u:object_r:p1_data_file:s0
在logpersist.te将allow语句改为:
allow logpersist p1_data_file:dir write;
然后在logpersist.te中单独将自定义的p1_data_file减去即可。
neverallow logpersist {
file_type
userdebug_or_eng(`-misc_logd_file -coredump_file')
with_native_coverage(`-method_trace_data_file')
-p1_data_file
}:file { create write append };
经常困扰的问题: