4. Vendor 分区 SELinux 策略:上下文与 AVC 排查
在 Vendor 分区定制与 HAL 驱动部署过程中,SELinux 策略配置错误是导致服务启动失败、设备节点访问被拒、属性读写异常的最常见原因。本章聚焦 Vendor 分区相关的核心 SELinux 上下文:vendor_file、vendor_init 进程,以及 AVC denial 的系统化排查方法。
4.1 Vendor 分区 SELinux 基础架构
Android 从 Treble 架构开始,将系统分区与 Vendor 分区的 SELinux 策略分离。Vendor 分区拥有独立的 file_contexts、property_contexts 和 sepolicy 文件,确保 OEM 定制不会破坏系统分区的安全基线。
4.2 vendor_file 上下文详解
vendor_file 是 Vendor 分区文件系统的默认类型,所有位于 /vendor 下的文件、目录、符号链接都必须通过 file_contexts 文件赋予正确的上下文。
4.2.1 常见 vendor_file 上下文类型
| 上下文类型 | 适用路径 | 说明 |
|---|---|---|
vendor_file |
/vendor/* |
默认文件类型,只读 |
vendor_exec |
/vendor/bin/* |
可执行文件,允许执行 |
vendor_configs_file |
/vendor/etc/* |
配置文件,只读 |
vendor_lib_file |
/vendor/lib[64]/* |
共享库文件 |
vendor_firmware_file |
/vendor/firmware/* |
固件文件 |
4.2.2 file_contexts 配置示例
# 文件: device/<oem>/<device>/file_contexts
/vendor/bin/hw/android\.hardware\.camera\.provider@2\.4-service u:object_r:hal_camera_exec:s0
/vendor/etc/init/android\.hardware\.camera\.provider@2\.4-service\.rc u:object_r:vendor_configs_file:s0
/vendor/lib64/hw/camera\.msm8998\.so u:object_r:vendor_lib_file:s0
/vendor/firmware/cpp_firmware_v1.* u:object_r:vendor_firmware_file:s0
file_contexts 中为可执行文件添加 _exec 后缀类型(如 hal_camera_exec),否则 init 无法执行该二进制文件。
4.3 vendor_init 进程上下文
vendor_init 是 Vendor 分区 init 进程的 SELinux 域。所有在 /vendor/etc/init/ 下注册的服务,其启动进程默认运行在 vendor_init 上下文中。该域拥有对 Vendor 分区文件、属性的特定访问权限。
4.3.1 vendor_init 与 system_init 的权限对比
| 权限项 | system_init | vendor_init |
|---|---|---|
访问 /system 文件 |
允许 | 拒绝(默认) |
访问 /vendor 文件 |
允许 | 允许 |
设置 ctl.xxx 属性 |
允许 | 允许 |
访问 sysfs 设备节点 |
受限 | 受限 |
| 加载内核模块 | 拒绝 | 允许(需策略支持) |
4.3.2 vendor_init.te 策略示例
# 文件: device/<oem>/<device>/sepolicy/vendor/vendor_init.te
# 允许 vendor_init 访问 vendor 属性
allow vendor_init vendor_prop:property_service set;
# 允许 vendor_init 启动 vendor 服务
allow vendor_init vendor_init:process transition;
allow vendor_init hal_camera:process transition;
# 允许 vendor_init 读取 vendor 配置文件
allow vendor_init vendor_configs_file:dir r_dir_perms;
allow vendor_init vendor_configs_file:file r_file_perms;
vendor_init 域中启动失败,通常是因为缺少 process transition 权限。检查 neverallow 规则是否阻止了域转换。
4.4 常见 AVC Denial 排查方法
AVC(Access Vector Cache)Denial 是 SELinux 拒绝访问时产生的审计日志。排查 AVC Denial 是解决 Vendor 分区权限问题的核心技能。
4.4.1 获取 AVC 日志
AVC 日志可以通过以下命令获取:
# 实时查看 AVC 拒绝
adb shell logcat -b events | grep "avc: denied"
# 从内核日志中提取
adb shell dmesg | grep "avc: denied"
# 查看完整的审计日志
adb shell cat /sys/fs/selinux/avc/cache_stats
# 使用 audit2allow 工具分析
adb shell dmesg | grep "avc: denied" > avc_denials.txt
audit2allow -i avc_denials.txt
4.4.2 AVC Denial 日志解析
一条典型的 AVC Denial 日志包含以下字段:
type=1400 audit(123456.789:0): avc: denied { read } for pid=1234
comm="hal_camera" name="camera_config.xml" dev="mmcblk0p56" ino=5678
scontext=u:r:vendor_init:s0
tcontext=u:object_r:vendor_configs_file:s0
tclass=file permissive=0
| 字段 | 含义 | 排查要点 |
|---|---|---|
scontext |
源上下文(进程) | 确认进程是否运行在正确的域 |
tcontext |
目标上下文(文件/属性) | 确认文件标签是否正确 |
tclass |
对象类别 | file/dir/property_service 等 |
requested |
请求的权限 | read/write/execute/set 等 |
permissive |
是否宽容模式 | 0=强制拒绝,1=仅记录 |
4.4.3 系统化排查步骤
- 确认问题现象: 服务启动失败?设备节点无法访问?属性设置无效?
- 收集 AVC 日志: 使用
logcat -b events和dmesg同时抓取。 - 解析日志字段: 提取
scontext、tcontext、tclass、requested。 - 检查文件上下文: 使用
ls -Z确认目标文件的实际标签。 - 检查进程上下文: 使用
ps -Z确认进程运行域。 - 生成策略补丁: 使用
audit2allow或手动编写.te文件。 - 验证修复: 重新编译 Vendor 分区,刷机验证。
permissive 域,那会绕过所有安全检查。
4.5 常见 AVC Denial 场景与解决方案
| 场景 | 典型 AVC 日志 | 解决方案 |
|---|---|---|
| HAL 服务无法执行 | avc: denied { execute } for comm="init" scontext=u:r:vendor_init:s0 tcontext=u:object_r:vendor_file:s0 tclass=file |
将 HAL 二进制文件上下文改为 hal_xxx_exec,添加 allow vendor_init hal_xxx_exec:file execute; |
| 无法读取配置文件 | avc: denied { read } for comm="hal_camera" scontext=u:r:hal_camera:s0 tcontext=u:object_r:vendor_configs_file:s0 tclass=file |
添加 allow hal_camera vendor_configs_file:file r_file_perms; |
| 无法设置系统属性 | avc: denied { set } for comm="vendor_init" scontext=u:r:vendor_init:s0 tcontext=u:object_r:system_prop:s0 tclass=property_service |
确认属性上下文是否为 vendor_prop,添加 allow vendor_init vendor_prop:property_service set; |
| 无法访问设备节点 | avc: denied { read write } for comm="hal_sensors" scontext=u:r:hal_sensors:s0 tcontext=u:object_r:device:s0 tclass=chr_file |
为设备节点添加 u:object_r:hal_sensors_device:s0 上下文,添加 allow hal_sensors hal_sensors_device:chr_file rw_file_perms; |
4.6 调试技巧与工具
- 临时宽容模式:
adb shell setenforce 0可临时关闭 SELinux 强制模式,用于快速验证是否为 SELinux 问题。生产环境禁止使用。 - 使用 audit2allow: 将 AVC 日志重定向到文件,运行
audit2allow -i avc.txt自动生成 allow 规则。 - 检查文件上下文:
adb shell ls -Z /vendor/bin/hw/确认所有文件都有正确的标签。 - 检查进程上下文:
adb shell ps -Z | grep vendor确认进程运行在预期的域中。 - 使用 sesearch:
sesearch --allow -s vendor_init -t vendor_file -c file -p read查询策略中是否已包含某条规则。
BoardConfig.mk 中设置 BOARD_VENDOR_SEPOLICY_DIRS 指向自定义策略目录,可以避免修改系统分区的 sepolicy 文件,保持 Treble 兼容性。
4.7 本章小结
Vendor 分区的 SELinux 策略是 HAL 驱动部署的“安全门禁”。掌握 vendor_file 上下文配置、vendor_init 进程域管理以及 AVC Denial 的系统化排查方法,能够解决 90% 以上的 Vendor 分区权限问题。记住:正确的上下文 + 精确的 allow 规则 = 稳定的 Vendor 分区运行环境。