配套系列教学视频链接:
说明
系统:Android10.0
设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)
前言
上一个章节介绍了如何定义策略, 并编译得到目标文件, 这些目标文件需要在RK3399开发板上进行更新验证。
一, 更新开发板策略
编译得到的目标文件需要更新到开发板的/vendor/bin中:
out/target/product/qh100_rk3399/vendor/bin/myse_test
生成的策略文件目标文件:
ls out/target/product/qh100_rk3399/vendor/etc/selinux/
plat_pub_versioned.cil vendor_file_contexts vendor_property_contexts vndservice_contexts
plat_sepolicy_vers.txt vendor_hwservice_contexts vendor_seapp_contexts
selinux_denial_metadata vendor_mac_permissions.xml vendor_sepolicy.cil
ls out/target/product/qh100_rk3399/odm/etc/selinux/
precompiled_sepolicy precompiled_sepolicy.product_sepolicy_and_mapping.sha256
precompiled_sepolicy.plat_sepolicy_and_mapping.sha256
将以上文件,以文件夹为单位从源码中拷贝出来, 需要替换根文件系统中的vendor和odm分区的selinux文件, 这样的好处就是不用重新烧录整个镜像,局部更新安全策略就可以了。
操作开发板, 通过adb执行如下:
adb root
adb remount
adb push myse_test /vendor/bin
adb push vendor/selinux /vendor/etc/
adb push odm/selinux /odm/etc/
二,运行验证
提个问题:在不使用selinux规则文件的情况下, 直接在root用户下, 通过命令启动myse_test,发现是可以正常运行的, 是为什么呢?
permissive模式下,并切换到root用户,测试更新了策略文件的效果:
adb root
adb remount
adb push vendor/selinux /vendor/etc/
adb push odm/selinux /odm/etc/
adb shell
qh100_rk3399:/ # getenforce
Permissive
qh100_rk3399:/ # ls -lZ /vendor/bin/myse_test
-rwxr-xr-x 1 root shell u:object_r:vendor_file:s0 11384 2022-05-09 09:58 /vendor/bin/myse_test
qh100_rk3399:/ # restorecon /vendor/bin/myse_test
SELinux: Loaded file_contexts
qh100_rk3399:/ # ls -lZ /vendor/bin/myse_test
-rwxr-xr-x 1 root shell u:object_r:myse_test_dt_exec:s0 11384 2022-05-09 09:58 /vendor/bin/myse_test
启动myse_test进程:
qh100_rk3399:/ # /vendor/bin/myse_test
在另外一个终端上查看:
qh100_rk3399:/ # ps -elfZ | grep myse
u:r:su:s0 root 6760 6524 95 14:53:46 pts/3 00:00:05 myse_test
以上可以看到, 在不进行restorecon的时候, 我们更新的文件会自动继承父目录的安全上下文, 而执行restorecon之后, 文件的安全上下文就发生了变化了。变成了u:object_r:vendor_file:s0和u:object_r:myse_test_dt_exec:s0, 说明我们定义的安全上下文是生效了的。
三, domain域转换
上面可以看到myse_test的domain是为shell或者su, 并没有变成u:r:myse_test_dt:s0,此时需要修改myse_test.te文件, 使其能够domain切换:
# subject context in proccess status
type myse_test_dt, domain;
# object context as a file
type myse_test_dt_exec, exec_type, vendor_file_type, file_type;
#grant perm as domain
init_daemon_domain(myse_test_dt)
domain_auto_trans(shell, myse_test_dt_exec, myse_test_dt)
重新编译策略文件,并重新更新vendor和odm中的策略。注意,想要看到进程域的切换, 需要更新好了策略文件之后, 进行重启,重启之后,才可以看到:
一个终端下启动myse_test
qh100_rk3399:/ $ ls -lZ /vendor/bin/myse_test
-rwxr-xr-x 1 root shell u:object_r:myse_test_dt_exec:s0 11384 2022-05-09 09:58 /vendor/bin/myse_test
qh100_rk3399:/ $ myse_test
在另外一个终端下查看:
qh100_rk3399:/ $ ps -elfZ | grep myse
u:r:myse_test_dt:s0 shell 1595 1412 96 15:07:24 pts/0 00:00:11 myse_test
以上说明策略文件生效了的, 注意,此时selinux模式是permissive模式, 并且也是在非root模式启动的进程。
四,selinux调试和enforcing模式下运行
同样的代码,我们将selinux模式切换到enforce模式之后, 启动myse_test的时候会出现如下情况:
qh100_rk3399:/ $ getenforce
Permissive
qh100_rk3399:/ $ su
:/ # setenforce 1
:/ # exit
qh100_rk3399:/ $ getenforce
Enforcing
再运行myse_test会出现崩溃:
qh100_rk3399:/ $ myse_test
Segmentation fault
同样的代码在permissive模式运行正常, 而在enforce模式下有问题,那应该就是权限问题了。此时需要调试,通过logcat来收集avc日志:
qh100_rk3399:/ $ logcat | grep avc | grep myse
02-24 15:07:25.694 1595 1595 I myse_test: type=1400 audit(0.0:77): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myse_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=1
02-24 15:07:25.694 1595 1595 I myse_test: type=1400 audit(0.0:78): avc: denied { read write } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
02-24 15:07:25.694 1595 1595 I myse_test: type=1400 audit(0.0:79): avc: denied { use } for path="/vendor/bin/myse_test" dev="dm-1" ino=49473 scontext=u:r:myse_test_dt:s0 tcontext=u:r:shell:s0 tclass=fd permissive=1
02-24 15:07:25.720 1595 1595 I myse_test: type=1400 audit(0.0:80): avc: denied { read write } for name="myse_dev" dev="tmpfs" ino=43383 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:device:s0 tclass=file permissive=1
02-24 15:07:25.720 1595 1595 I myse_test: type=1400 audit(0.0:81): avc: denied { open } for path="/dev/myse_dev" dev="tmpfs" ino=43383 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:device:s0 tclass=file permissive=1
02-24 15:11:04.956 1906 1906 I myse_test: type=1400 audit(0.0:86): avc: denied { use } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myse_test_dt:s0 tcontext=u:r:adbd:s0 tclass=fd permissive=1
02-24 15:11:04.956 1906 1906 I myse_test: type=1400 audit(0.0:87): avc: denied { read write } for path="/dev/pts/0" dev="devpts" ino=3 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:devpts:s0 tclass=chr_file permissive=1
02-24 15:11:04.957 1906 1906 I myse_test: type=1400 audit(0.0:88): avc: denied { use } for path="/vendor/bin/myse_test" dev="dm-1" ino=49473 scontext=u:r:myse_test_dt:s0 tcontext=u:r:shell:s0 tclass=fd permissive=1
02-24 15:11:04.984 1906 1906 I myse_test: type=1400 audit(0.0:89): avc: denied { read write } for name="myse_dev" dev="tmpfs" ino=43383 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:device:s0 tclass=file permissive=1
02-24 15:11:04.984 1906 1906 I myse_test: type=1400 audit(0.0:90): avc: denied { open } for path="/dev/myse_dev" dev="tmpfs" ino=43383 scontext=u:r:myse_test_dt:s0 tcontext=u:object_r:device:s0 tclass=file permissive=1
将以上内容新建到一个文件: avc_log.txt
audit2allow -i avc_log.txt
audit2allow一般在android源码中自带, 也可以通过apt进行安装, 得到如下结果:
#============= myse_test_dt ==============
allow myse_test_dt adbd:fd use;
allow myse_test_dt device:file { read write open };
allow myse_test_dt devpts:chr_file { read write };
allow myse_test_dt shell:fd use;
以上结果就表示myse_test_dt.te缺少权限, 需要在该文件添加权限,如下所示:
# subject context in proccess status
type myse_test_dt, domain;
# object context as a file
type myse_test_dt_exec, exec_type, vendor_file_type, file_type;
#grant perm as domain
init_daemon_domain(myse_test_dt)domain_auto_trans(shell, myse_test_dt_exec, myse_test_dt)
#============= myse_test_dt ==============
allow myse_test_dt adbd:fd use;
allow myse_test_dt device:file { read write open };
allow myse_test_dt devpts:chr_file { read write };
allow myse_test_dt shell:fd use;
重新编译策略文件,更新根文件系统,重新编译,按照之前的方法, 将模式切换到enforcing模式下, 发现myse_test程序是可以正常运行的,说明我们给的权限是够的。