最近做培训的相关的工作,在讲解Selinux相关工作的时候,一名学员提出来一个问题,即然Selinux能够在进程在获取Root权限后,依旧对其有所限制,那么是否可以通过Selinux的policy来阻止Root进程来删除某个特定文件?我的回答是当然可以,那么具体怎么做呢?
实验环境
开始,需要找一台支持Selinux的设备,我尝试在Ubuntu上安装Selinux模块,于是乎Ubuntu就无法启动了(还好是ESXI的虚拟机)。于是乎,我想到了是否能用Android来做这次实验,毕竟Android原生就支持Selinux。但是Android上没有自带的管理Selinux Policy的相关工具,而刷机有比较麻烦,于是乎我把目光引向了Magisk和magiskpolicy工具。在手机上安装Magisk成功后,自然而然就存在magiskpolicy这个工具了。本平台使用的是OnePlus 7T + Lineage OS 21 + Magisk的组合,刷机过程不作赘述。
实验开始
在Gpt的加持下写代码一把梭,很快写出了以下规则:
1 | # myprotect.rule |
这里定义了一个新的SELinux类型,名为 protected_software
,并将 protected_software
类型添加到 file_type
属性中。
然后,应用这个规则,并给文件应用了刚刚创建的安全上下文:
1 | OnePlus7T:/data/local/tmp # magiskpolicy --live --apply myprotect.rule |
在用ls检查一下,可以发现已经成功了:
1 | OnePlus7T:/data/local/tmp # ls -Z new_file |
由于上述规则中并没有任何对该文件的权限,如果尝试删除这个文件会引来报错。
1 | OnePlus7T:/data/local/tmp # rm new_file |
但是被打脸了,可以成功删除,我继续查看id,发现当前的context为magisk:
1 | OnePlus7T:/data/local/tmp # id |
看来magisk这个context是具有特权的,在询问了开发Magisk工具的师傅后,他告诉我Magisk的su几乎是完全不受Selinux限制,因为它给了几乎所有权限,同时还是permissive域,permissive域执行所有操作都会放行,但是如果没明确的 allow 规则 avc 日志里还会叫一声,具体可以查看Magisk代码,可以通过以下代码看到Magisk的所有allow规则。
1 | magiskpolicy --print-rules | grep magisk |
那看来是需要给自己进程重新降级了?
本来我想着重新创建一个进程的Selinux上下文,但是权限问题报的很多,而给了所有权限又没法测试本文的主旨了。因此我使用了现有的shell上下文。通过以下命令,就可以进入一个新的上下文的shell,同时还具有root权限。
1 | OnePlus7T:/data/local/tmp # runcon u:r:shell:s0 /system/bin/sh |
但是又又又遇到问题了:
1 | OnePlus7T:/data/local/tmp # ls |
奇了怪了,竟然对自己拥有的文件夹也不具有权限了?
1 | OnePlus7T:/data/local/tmp $ id |
而没有root权限context的反而对改文件夹具有权限?
我查看了一样Selinux的日志:
1 | OnePlus7T:/data/local/tmp # dmesg | grep avc |
发现了上述两条报错,可以看到因为dac_override
和dac_read_search
的原因拒绝了ls
的操作。
经过检索发现:
dac_override 拒绝事件意味着违规进程正在尝试使用错误的 unix user/group/world 权限访问某个文件。正确的解决方案几乎从不授予 dac_override 权限,而是更改相应文件或进程的 unix 权限。有些域(例如init、vold 和 installd)确实需要能够替换 unix 文件权限才能访问其他进程的文件。要查看更深入的讲解,请访问 Dan Walsh 的博客
具体可以参考这篇文章,大概明白了,进程使用错误的权限/权限组,会报这个错误。
知道原因,找到解决方法就不难了,在magisk域下使用以下命令:
1 | magiskpolicy --live "allow shell shell capability { dac_override }" |
之后可以看到ls
可以正常使用了。
实验过程
解决掉上述一系列的问题,可以正式开始我们的的实验了。
创建规则并且应用规则
1
magiskpolicy --live --apply myprotect.rule
创建文件并赋予文件新的上下文
1
touch new_file && chcon u:object_r:protected_software:s0 new_file
给shell赋予
dac_override
的权限1
magiskpolicy --live "allow shell shell capability { dac_override }"
进入shell的context
1
runcon u:r:shell:s0 /system/bin/sh
尝试删除文件
1
2OnePlus7T:/data/local/tmp # rm new_file rm ro new_file (y/N):y
rm: new_file: Permission denied查看日志验证Selinux拦截了相关操作
1
[ 1921.167160] type=1400 audit(1727467597.663:72): avc: denied { unlink } for comm="rm" name="new_file" dev="dm-44" ino=4046859 scontext=u:r:shell:s0 tcontext=u:object_r:protected_software:s0 tclass=file permissive=0
至此,整个Selinux实验结束。