Android的Sepolicy实际上是对SELinux安全策略的描述和设置。
什么是SELinux
安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是 Linux 的一个安全子系统。SELinux 主要作用是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。对资源的访问控制分为两类: DAC和MAC.
DAC
在未使用SELinux的系统上, 对资源的访问是通过权限位来确定, 比如一个文件对所属用户是否有读、写、执行权限, 其他用户的访问可由所属用户进行配置. 这种由所属用户自己决定是否将资源的访问权或部分访问权授予其他用户,这种控制方式是自主的,即自主访问控制(Discretionary Access Control, DAC).
ls -l可查看权限
> ls -l note -rw-rw-r-- 1 ifantsai ifantsai 37 6月 17 13:36 note
MAC
在使用了 SELinux 的系统上,对资源的访问除了通过权限位判定外,还需要判断每一类进程是否拥有对某一类资源的访问权限。这种方式对资源的访问控制, 称之为强制访问控制(Mandatory Access Control, MAC).只给每个进程开放所需要的资源, 将权限开放到最小, 当进程出现漏洞时也只会影响到该进程所涉及的资源, 这大大提升了安全性.
SELinux工作模式
SELinux 有三种工作模式,分别为:
- enforcing: 强制模式, 执行SELinux规则, 违反的行为会被阻止
- permissive: 宽容模式, 执行SELinux规则, 违反的行不会被阻止
- disabled: 关闭SELinux
通过执行getenforce
命令可以获取当前SELinux的工作模式。
SELinux与Android
SELinux是Google从android 5.0开始,强制引入的一套非常严格的权限管理机制,主要用于增强系统的安全性。然而,在Android系统开发中,我们经常会遇到由于SELinux造成的各种权限不足,即使拥有“万能的root权限”,也不能获取全部的权限。
为了澄清是否因为SELinux导致的问题,可以尝试将SELinux工作模式临时改为宽容模式看问题是否解决, 来判定是否是SELinux引起的问题.
# 修改工作模式为宽容模式
setenforce permissive
# 临时禁用SELinux
setenforce 0
# 获取当前sepolicy配置
getenforce
遇到权限问题时, 在log中会打印avc denied提示缺少什么权限, 可以通过dmesg | grep avc
过滤出所有avc denied.
如果问题消失了,基本可以确认是SELinux造成的权限问题,需要通过正规的方式来解决权限问题。
遇到权限问题,在logcat或者kernel的log中一定会打印avc denied提示缺少什么权限,可以通过命令过滤出所有的avc denied,再根据这些log各个击破:
cat /proc/kmsg | grep avc
或
dmesg | grep avc
例如:
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
可以看到有avc denied,且最后有permissive=0,表示不允许。
解决avc denied
解决原则是:缺什么权限补什么,一步一步补到没有avc denied为止。
解决权限问题需要修改的权限文件如下位置,以.te结尾
A:Android/devicesoftwinner/astar-common/sepolicy/*.te
B:Android/external/sepolicy/*.te
其中,A是对B的overlay(覆盖),能在A修改的尽量在A修改,尽量避免修改B,修改B可能会导致CTS fail问题,修改A不会影响CTS测试。
下面给出四个案例:
案例1
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=/1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
分析过程:
缺少什么权限: {undefined write }权限,
谁缺少权限: scontext=u:r:kernel:s0
对哪个文件缺少权限:tcontext=u:object_r:block_device
什么类型的文件: tclass=blk_file
完整的意思: kernel进程对block_device类型的blk_file缺少write权限。
解决方法:在上文A位置,找到kernel.te这个文件,加入以下内容:
allow kernel block_device:blk_file write;
make installclean后重新编译,刷boot.img才会生效
万能公式
通过案例,我们可以总结出一般规律,以下面为例
audit(1441759284.810:5): avc: denied { read } for pid=1494 comm="sdcard" name="0" dev="nandk" ino=245281 scontext=u:r:sdcardd:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0
某个scontext对某个tclass类型的tcontext缺乏某个权限,我们需要允许这个权限:
我们的log重新排列一下,
scontext = u:r:sdcardd
tcontex t= u:object_r:system_data_file:s0
tclass = dir
avc: denied { read }
在scontext所指的.te文件(例如sdcardd.te)中加入类似如下allow内容:
allow <scontext> <tcontext>:<tclass> {<avc: denied>}
案例2
在RK Android9.0上进行操作, 权限文件以.te
为后缀, 涉及到需要修改的路径:
android/device/rockchip/common/sepolicy
android/device/rockchip/rk3399/sepolicy
Android自带的进程服务通过以上目录配置即可 , 自己添加的第三方进程需要添加到自定义的目录下
以如下所示的avc denied为例讲解
# avc: denied { 操作权限 } for pid=7201 comm=“进程名” scontext=u:r:源类型:s0 tcontext=u:r:目标类型:s0 tclass=访问类别 permissive=0 avc: denied { read } for pid=7517 comm="audio@2.0-servi" name="u:object_r:default_prop:s0" dev="tmpfs" ino=11426 scontext=u:r:hal_audio_default:s0 tcontext=u:object_r:default_prop:s0 tclass=file permissive=0
主要关注以下内容:
denied {read}
: 表示缺少read权限scontext=u:r:hal_audio_default:s0
: 表示hal_audio_default缺少了权限tcontext=u:object_r:default_prop:s0
: 表示是对default_prop缺少了权限tclass=file
: 表示缺少权限的资源类型为file
因此只要在hal_audio_default.te文件中加入下面内容即可
allow hal_audio_default tcontext:file read;
如果需要赋予read, open权限, 当有多个权限时用{}
包裹
allow hal_audio_default tcontext:file { read open };
或者参考android/system/sepolicy/public/global_macros
中赋予一个复合权限, 如r_file_perms
表示{ getattr open read ioctl lock map }
参考链接:
SELinux之解决avc denied: https://www.caiyifan.cn/p/38175be7.html
Android SELinux avc dennied权限问题解决方法: https://blog.csdn.net/tung214/article/details/72734086