一次Selinux的实验(非常主观)
2024-10-05 22:34:52

最近做培训的相关的工作,在讲解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
2
3
# myprotect.rule
type protected_software
typeattribute protected_software file_type

这里定义了一个新的SELinux类型,名为 protected_software,并将 protected_software 类型添加到 file_type 属性中。

然后,应用这个规则,并给文件应用了刚刚创建的安全上下文:

1
2
OnePlus7T:/data/local/tmp # magiskpolicy --live --apply myprotect.rule
OnePlus7T:/data/local/tmp # chcon u:object_r:protected_software:s0 new_file

在用ls检查一下,可以发现已经成功了:

1
2
OnePlus7T:/data/local/tmp # ls -Z new_file
u:object_r:protected_software:s0 new_file

由于上述规则中并没有任何对该文件的权限,如果尝试删除这个文件会引来报错。

1
OnePlus7T:/data/local/tmp # rm new_file

但是被打脸了,可以成功删除,我继续查看id,发现当前的context为magisk:

1
2
OnePlus7T:/data/local/tmp # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:magisk:s0

看来magisk这个context是具有特权的,在询问了开发Magisk工具的师傅后,他告诉我Magisk的su几乎是完全不受Selinux限制,因为它给了几乎所有权限,同时还是permissive域,permissive域执行所有操作都会放行,但是如果没明确的 allow 规则 avc 日志里还会叫一声,具体可以查看Magisk代码,可以通过以下代码看到Magisk的所有allow规则。

1
magiskpolicy --print-rules | grep magisk      

那看来是需要给自己进程重新降级了?

本来我想着重新创建一个进程的Selinux上下文,但是权限问题报的很多,而给了所有权限又没法测试本文的主旨了。因此我使用了现有的shell上下文。通过以下命令,就可以进入一个新的上下文的shell,同时还具有root权限。

1
2
3
OnePlus7T:/data/local/tmp # runcon u:r:shell:s0 /system/bin/sh
OnePlus7T:/data/local/tmp # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:shell:s0

但是又又又遇到问题了:

1
2
OnePlus7T:/data/local/tmp # ls
ls: .: Permission denied

奇了怪了,竟然对自己拥有的文件夹也不具有权限了?

1
2
3
4
5
6
7
8
OnePlus7T:/data/local/tmp $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),1078(ext_data_rw),1079(ext_obb_rw),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid),3012(readtracefs) context=u:r:shell:s0
OnePlus7T:/data/local/tmp $ ls -alZ
total 12
drwxrwx--x 2 shell shell u:object_r:shell_data_file:s0 4096 2024-09-28 03:43 .
drwxr-x--x 5 root root u:object_r:system_data_file:s0 4096 1970-02-05 03:11 ..
-rw-r--r-- 1 root root u:object_r:protected_software:s0 0 2024-09-28 19:14 aaa
-rw-r--r-- 1 root root u:object_r:shell_data_file:s0 67 2024-09-28 19:29 myprotect.rule

而没有root权限context的反而对改文件夹具有权限?

我查看了一样Selinux的日志:

1
2
3
4
OnePlus7T:/data/local/tmp # dmesg | grep avc
...
[ 1212.072580] type=1400 audit(1727466888.567:51): avc: denied { dac_read_search } for comm="ls" capability=2 scontext=u:r:shell:s0 tcontext=u:r:shell:s0 tclass=capability permissive=0
[ 1212.072832] type=1400 audit(1727466888.571:52): avc: denied { dac_override } for comm="ls" capability=1 scontext=u:r:shell:s0 tcontext=u:r:shell:s0 tclass=capability permissive=0

发现了上述两条报错,可以看到因为dac_overridedac_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. 创建规则并且应用规则

    1
    magiskpolicy --live --apply myprotect.rule
  2. 创建文件并赋予文件新的上下文

    1
    touch new_file && chcon u:object_r:protected_software:s0 new_file
  3. 给shell赋予dac_override的权限

    1
    magiskpolicy --live "allow shell shell capability { dac_override }"          
  4. 进入shell的context

    1
    runcon u:r:shell:s0 /system/bin/sh
  5. 尝试删除文件

    1
    2
    OnePlus7T:/data/local/tmp # rm new_file                                               rm ro new_file (y/N):y
    rm: new_file: Permission denied
  6. 查看日志验证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实验结束。

Prev
2024-10-05 22:34:52