一、 概述
SELinux(Security Enhanced Linux)是一种在内核中实现的强制访问控制(MAC)系统。其通过预先定义的策略(policy),在系统启动和运行期间,控制所有访问和操作权限,防止未定义的权限被执行,以确保系统安全。
作为 Android 安全模块的一部分,Android 使用 SELinux 对所有的进程实施强制访问控制(MAC),即使运行在 root 权限或者超级用户权限的进程也会受到 SELinux 的强制访问控制。SELinux 通过限制特权进程和自动化的安全策略创建来加强 Android 安全。
通过 SELinux,Android 可以更好的保护和限制系统服务,控制进程对文件,应用程序数据以及系统日志的访问,减少恶意软件的影响,保护用户免受设备上潜在缺陷代码的影响。
需要 CTS(Compatibility Test Suite)认证的 Android 系统,必须开启 SELinux 强制模式(Enforcing),如下:
- CTS 禁止关闭 SELinux,测试项 testSELinuxEnforcing 应返回 Enforcing。
- CTS 禁止对 Android 原生策略进行修改(external/sepolicy/)。
海思 Android 解决方案在原生 Android 基础上,扩展了 SELinux 策略,以保证系统各模块获得相应运行权限。客户的任何修改,都要进行全面的 SELinux 配置验证。
二、功能描述
SELinux 已经被实现为 Linux 安全模型框架(LSM)的一部分,该框架会识别各种内核对象以及在该对象上运行的敏感操作。在敏感操作被执行前,一个 LSM 的钩子函数会被调用,该函数会根据存储在一个不透明安全对象中的信息来决定该敏感操作是否被允许。SELinux 为 LSM 的钩子函数提供了具体的实现,并且管理了这些安全对象。这些安全对象包含了各自的安全策略并且确定了访问控制。
2.1 源码路径
SELinux 源码路径如下:
源代码:external/selinux/libselinux
编译器:external/selinux/checkpolicy
原生策略:external/selinux/python/sepolicy
海思扩展策略:device/hisilicon/bigfish/external/sepolicy
引入海思策略:在 device/hisilicon/Hi3751V811/BoardConfig.mk 中(Hi3751V811 代表芯片类型,如 Hi3751 V811) 添加 include device/hisilicon/bigfish/external/sepolicy/BoardSepolicy.mk
32 位内核配置文件目录:device/hisilicon/bigfish/sdk/source/kernel/linux-4.9.y/arch/arm/configs/
64 位内核配置文件目录:device/hisilicon/bigfish/sdk/source/kernel/linux-4.9.y/arch/arm64/configs/
2.2 工作模式
SELinux 有以下三种工作模式,发布版本采用 Enforcing 模式。
Enforcing:强制使能状态,所有违反 policy 的动作都会被拒绝。
Permissive:宽容模式,违反 policy 的动作不会被拒绝,只会警告。
Disabled:完全禁用状态,内核配置项未使能。
设备端串口输入以下命令,设置宽容模式,并查看修改结果:
$ su
$ setenforce Permissive(或“setenforce 0”)
$ getenforce
三、开发指引
因为 SELinux 会检查所有进程的访问权限,所以源码修改后生成的镜像,都需要检查是否存在告警,并根据告警配置权限。
3.1 定义域
SELinux 通过定义域(domain)来表示系统进程的安全上下文(contexts)的属性。当系统开启 SELinux,但没有为进程定义域,串口会出现告警打印:
init: Warning! Service netshared needs a SELinux domain defined; please fix!
这里以 netshared 服务为例,介绍新增域定义及新增服务类型。
新增域定义
为可执行文件 netshared 增加域步骤如下:
步骤 1 新建策略文件 netshared.te,并使用 type 关键字,定义一个域 netshared。
device/hisilicon/bigfish/external/sepolicy/vendor/file_contexts 目录文件下添加如下代码:
/system/bin/netshared u:object_r:netshared_exec:s0
步骤 2 为 netshared 可执行文件定义自己的类型,并增加属性 exec_type,file_type。
步骤 3 添加 init_daemon_domain,表示 init 进程在执行 netshared 可执行文件时,自动将新进程的域设为 netshared。
device/hisilicon/bigfish/external/sepolicy/vendor/netshared.te 创建如下:
type netshared, domain;
type netshared_exec, exec_type, file_type;
init_daemon_domain(netshared)
新增服务类型
由于 netshared 进程通过 ServiceManager 注册了系统服务,所以需要在 service_contexts 中新增服务类型。添加服务的源代码如下:
defaultServiceManager()->addService(String16("HinetshareBService"), new HiNSService());
据已定义的域和声明的服务名称,新增服务类型需在服务域定义中新增服务域定义,在 service 策略文件中添加服务类型,并在 netshared 策略中添加 binder 和 service add 权限。
dvice/hisilicon/bigfish/external/sepolicy/system/private/service_contexts 添加如下:
HietshareBService u:object_r:netshared_service:s0
dvice/hisilicon/bigfish/external/sepolicy/vendor/service.te 添加如下:
type netshared_service, service_manager_type;
device/hisilicon/bigfish/external/sepolicy/vendor/netshared.te 创建如下:
binder_use(netshared)
binder_service(netshared)
binder_call(netshared, system_server)
allow netshared netshared_service:service_manager add;
注意:SystemService 添加的服务可以归入 system_server_service 域,不需要新增类型。
3.2 添加策略
应用或服务进行访问和操作时,SELinux 会检查定义的策略数据库,如果行为主体不拥有该操作的权限,系统会阻止该行为(Enforcing 模式),并打印告警。请根据告警内容添加相应策略。
以添加 USB 8822cu WiFi 模块为例,有如下告警信息:
dmesg | grep 8822 告警信息:
[ 122.072099] type=1400 audit(46.606:31): avc: denied { module_load } for pid=3102 comm="insmod" path="/vendor/lib64/modules/rtl8822cu.ko" dev="mmcblk0p19" ino=583 scontext=u:r:su:s0 tcontext=u:object_r:vendor_file:s0 tclass=system permissive=1
解决方法:
device/hisilicon/bigfish/external/sepolicy/vendor/hal_wifi_default.te 增加一行:
allow hal_wifi_default kernel:system { module_request };
logcat | grep wifi 告警信息:
01-01 08:00:12.966 1823 1823 W wifi@1.0-servic: type=1400 audit(0.0:21): avc: denied { module_request } for kmod="netdev-wlan0" scontext=u:r:hal_wifi_default:s0 tcontext=u:r:kernel:s0 tclass=system permissive=0
01-01 08:00:12.984 1823 1823 W wifi@1.0-servic: type=1400 audit(0.0:22): avc: denied { module_request } for kmod="wlan0" scontext=u:r:hal_wifi_default:s0 tcontext=u:r:kernel:s0 tclass=system permissive=0
解决方法:
device/hisilicon/bigfish/external/sepolicy/vendor/system_server.te 增加一行:
allow su vendor_file:system { module_load };
3.3 编译处理
当添加的策略违反原生策略时,编译无法通过。部分场景可以通过修改策略,解决问题。常见编译错误和解决方法如下:
系统中新增设备节点 /dev/mali,运行时会出现如下告警信息:
type=1400 audit(1388534400.286:4): avc: denied { open } for pid=1362 comm="surfaceflinger" path="/dev/mali" dev="tmpfs" ino=4278 scontext=u:r:surfaceflinger:s0 tcontext=u:object_r:device:s0 tclass=chr_file
根据告警中关键字段,在策略文件 surfaceflinger.te 中添加策略:
allow surfaceflinger device:chr_file { open };
修改策略后重新编译,出现错误:
neverallow on line 258 of external/sepolicy/domain.te (or line 5240 of policy.conf) violated by allow surfaceflinger device:chr_file {open };
解决方法:
因为 /dev/mali 是一个新增的设备节点,需要新定义设备名称,并关联到 dev_type 属性组里,请在策略文件中修改以下内容:
device/hisilicon/bigfish/external/sepolicy/vendor/file_contexts 添加如下:
/dev/mali u:object_r:mali_device:s0
device/hisilicon/bigfish/external/sepolicy/vendor/device.te 添加如下:
type mali_device, dev_type;
device/hisilicon/bigfish/external/sepolicy/vendor/surfaceflinger.te 添加如下:
allow surfaceflinger mali_device:chr_file {open};
注:如果应用或服务确实违反 Android 安全策略,请检视程序代码,按 Android 官方 API 实现所需操作。
3.4 验证方法
在源码下配置好策略后,编译版本,烧写镜像,系统运行后,查看相应场景下告警是否消失。
如果只修改策略文件,重新构建并烧写 kernel 即可。
如果修改了 contexts 文件,需要重烧 kernel、system。
如果告警中 platform_app 或 untrusted_app 的 tcontext 字段为 u:object_r:unlabeled:s0 ,需要重烧 userdata。
四、参考资料
《Android 解决方案 开发指南》
评论