Android应用层读取驱动层设备节点在Android应用中使用广泛,设备节点文件是设备驱动的逻辑文件,可以通过设备节点来访问设备驱动。
很多设备信息都可存储在节点中。apk可以访问节点,获取设备信息或状态。
对于读写设别节点,需要root权限和selinux权限,在开发中,我们经常会遇到由于SELinux造成的各种权限不足,即使拥有“万能的root权限”,也不能获取全部的权限。本文旨在结合具体案例,讲解如何根据log来快速解决90%的SELinux权限问题。要在系统的SELinux相关te文件中加入权限。先来看看应用层读取节点的方法:
private void readdata() {
try {
FileInputStream fp_read = new FileInputStream("/sys/devices/soc/soc:usb_switch/function_otg_en");
byte[] mbyte = new byte[4];
fp_read.read(mbyte);
otg_enabled = new String(mbyte);
} catch (Exception e) {
e.printStackTrace();} }
添加对应节点的权限,需要在目录android\device\qcom\sepolicy\vendor\common下修改几个相关的文件。
system_app.te
file.te
file_contexts
init.te
platform_app.te
system_server.te
,比如针对上面的设备节点"/sys/devices/soc/soc:usb_switch/function_otg_en"
1.在file_contexts文件中添加(普通的节点和虚拟节点都需要添加)
/sys/class/Usb_switch/usbswitch/function_otg_en u:object_r:sysfs_function_otg:s0
/sys/devices/soc/soc:usb_switch/function_otg_en u:object_r:sysfs_function_otg:s0
2. init.target.rc(device/qcom/sdm660_64)文件中添加以下777权限:
chmod 777/sys/class/Usb_switch/usbswitch/function_otg_en
chmod 777/sys/devices/soc/soc:usb_switch/function_otg_en
3.file.te中添加以下代码:
type sysfs_function_otg, fs_type, sysfs_type;
4.system_app.te中添加以下代码:
allow system_app sysfs_function_otg:file rw_file_perms;
5.system_server.te中添加以下代码:
allow system_serversysfs_function_otg:file rw_file_perms;
然后全编,编译,运行,如果还是提示permision denied,要根据log中的type 1400定位问题分析缺少的权限
05-20 09:25:11.040 1546 1546 I auditd : type=1400 audit(0.0:13): avc: denied { read } for comm="medoctorstation" name="ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I medoctorstation: type=1400 audit(0.0:13): avc: denied { read } for name="ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I auditd : type=1400 audit(0.0:14): avc: denied { write } for comm="medoctorstation" name="ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I medoctorstation: type=1400 audit(0.0:14): avc: denied { write } for name="ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I auditd : type=1400 audit(0.0:15): avc: denied { open } for comm="medoctorstation" path="/dev/ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I medoctorstation: type=1400 audit(0.0:15): avc: denied { open } for path="/dev/ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I auditd : type=1400 audit(0.0:16): avc: denied { ioctl } for comm="medoctorstation" path="/dev/ttyS0" dev="tmpfs" ino=8685 ioctlcmd=5401 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.040 1546 1546 I medoctorstation: type=1400 audit(0.0:16): avc: denied { ioctl } for path="/dev/ttyS0" dev="tmpfs" ino=8685 ioctlcmd=5401 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1 05-20 09:25:11.060 1546 1546 I auditd : type=1400 audit(0.0:17): avc: denied { getattr } for comm="medoctorstation" path="/dev/ttyS0" dev="tmpfs" ino=8685 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:serial_device:s0 tclass=chr_file permissive=1
6.调试确认SELinux问题
为了澄清是否因为SELinux导致的问题,可先执行:
setenforce 0 (临时禁用掉SELinux)
getenforce (得到结果为Permissive)
进入到设备节点目录执行 chmod 777 function_otg_en。
如果问题消失了,基本可以确认是SELinux造成的权限问题,需要通过正规的方式来解决权限问题。
遇到权限问题,在logcat或者kernel的log中一定会打印avc denied提示缺少什么权限,可以通过命令过滤出所有的avc denied,再根据这些log各个击破:
cat /proc/kmsg | grep avc
或
dmesg | grep avc
例如:
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
可以看到有avc denied,且最后有permissive=0,表示不允许。
同时需要注意增加权限的时候虚拟设备节点也要增加相应的权限,获取虚拟节点的方法可以采用adb命令进行查找:
adb shell find / -name "*userdata*",
比如"/sys/devices/platform/soc/soc:usb_switch/gpio_pogo_det" 这个就换成adb shell find / -name "*gpio_pogo_det*".
7.案例分析
解决原则是:缺什么权限补什么,一步一步补到没有avc denied为止。
解决权限问题需要修改的权限文件如下位置,以.te结尾
A:Android/devicesoftwinner/astar-common/sepolicy/*.te
B:Android/external/sepolicy/*.te
其中,A是对B的overlay(覆盖),能在A修改的尽量在A修改,尽量避免修改B,修改B可能会导致CTS fail问题,修改A不会影响CTS测试。
(如果不需要深入了解,请直接跳到万能公式这一章阅读更简洁)
下面给出四个案例:
案例1
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=/1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
分析过程:
缺少什么权限: { write }权限,
谁缺少权限: scontext=u:r:kernel:s0
对哪个文件缺少权限:tcontext=u:object_r:block_device
什么类型的文件: tclass=blk_file
完整的意思: kernel进程对block_device类型的blk_file缺少write权限。
解决方法:在上文A位置,找到kernel.te这个文件,加入以下内容:
allow kernel block_device:blk_file write;