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 定制不会破坏系统分区的安全基线。

关键原则: Vendor 分区内的所有文件、进程、属性都必须拥有正确的 SELinux 上下文,否则系统服务(如 HAL、init.rc 脚本)将因权限拒绝而无法正常运行。
Vendor 分区 SELinux 上下文关系图 vendor_file 文件/目录上下文 vendor_init 进程上下文 vendor_prop 属性上下文 /vendor/bin/* /vendor/etc/init/* /vendor/lib[64]/* AVC Denial 日志 → audit.log / dmesg 说明:vendor_file 定义文件标签,vendor_init 定义进程域,vendor_prop 定义属性访问规则。三者共同构成 Vendor 分区的 SELinux 策略骨架。

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
最佳实践: 新增 HAL 服务时,务必在 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;
常见错误: 如果 HAL 服务在 vendor_init 域中启动失败,通常是因为缺少 process transition 权限。检查 neverallow 规则是否阻止了域转换。
vendor_init 域下 HAL 服务启动流程 init 解析 .rc 文件 创建 vendor_init 进程 域转换检查 执行 HAL 二进制 AVC 审计日志 HAL 服务正常运行 提示:域转换失败时,进程会停留在 vendor_init 域,导致 HAL 服务无法获得应有的权限。

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 系统化排查步骤

  1. 确认问题现象: 服务启动失败?设备节点无法访问?属性设置无效?
  2. 收集 AVC 日志: 使用 logcat -b events 和 dmesg 同时抓取。
  3. 解析日志字段: 提取 scontext、tcontext、tclass、requested。
  4. 检查文件上下文: 使用 ls -Z 确认目标文件的实际标签。
  5. 检查进程上下文: 使用 ps -Z 确认进程运行域。
  6. 生成策略补丁: 使用 audit2allow 或手动编写 .te 文件。
  7. 验证修复: 重新编译 Vendor 分区,刷机验证。
排查口诀: 先看 scontext 对不对,再看 tcontext 准不准,最后补 allow 规则。不要盲目添加 permissive 域,那会绕过所有安全检查。
AVC Denial 系统化排查流程图 ① 确认问题现象 ② 收集 AVC 日志 ③ 解析日志字段 ④ 检查文件上下文 ⑤ 检查进程上下文 ⑥ 生成策略补丁 ⑦ 验证修复 问题解决? 否(回退到步骤④) 是(结束)

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 分区运行环境。