作为底层开发人员,如果不了解SELinux,设计的程序不能访问某个文件或属性值,将很受折磨。
先来看看SELinux用途,旨在增强Linux系统的安全性。
如何来保障安全性呢?接下来从SElinux运行机制剖析。
Linux 内核资源访问控制分为 DAC(Discretionary Access Control,自主访问控制)和MAC(Mandatory Access Control,强制访问控制)两类。
DAC
基于“用户-用户组-其他”的“读、写、执行”的权限检查,进程理论上所拥有的权限与执行它的用户的权限相同,该管理过于宽松,如果获得 root 权限,可以在 Linux 系统内做任何事情。
MAC
SELinux(Security-Enhanced Linux,安全增强型 Linux)是 MAC 机制的一种实现,基于安全上下文和安全策略的安全机制,用于补充 DAC 检查。访问系统资源时,会先进行 DAC 检查,DAC检查通过,才能进行 MAC 检查,如果 MAC 检查通过,才能获得资源访问权限。
工作流程如下:
1,SELinux工作模式
支持三种工作模式,分别是enforcing(强制模式)、permissive(宽容模式)和disabled(关闭模式)。在enforcing模式下,所有违反SELinux策略的行为都会被阻止并记录到日志中;在permissive模式下,违规行为只会被记录而不会被阻止,通常用于调试;而在disabled模式下,SELinux功能被关闭。
2,Security Context安全上下文
SELinux为系统中的每个文件、进程和服务都分配了一个安全上下文,也称为SELinux标签。这些上下文包含了安全相关的属性,如用户身份、角色、类型等。SELinux策略规则基于这些上下文来决定是否允许某个操作执行。
两种类型:
主体(subject):可以等同于进程,即进程domain
客体(object):进程访问的各类资源,文件,端口,服务等,由于客体绝大多数情况下都是文件,为了便于描述,下面在描述中把客体等同于文件。
在启动selinux后,系统中所有的资源(文件,端口,服务,进程等)都会被打上标签(label),这就是安全上下文(security context),selinux就是通过这些标签来辅助完成访问控制的。
安全上下文由4段组成:user:role:type:range
User:用户,非Linux UID;
Role:角色;
Type:Subject或者Object的类型。
Range:Multi-Level Security(MLS)的级别。(例如s0,s1:c0,s7:c10.c15)
1,允许应用访问文件
type input_device, dev_type;
allow hal_camera input_device:chr_file read;
2,允许应用访问属性key
type camera_prop, property_type;
persist.camera. u:object_r:camera_prop:s0 //persist.camera.后所有组成的属性属于camera_prop
set_prop(hal_camera, camera_prop) //允许hal_camera进程访问camera_prop
set_prop(cameraserver, camera_prop)
set_prop(system_app, camera_prop)
可参照源码
http://androidxref.com/9.0.0_r3/search?q=camera_prop&project=device
在本地编译验证selinux权限能够大大提高效率。
1,编译命令:
make selinux_policy
编译成功后,结果保存在:
out/target/product/{project}/system/etc/selinux/
out/target/product/{project}/vendor/etc/selinux/
2,编译产物push到对应目录
将上面两个目录下的文件分别push到手机对应的目录下:
adb push out/target/product/{project}/system/etc/selinux/* /system/etc/selinux/
adb push out/target/product/{project}/vendor/etc/selinux/* /vendor/etc/selinux/
之后重启手机:adb reboot,修改的selinux即可生效。
3,使用指令查看文件上下文信息
ls -Z
一般出错log格式一般如下:
avc: denied { 操作权限 } for pid=XX comm=“进程名” scontext=u:r:源类型:s0 tcontext=u:r:目标类型:s0 tclass=访问类型 permissive=0
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
上面log表示拒绝,解析如下:
操作{open} - 被拒绝的操作是open。
操作方 - scontext(来源环境)条目表示操作方;在此例中对应为 mediaserver进程。
对象 - tcontext(目标环境)条目表示对哪个对象执行操作;在此例中对应为 device。
结果 - tclass(目标类别)条目表示操作对象的类型;在此例中为 chr_file(字符设备)。
解决如下:
allow mediaserver device:chr_file open;