AOSP设备节点权限添加相关

81 阅读5分钟

要求

在一个工厂测试APP中,要测试一个按钮是否好用,驱动同事提供了一个设备节点/sys/class/fn_key/fn_key_gpio/fn,这个节点由于某些特殊原因,无法做成正常按钮那样来监听,只能不断读取这个节点来处理,当打开按钮时,节点值会变成1,关闭按钮会变成0,我需要做的是在工厂测试APP对应的测试项中一直读,这个操作可以用handler+runnable来处理。但是读取这个节点的时候会有权限问题,导致无法读取,节点权限报错提示如下:

image.png

12-30 18:54:08.147 4873 4873 W com.qti.factory: 
type=1400 audit(0.0:121): avc: denied { read } for name="fn" dev="sysfs" ino=96682 scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0

各部分含义:

字段解释
type=14001400SELinux审计日志的标准类型标识
avc: denieddenied表示访问被拒绝
{ read }read被拒绝的操作是"读取"
name="fn"fn要访问的文件名是"fn"
dev="sysfs"sysfs文件所在的设备是sysfs虚拟文件系统
**scontext=**​u:r:system_app:s0源上下文​ - 发起访问的进程
**tcontext=**​u:object_r:sysfs:s0目标上下文​ - 被访问的对象
**tclass=**​file目标类型是"文件"
permissive=00SELinux处于强制模式(1=宽容模式)

发生了什么?

  • 进程 system_app试图读取一个名为 fn的文件
  • 这个文件位于sysfs文件系统中
  • SELinux策略不允许system_app域读取sysfs类型的文件
  • 因此访问被拒绝

根据上面的信息,要做的就是允许system_app访问这个节点。

权限添加

虽然提供的节点是/sys/class/fn_key/fn_key_gpio/fn,但如果直接针对这个节点添加权限,你发现可能会不生效,这也是我遇到的问题,针对这个节点添加权限编译后还是无法读取。 建议先在adb中执行readlink -f /sys/class/fn_key/fn_key_gpio/fn,这条命令的作用是主要用于解析Android设备上符号链接的最终真实路径

执行命令 readlink -f /sys/class/fn_key/fn_key_gpio/fn
返回结果 /sys/devices/platform/soc/a8c000.i2c/i2c-4/4-0038/fn_key/fn_key_gpio/fn

在执行命令后可以看到节点的真实路径,我们要对这个真实的路径添加权限才行。

对符号链接和真实路径的说明

在 Linux 和 Android 中,/sys/class/... 下的大部分节点其实都是符号链接(Symbolic Link) ,指向 /sys/devices/... 下真正的硬件设备路径。

为什么这会导致 SELinux 报错?

  1. 标签未应用到真实文件: 当你在 file_contexts 中写 /sys/class/fn_key/fn_key_gpio/fn 时,SELinux 工具(如 restorecon)有时只会尝试给那个“快捷方式”(链接文件)打标签,而不会给它指向的“真实文件”打标签。
  2. 内核访问机制: 当你的 App 尝试打开这个文件时,内核会解析链接。如果真实路径 /sys/devices/platform/soc/a8c000.i2c/i2c-4/4-0038/fn_key/fn_key_gpio/fn 没有任何特殊定义,它就会继承 sysfs 的默认标签(即 u:object_r:sysfs:s0)。

之前的权限修改(即针对/sys/class/权限修改)

文件 init.target.rc 
新增chmod 777 /sys/class/fn_key/fn_key_gpio/fn
这个chmod 777我不知道有没有生效,ai说是没有,但我看前辈都加了,我也跟着加了

文件 file.te
新增 type sysfs_fn_key, fs_type, sysfs_type;
在file.te定义了一个标签

文件 system_app.te
新增 allow system_app sysfs_fn_key:file {read write open ioctl getattr};
运行system_app对我们定义的标签有各种权限

文件 file_contexts
新增 /sys/class/fn_key/fn_key_gpio/fn		u:object_r:sysfs_fn_key:s0
将之前的节点跟定义的标签关联起来

这只是针对符号链接的权限添加,没有起作用。

修改之后的权限(即 对/sys/devices/)

这里只是修改了file_contexts,将/sys/devices/真正的节点跟我们定义的标签sysfs_fn_key相关联

文件 file_contexts
旧的,但我没删 /sys/class/fn_key/fn_key_gpio/fn		u:object_r:sysfs_fn_key:s0
新增 /sys/devices/platform/soc/a8c000.i2c/i2c-4/4-0038/fn_key/fn_key_gpio/fn		u:object_r:sysfs_fn_key:s0
将之前的节点跟定义的标签关联起来

这样重新编译后就能生效了。


验证权限添加是否成功的一些辅助命令

查看节点所属标签

adb shell命令 ls -Z /sys/class/fn_key/fn_key_gpio/fn 
返回结果 u:object_r:sysfs:s0 /sys/class/fn_key/fn_key_gpio/fn
可以看到,返回了节点所属标签,仍然是sysfs,不是我们自定义的标签,没有建立起关联,因此权限没有生效。

临时关闭selinux权限验证

这个方法只在debug版本试过。有的时候添加了一个节点,没有加对应的权限,又想验证节点是否好用的,可以用以下方法临时关闭selinux权限检查。以下命令均是adb

1. setenforce 0
2. chown -R system pwrdet //其中pwrdet为节点所在目录
3. chgrp -R system pwrdet //其中pwrdet为节点所在目录

说明:上面这三条命令我都是一块用,没有单独用。

给/dev/目录下节点/dev/lirc0 添加权限

节点/dev/lirc0 是个红外节点,往节点写值就可以发射红外线(命令行执行echo -ne "\x28\x23\x00\x00" > /dev/lirc0就可以往节点写值),一开始有权限问题,不知道是不是位于/dev/中的原因,权限报错在log中没有出现,即没有出现1400、avc等常规的selinux关键字,但是如果你执行以下命令关掉selinx确实会正常运行,这里特意说明一下:

adb shell
su
setenforce 0

以下三个文件操作路径为vendor下的device/qcom/sepolicy_vndr

前面讲的,都是给/sys/目录下的添加权限,这里说一个给节点/dev/lirc0添加权限,跟前面说的稍有不同。

第一步:在 device.te 定义标签 (注意不是 file.te)

因为 /dev 下面是设备硬件接口,属于设备类型。

# device.te
type lirc_device, dev_type;
第二步:在 file_contexts 关联节点
# file_contexts
/dev/lirc0                u:object_r:lirc_device:s0
第三步:在 system_app.te 授权

注意这里是 chr_file(字符设备),而不是 file

# system_app.te
allow system_app lirc_device:chr_file { read write open ioctl getattr };