? ? Android應(yīng)用層讀取驅(qū)動(dòng)層設(shè)備節(jié)點(diǎn)在Android應(yīng)用中使用廣泛,設(shè)備節(jié)點(diǎn)文件是設(shè)備驅(qū)動(dòng)的邏輯文件,可以通過(guò)設(shè)備節(jié)點(diǎn)來(lái)訪問(wèn)設(shè)備驅(qū)動(dòng)。
很多設(shè)備信息都可存儲(chǔ)在節(jié)點(diǎn)中。apk可以訪問(wèn)節(jié)點(diǎn),獲取設(shè)備信息或狀態(tài)。
對(duì)于讀寫(xiě)設(shè)別節(jié)點(diǎn),需要root權(quán)限和selinux權(quán)限,在開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到由于SELinux造成的各種權(quán)限不足,即使擁有“萬(wàn)能的root權(quán)限”,也不能獲取全部的權(quán)限。本文旨在結(jié)合具體案例,講解如何根據(jù)log來(lái)快速解決90%的SELinux權(quán)限問(wèn)題。要在系統(tǒng)的SELinux相關(guān)te文件中加入權(quán)限。先來(lái)看看應(yīng)用層讀取節(jié)點(diǎn)的方法:
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();}? }
添加對(duì)應(yīng)節(jié)點(diǎn)的權(quán)限,需要在目錄android\device\qcom\sepolicy\vendor\common下修改幾個(gè)相關(guān)的文件。
system_app.te
file.te
file_contexts
init.te
platform_app.te
system_server.te
,比如針對(duì)上面的設(shè)備節(jié)點(diǎn)"/sys/devices/soc/soc:usb_switch/function_otg_en"
1.在file_contexts文件中添加(普通的節(jié)點(diǎn)和虛擬節(jié)點(diǎn)都需要添加)
/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權(quán)限:
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;
然后全編,編譯,運(yùn)行,如果還是提示permision denied,要根據(jù)log中的type 1400定位問(wèn)題分析缺少的權(quán)限
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.調(diào)試確認(rèn)SELinux問(wèn)題
為了澄清是否因?yàn)镾ELinux導(dǎo)致的問(wèn)題,可先執(zhí)行:
setenforce 0 (臨時(shí)禁用掉SELinux)
getenforce ?(得到結(jié)果為Permissive)
進(jìn)入到設(shè)備節(jié)點(diǎn)目錄執(zhí)行 chmod 777?function_otg_en。
如果問(wèn)題消失了,基本可以確認(rèn)是SELinux造成的權(quán)限問(wèn)題,需要通過(guò)正規(guī)的方式來(lái)解決權(quán)限問(wèn)題。
遇到權(quán)限問(wèn)題,在logcat或者kernel的log中一定會(huì)打印avc denied提示缺少什么權(quán)限,可以通過(guò)命令過(guò)濾出所有的avc denied,再根據(jù)這些log各個(gè)擊破:
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,表示不允許。
同時(shí)需要注意增加權(quán)限的時(shí)候虛擬設(shè)備節(jié)點(diǎn)也要增加相應(yīng)的權(quán)限,獲取虛擬節(jié)點(diǎn)的方法可以采用adb命令進(jìn)行查找:
adb shell?find?/?-name?"*userdata*",
比如"/sys/devices/platform/soc/soc:usb_switch/gpio_pogo_det" 這個(gè)就換成adb shell?find / -name "*gpio_pogo_det*".
7.案例分析
解決原則是:缺什么權(quán)限補(bǔ)什么,一步一步補(bǔ)到?jīng)]有avc denied為止。
解決權(quán)限問(wèn)題需要修改的權(quán)限文件如下位置,以.te結(jié)尾
A:Android/devicesoftwinner/astar-common/sepolicy/*.te
B:Android/external/sepolicy/*.te
其中,A是對(duì)B的overlay(覆蓋),能在A修改的盡量在A修改,盡量避免修改B,修改B可能會(huì)導(dǎo)致CTS?fail問(wèn)題,修改A不會(huì)影響CTS測(cè)試。
(如果不需要深入了解,請(qǐng)直接跳到萬(wàn)能公式這一章閱讀更簡(jiǎn)潔)
下面給出四個(gè)案例:
案例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
分析過(guò)程:
缺少什么權(quán)限: ?????{?write?}權(quán)限,
誰(shuí)缺少權(quán)限: ???????scontext=u:r:kernel:s0
對(duì)哪個(gè)文件缺少權(quán)限:tcontext=u:object_r:block_device
什么類型的文件: ???tclass=blk_file
完整的意思: kernel進(jìn)程對(duì)block_device類型的blk_file缺少write權(quán)限。
解決方法:在上文A位置,找到kernel.te這個(gè)文件,加入以下內(nèi)容:
allow ?kernel ?block_device:blk_file ?write;