4. 设备节点权限模型:Linux文件权限(rwx)、设备节点默认权限、权限对HAL层访问的影响
设备节点是用户空间与内核驱动交互的“门把手”。Linux 内核通过标准的文件权限模型(rwx)控制对设备节点的访问。HAL 层作为用户空间守护进程,必须拥有正确的权限才能打开设备节点并执行 IOCTL、read、write 等操作。本章深入剖析设备节点权限的构成、默认规则以及权限不足对 HAL 层造成的典型故障。
4.1 Linux 文件权限模型(rwx)回顾
Linux 使用 9 位权限位(Owner / Group / Others)控制文件或设备节点的访问能力,外加 3 位特殊权限位(SUID、SGID、Sticky)。对于设备节点,核心关注三类操作:
| 权限位 | 数值 | 对设备节点的含义 |
|---|---|---|
r (读) |
4 | 允许 read() 系统调用;部分驱动在 open() 时检查读权限 |
w (写) |
2 | 允许 write() 系统调用;多数字符设备需要写权限才能发送命令 |
x (执行) |
1 | 对设备节点无意义(目录才使用);通常置为 0 |
open() 系统调用会同时检查权限位和 fmode 标志。即使进程具有 root 权限,如果驱动实现的 open() 回调中做了额外的权限校验(如 capabilities 检查),仍可能拒绝访问。
4.2 设备节点默认权限的生成规则
设备节点的默认权限由 udev(或 mdev/devtmpfs)在设备创建时根据内核提供的 devnode 回调、udev 规则文件以及 umask 共同决定。默认权限通常为 0660(rw-rw----),即所有者和所属组可读写,其他用户无任何权限。
- 内核驱动调用
device_create()或misc_register()创建设备。 - 内核
devtmpfs在/dev下创建设备节点,初始权限由devnode回调返回的umode_t决定。 - udev 监听到
uevent,根据/etc/udev/rules.d/中的规则文件修改权限、所有者和组。 - 最终生效的权限 = udev 规则覆盖后的结果。
4.3 udev 规则对设备节点权限的定制
实际产品中,HAL 层通常以非 root 用户(如 system、bluetooth、cameraserver)运行。必须通过 udev 规则将设备节点的组设置为 HAL 进程所属的组,并赋予 0660 或 0666 权限。典型的 udev 规则文件位于 /etc/udev/rules.d/99-custom-device.rules:
# 示例:为 GPIO 设备节点设置权限
KERNEL=="gpio*", SUBSYSTEM=="gpio", MODE="0660", GROUP="gpio"
# 示例:为 I2C 设备节点设置权限
KERNEL=="i2c-[0-9]*", SUBSYSTEM=="i2c", MODE="0660", GROUP="i2c"
# 示例:为传感器设备节点设置权限
KERNEL=="sensor*", SUBSYSTEM=="misc", MODE="0664", GROUP="sensors"
MODE 设置为 0660 但 GROUP 写错或缺失,HAL 进程将无法打开设备节点。open() 返回 EACCES(Permission denied),导致 HAL 服务初始化失败。
4.4 权限对 HAL 层访问的影响分析
HAL 层访问设备节点时,权限不足会引发以下典型故障:
| 权限问题 | HAL 层表现 | 内核日志 | 解决方案 |
|---|---|---|---|
| 节点不存在 | open() 返回 -1,errno = ENOENT |
无 | 检查驱动是否加载,udev 是否创建节点 |
| 节点权限为 0600,HAL 非 owner | open() 返回 -1,errno = EACCES |
无(或 audit 日志) | 修改 udev 规则,设置 MODE="0660" 并指定 GROUP |
| 节点组正确但 MODE 为 0640 | HAL 可读但不可写,IOCTL 失败 | 无 | 将 MODE 改为 0660 或 0666 |
| SELinux 上下文错误 | open() 返回 -1,errno = EACCES |
avc: denied { open } | 添加 SELinux policy 允许 HAL 域访问设备节点 |
4.5 实战:权限排查与修复步骤
当 HAL 层报告设备节点访问失败时,按以下步骤快速定位权限问题:
- 确认节点存在:
ls -l /dev/<device_name>,检查主次设备号是否正确。 - 检查节点权限和属主: 确认
MODE、OWNER、GROUP是否符合预期。 - 确认 HAL 进程身份:
ps -A | grep hal或cat /proc/<pid>/status | grep Uid。 - 验证进程是否在目标组中:
id <hal_user>查看补充组列表。 - 检查 SELinux 策略:
audit2allow -a或dmesg | grep avc。 - 临时修复验证:
chmod 0666 /dev/<device_name>或chgrp <hal_group> /dev/<device_name>(仅调试用)。
devices 或 file_contexts 配置设备节点的 SELinux 标签和权限。
4.6 权限模型与 HAL 层架构的协同
在典型的 HAL 层架构中,权限模型的分层职责如下:
| 层级 | 职责 | 权限相关操作 |
|---|---|---|
| Linux 内核 | 提供设备节点,执行 DAC 检查 | 通过 devnode 回调设置初始权限 |
| udev / devtmpfs | 动态创建设备节点,应用规则 | 修改 MODE、OWNER、GROUP |
| SELinux / AppArmor | 提供 MAC 强制访问控制 | 定义域转换和访问向量 |
| HAL 守护进程 | 打开设备节点,执行 IOCTL | 以特定用户/组身份运行,继承权限 |
| HAL 客户端(Framework) | 通过 Binder/HIDL 调用 HAL | 不直接访问设备节点,依赖 HAL 进程权限 |
理解设备节点权限模型是 HAL 层驱动开发的基石。权限配置错误是 HAL 层“设备打开失败”故障的首要原因。掌握 rwx 权限位、udev 规则定制以及 SELinux 策略编写,能够帮助开发者快速定位并修复访问控制问题,确保 HAL 层与内核驱动的稳定通信。