中间件SELinux权限配置

内容分享3小时前发布
0 0 0

一、 SELinux简单介绍

如下基础概念性内容来源为google网站,建议打开如下链接浏览,本文此部分为摘抄。

https://source.android.google.cn/security/selinux

1. SELinux 概念

Android 中的安全增强型 Linux(SELinux )按照**默认拒绝**的原则运行:

任何未经明确允许的行为都会被拒绝。

SELinux 可按两种全局模式运行:

宽容模式​:权限拒绝事件会被记录下来,但不会强制执行SELinux 安全政策。​强制模式​:权限拒绝事件会被记录下来并强制执行。

Android 中包含 SELinux(处于强制模式)和默认适用于整个 AOSP 的相应安全政策。在强制模式下,非法操作会被阻止,并且尝试进行的所有违规行为都会被内核记录到
dmesg

logcat
。开发时,您应该先利用这些错误信息对软件和 SELinux 政策进行优化,再对它们进行强制执行。

2. 标签、规则和域

SELinux 依靠**标签**来匹配操作和政策。标签用于决定允许的事项。套接字、文件和进程在 SELinux 中都有标签。SELinux 在做决定时需参照两点:一是为这些对象分配的标签,二是定义这些对象如何交互的政策。

标签格式

标签采用以下形式:
user:role:type:mls_level
,其中:


type
是访问决定的主要组成部分,可通过构成标签的其他组成部分进行修改。对象会映射到**类**,对每个类的不同访问类型由**权限**表示。

政策规则格式


allow domains types:classes permissions;

各字段说明:


Domain
– 一个进程或一组进程的标签(也称域类型)。
Type
– 一个对象(例如,文件、套接字)或一组对象的标签。
Class
– 要访问的对象(例如,文件、套接字)的类型。
Permission
– 要执行的操作(例如,读取、写入)。

规则示例


# 允许所有应用域读写带有 app_data_file 标签的文件
allow appdomain app_data_file:file rw_file_perms;

常用宏说明

上述规则依赖于
global_macros
文件中定义的宏,
te_macros
文件中还提供了其他实用宏(位于
system/sepolicy
目录,Android 8.0+ 在
public
子目录)。应尽可能使用这些宏,以降低权限被拒的风险。

域的典型示例

应用类型 域标签 权限等级
第三方应用 untrusted_app 最低
平台应用 platform_app 中等
系统 UID 应用 system_app 最高

禁止直接访问的通用标签

在任何情况下,都不应直接允许域访问以下通用标签;而应为一个或多个对象创建一个更具体的类型:

socket_devicedeviceblock_devicedefault_servicesystem_data_filetmpfs

3. 关键文件

SELinux 被设置为“默认拒绝”模式,这意味着,对于在内核中存在钩子的每一次访问,都必须获得政策的明确许可。通常情况下,您不能直接修改
system/sepolicy
文件,但可以添加或修改自己的设备专用政策文件(位于
/device/manufacturer/device-name/sepolicy
目录)。

3.1 政策文件


*.te
结尾的文件是 SELinux 政策源代码文件,用于定义域及其标签。您可能需要在
/device/manufacturer/device-name/sepolicy
中创建新的政策文件,但应尽可能尝试更新现有文件。

3.2 上下文的描述文件

用于为系统对象指定标签,核心文件如下:

文件名 用途 生效方式
file_contexts 为文件分配标签 重新构建映像或运行
restorecon
genfs_contexts 为不支持扩展属性的文件系统(proc/vfat)分配标签 重新启动设备或卸载重装文件系统
property_contexts 为系统属性分配标签,控制进程对属性的读写权限 启动时由 init 进程读取
service_contexts 为 Binder 服务分配标签,控制服务的注册和查询 启动时由 servicemanager 进程读取
seapp_contexts 为应用进程和
/data/data
目录分配标签
应用启动时由 zygote 读取;启动时由 installd 读取
mac_permissions.xml 根据应用签名和包名分配 seinfo 标记 启动时由 system_server 读取

3.3 BoardConfig.mk makefile

修改或添加政策文件和上下文描述文件后,需更新
/device/manufacturer/device-name/BoardConfig.mk
以引用
sepolicy
子目录和新政策文件:


BOARD_SEPOLICY_DIRS += 
        <root>/device/manufacturer/device-name/sepolicy

4. 自定义 SELinux

SELinux 采用白名单方法,仅授予政策中明确允许的访问权限。如需自定义 SELinux 设置,应遵循以下步骤和原则:

核心原则

使用最新的 Android 内核。采用**最小权限原则**。仅针对您向 Android 添加的内容调整政策(默认政策已适配 AOSP)。将软件组件拆分为多个单一功能模块。为模块创建隔离的 SELinux 政策。政策文件放在
/device/manufacturer/device-name/sepolicy
目录(
.te
扩展名),通过
BOARD_SEPOLICY
变量纳入编译。先将新域设为宽容域(便于调试)。分析拒绝日志并优化域定义。调试完成后移除宽容声明。

4.1 政策声明示例

SELinux 基于 M4 计算机语言,支持宏定义以简化配置。

完整权限声明

# 允许所有域读写 /dev/null
allow domain null_device:chr_file { getattr open read ioctl lock append write};
# 允许所有域只读访问 /dev/zero
allow domain zero_device:chr_file { getattr open read ioctl lock };
宏简化声明(推荐)

# 允许所有域读写 /dev/null
allow domain null_device:chr_file rw_file_perms;
# 允许所有域只读访问 /dev/zero
allow domain zero_device:chr_file r_file_perms;

4.2 neverallow 规则

SELinux
neverallow
规则用于禁止在任何情况下都不应该发生的行为。以下是关键规则示例及说明:

规则 48(禁止非授权进程使用 ptrace)

neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;

说明:
sys_ptrace
权限允许对任意进程执行 ptrace 命令,仅指定系统组件可享有该权限。如需该权限,通常表明存在不必要的功能,应移除相关组件。

规则 76(禁止执行非系统分区代码)

neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;

说明:仅允许执行
/system
分区中的代码,以保证启动时验证等安全机制。遇到该规则冲突时,应将违规代码移至
/system
分区。

5. 验证 SELinux

步骤 1:设置宽容模式

在 boot 的 bootargs 参数中加入:


androidboot.selinux=permissive

步骤 2:查看拒绝日志

SELinux 拒绝事件会记录到
dmesg

logcat
,日志包含“avc:”字样,可通过以下命令过滤:


# 查看当前拒绝事件
cat /proc/kmsg | grep avc
# 查看上次启动的拒绝事件
cat /sys/fs/pstore/console-ramoops | grep avc
# 实时查看 logcat 中的拒绝事件
logcat | grep avc

步骤 3:日志分析示例

日志示例

<5> type=1400 audit: avc:  denied  { read write } for  pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file
日志关键元素解析
元素 说明 示例值
操作 试图执行的操作 read write
操作方 进程的安全上下文(scontext) u:r:rmt:s0(rmt 域)
对象 目标资源的安全上下文(tcontext) u:object_r:kmem_device:s0(kmem_device 类型)
目标类别 操作对象的类型(tclass) chr_file(字符设备)
修复示例

针对上述日志,需在
rmt.te
文件中添加:


allow rmt kmem_device:chr_file { read write };

二、 中间件SELinux权限配置

1. 增加中间件sepolicy目录及mk文件

问题背景

中间件涉及不同芯片平台,若直接将 sepolicy 配置放在设备平台代码中,移植时需单独修改
BoardConfig.mk
,不利于公共模块维护。

解决方案

在中间件内部创建 sepolicy 目录,按 Android 版本和芯片平台分目录存放配置文件,并通过独立 mk 文件管理编译。

目录结构


vendor/xxx/driverBase/android/sepolicy/
├── AndroidP
└── AndroidQ
    ├── common
    └── platform
        └── mstar

sepolicy.mk 文件内容


# te for driverbase
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 29 && echo OK),OK)
BOARD_SEPOLICY_DIRS += vendor/skyworth/driverBase/android/sepolicy/AndroidQ/common
ifneq ($(filter mstar, $(LONGAN_TARGET_PLATFORM)),)
BOARD_SEPOLICY_DIRS += vendor/skyworth/driverBase/android/sepolicy/AndroidQ/platform/mstar
endif 
else
BOARD_SEPOLICY_DIRS += vendor/skyworth/driverBase/android/sepolicy/AndroidP
endif

BoardConfigCommon.mk 配置


/device/skyworth/芯片/common/BoardConfigCommon.mk
中添加:


# SELinux
include vendor/xxx/driverBase/sepolicy.mk

2. 增加中间件service对应的sepolicy配置文件

以 service
/vendor/bin/hw/vendor.skyworth.hardware.hwtv@1.0-service
为例,需完成以下配置:

2.1 增加hal_hwtvservice.te文件


# 声明hal_hwtvservice为一个域
type hal_hwtvservice, domain;

# 声明hal_hwtvservice的可执行程序类型
type hal_hwtvservice_exec, exec_type, file_type, vendor_file_type;

# 声明此service使用hwbinder(system分区进程通过hwbinder访问)
hwbinder_use(hal_hwtvservice);

# 声明此service使用vndbinder(vendor分区进程通过vndbinder访问)
vndbinder_use(hal_hwtvservice);

# init启动service时类型转换声明(宏)
# 将hal_hwtvservice_exec(客体)转换成hal_hwtvservice(进程域)
init_daemon_domain(hal_hwtvservice);

# 将service加入到hwservice_manager(通过hidl接口访问)
add_hwservice(hal_hwtvservice, hal_hwtvservice_hwservice);

2.2 在file_contexts里面增加service bin文件的声明


/(vendor|system/vendor)/bin/hw/vendor.skyworth.hardware.hwtv@1.0-service u:object_r:hal_hwtvservice_exec:s0

2.3 在hwservice.te文件中定义新加的service类型


type hal_hwtvservice_hwservice, hwservice_manager_type;

2.4 在hwservice_contexts文件中增加service的权限


vendor.skyworth.hardware.hwtv::IHwtv u:object_r:hal_hwtvservice_hwservice:s0

2.5 在service_contexts文件中增加service的权限


hwtvservice_1_0 u:object_r:hwtvservice_1_0_service:s0

2.6 配置其他进程/应用对此service的访问

允许platform_app访问


platform_app.te
中添加:


allow platform_app hal_hwtvservice_hwservice:hwservice_manager { find };
allow platform_app hal_hwtvservice:binder { call transfer };
允许system_app访问


system_app.te
中添加:


allow system_app hal_hwtvservice_hwservice:hwservice_manager { find };
allow system_app hal_hwtvservice:binder { call transfer };
配置原则

其他进程/应用的访问权限可先将 SELinux 设为宽容模式,根据
avc
警告信息逐步添加。

3. 中间件sepolicy配置实例说明

3.1 配置新增加分区的上下文

问题现象

查看 xxx 分区文件上下文,发现未正确配置(均为
system_file
类型):


ls -lZ /xxx
drwxrwxr-x 4 system system u:object_r:system_file:s0   4096 2020-11-09 10:35 app
-rw-rw-rw- 1 root   root   u:object_r:system_file:s0     43 2009-01-01 00:01 checksysVersion
配置步骤


file.te
中增加 xxx
_file
文件类型:


type xxx_file, file_type;


file_contexts
中声明
/x
xx 目录下的文件类型:


/xxx(/.*)?   u:object_r:xxx_file:s0


init.rc
中设置目录文件继承标签:


restorecon_recursive /xxx
验证结果

配置后文件上下文应显示为 xxx
_file
类型:


ls -lZ /xxx/app
drwxrwxr-x 4 system system u:object_r:xxx_file:s0   4096 2020-11-09 10:35 app

3.2 配置property属性的上下文

场景1:自定义属性访问权限
问题现象

自定义属性
third.get.facSingleKeyEnable
默认为
default_prop
类型,Android 10.0 不允许 vendor 下的 native service 访问,开机出现
avc
警告:


selinux: avc:  denied  { get } for property=third.get.facSingleKeyEnable pid=2507 uid=0 gid=0 scontext=u:r:hal_hwtvservice:s0 tcontext=u:object_r:default_prop:s0 tclass=property_service permissive=1
配置步骤


property.te
中增加自定义属性类型:


type vendor_xxx_default_prop, property_type;


property_contexts
中将自定义属性关联新类型:


third.get.facSingleKeyEnable     u:object_r:vendor_xxx_default_prop:s0


hal_hwtvservice.te
中添加访问权限:


get_prop(hal_hwtvservice, vendor_xxx_default_prop);  # 读权限
set_prop(hal_hwtvservice, vendor_xxx_default_prop);  # 写权限
场景2:系统属性访问权限(间接访问)
问题现象

系统属性
dev.bootcomplete

exported3_system_prop
类型,vendor 下的 native service 无法直接访问,开机出现
avc
警告:


selinux: avc:  denied  { get } for property=dev.bootcomplete pid=2507 uid=0 gid=0 scontext=u:r:hal_hwtvservice:s0 tcontext=u:object_r:exported3_system_prop:s0 tclass=property_service permissive=1
解决方案(属性转换)


vendor/etc/init/vendor.xxx.hardware.hwtv@1.0-service.rc
中添加属性转换:


on property:dev.bootcomplete=1
    setprop third.get.bootcomplete 1


property_contexts
中声明自定义属性类型:


third.get.bootcomplete     u:object_r:vendor_xxx_default_prop:s0


vendor_init.te
中添加
vendor_init
对属性的访问权限:


get_prop(vendor_init, vendor_xxx_default_prop);
set_prop(vendor_init, vendor_xxx_default_prop);
注意事项

若自定义属性无法触发
on property
动作,需在
system/core/init/stable_properties.h

kExportedActionableProperties
数组中添加白名单:


static const std::set<std::string> kExportedActionableProperties = {
    "dev.bootcomplete",
    "init.svc.console",
    // ... 其他默认属性
    "third.get.bootcomplete",  // 新增自定义属性
};

3.3 配置进程的上下文及用户

问题现象

查看
hwtvservice
进程上下文,发现以
root
用户运行,出现
dac_override
权限拒绝警告:


ps -AZ | grep hwtv
u:r:hal_hwtvservice:s0  root 2507 1 54768 17748 binder_thread_read 0 S vendor.xxx.hardware.hwtv@1.0-service

avc: denied { dac_override } for capability=1 scontext=u:r:hal_hwtvservice:s0 tcontext=u:r:hal_hwtvservice:s0 tclass=capability permissive=1
解决方案

修改 service 的运行用户为
system
,在
vendor/etc/init/vendor.xxx.hardware.hwtv@1.0-service.rc
中调整:


service hwtv-1-0 /vendor/bin/hw/vendor.skyworth.hardware.hwtv@1.0-service
    class early hal
    user system  # 改为system用户
    group root system audio input drmrpc  # 根据需求添加用户组

3.4 ioctl权限配置

问题背景

Android Q 增强了对
ioctl
的审查,除授权
ioctl
操作外,还需指定具体的
ioctlcmd

错误配置示例

直接授权
ioctl
会导致编译报错:


# 错误配置
allowxperm hal_hwtvservice proc_utopia: file ioctl;

ERROR 'syntax error' at token ';' on line 73660:
allowxperm hal_hwtvservice proc_utopia: file ioctl;
正确配置示例

需指定具体的
ioctlcmd
ID:


# 允许 hal_hwtvservice 对 proc_utopia 执行指定 ioctl 命令
allowxperm hal_hwtvservice proc_utopia:{ file } ioctl { 0x5501 0x5503 };

3.5 通用域的配置

问题现象

访问
/proc/apm
时出现权限拒绝,直接使用
proc
通用域配置会触发
neverallow
规则:


avc: denied { read } for comm="fsck" path="/proc/apm" dev="proc" scontext=u:r:fsck:s0 tcontext=u:object_r:proc:s0 tclass=file permissive=1

# 错误配置(触发neverallow)
allow fsck proc:file r_file_perms;
正确配置示例


file.te
中定义专用类型:


type proc_apm, fs_type, proc_type, mlstrustedobject;


genfs_contexts
中关联路径和类型:


genfscon proc /apm       u:object_r:proc_apm:s0


fsck.te
中添加访问权限:


allow fsck proc_apm:file r_file_perms;

三、 部分编译及验证

1. 部分编译命令

修改 SELinux 配置后,可单独编译 sepolicy 以提高效率:


mmm -j32 system/sepolicy 2>&1 | tee se.txt

MTK平台注意事项

MTK 平台部分编译通过后,完整编译前需执行
make mtk_clean
,否则可能报错。建议:

第一个工程用于部分编译验证 SELinux 配置。验证通过后,将修改合并到第二个工程,直接完整编译输出升级包。

2. 验证方法

步骤 1:拷贝编译产物

单独编译后,将输出目录的以下文件拷贝到测试设备:


system/etc/selinux/

vendor/etc/selinux/

步骤 2:自动化脚本(参考)

cpselinux.sh(拷贝输出文件到本地目录)

#!/bin/bash
# 拷贝 sepolicy 编译产物到 ~/selinuxOutputFile
OUTPUT_DIR=~/selinuxOutputFile
mkdir -p $OUTPUT_DIR/system/etc/selinux
mkdir -p $OUTPUT_DIR/vendor/etc/selinux

cp -r out/target/product/mt9652/system/etc/selinux/* $OUTPUT_DIR/system/etc/selinux/
cp -r out/target/product/mt9652/vendor/etc/selinux/* $OUTPUT_DIR/vendor/etc/selinux/

echo "SELinux files copied to $OUTPUT_DIR"
updateSe.sh(设备端覆盖selinux文件)

#!/bin/bash
# 从 U 盘拷贝 selinux 文件到设备
U盘路径=/mnt/usb
SYSTEM_SELINUX=/system/etc/selinux
VENDOR_SELINUX=/vendor/etc/selinux

# 挂载为可写
mount -o remount,rw /system
mount -o remount,rw /vendor

# 覆盖文件
cp -r $U盘路径/system/etc/selinux/* $SYSTEM_SELINUX/
cp -r $U盘路径/vendor/etc/selinux/* $VENDOR_SELINUX/

# 恢复只读
mount -o remount,ro /system
mount -o remount,ro /vendor

echo "SELinux files updated successfully"

步骤 3:验证流程


selinuxOutputFile
目录拷贝到 U 盘。U 盘插入设备,执行
updateSe.sh
脚本覆盖文件。重启设备,查看
dmesg

logcat
确认无
avc
拒绝日志。


四、 参考文档

Google 官方文档:Android 中的安全增强型 Linux

© 版权声明

相关文章

暂无评论

none
暂无评论...