• Android系统10 RK3399 init进程启动(三十八) 属性Selinux实战编程


    配套系列教学视频链接:

          安卓系列教程之ROM系统开发-百问100ask

    说明

    系统:Android10.0

    设备: FireFly RK3399 (ROC-RK3399-PC-PLUS)

    前言

    上一节介绍了如何属性编程, 参考:

    Android系统10 RK3399 init进程启动(三十七) 属性代码编程_旗浩QH的博客-CSDN博客

    但是安卓对属性有selinux权限控制的, 本文重点介绍如何在selinux的不同模式下, 如permissive和enforceing模式下进行selinux规则编程。


    一, 不配置selinux规则

    将prop_test放在/vendor/bin中, 普通用户+permissive模式, 运行prop_test, 此时正常运行(adb重启了):

    qh100_rk3399:/ $ getprop | grep adb.tcp

    [service.adb.tcp.port]: [15000]

    qh100_rk3399:/ $ getprop | grep ctl  #结果为空
    qh100_rk3399:/ $ getprop | grep new

    [new.prop.test.name]: [qh100]

     同时查看可执行程序和各个属性的安全上下文:

    console:/ $ ps -elZ | grep prop_test

    u:r:shell:s0       0 R  2000 15297 15289 87 19   0  64  8433 0      pts/0    00:00:02 prop_test

    console:/ $ ls -Z /vendor/bin/prop_test

    u:object_r:vendor_file:s0 /vendor/bin/prop_test

     属性的安全安全上下文:

    qh100_rk3399:/ $ getprop -Z service.adb.tcp.port

    [service.adb.tcp.port]: [u:object_r:shell_prop:s0]

    qh100_rk3399:/ $ getprop -Z  vendor.new.prop.test.name

    [vendor.new.prop.test.name]: [u:object_r:default_prop:s0]

    qh100_rk3399:/ $ getprop -Z  ctl.start

    u:object_r:ctl_default_prop:s0

    qh100_rk3399:/ $ getprop -Z  ctl.stop

    u:object_r:ctl_default_prop:s0

    qh100_rk3399:/ $ getprop -Z  ctl.restart

    u:object_r:ctl_default_prop:s0

    在selinux为permissve模式下不修改任何selinux规则, 以上代码正常,但是设置成enforce模式下:

    qh100_rk3399:/ $ su

    qh100_rk3399::/ # setenforce  1

    qh100_rk3399::/ # exit

     运行prop_test,日志显示:

    qh100_rk3399:/ $ prop_test

    /system/bin/sh: /vendor/bin/prop_test: Permission denied

     在串口上查看属性自然无效:

    console:/ $ getprop  | grep new

    说明此时属性因为selinux权限管控,无法任意修改属性。所以此时需要定制selinux规则。

    二, 配置selinux基本规则

    需要配置的selinux规则文件如下所示: 

     prop_test作为vendor,分区去修改shell_prop类型的属性service.adb.tcp.port, 可能修改到system分区的selinux的规则, 所以暂时将主程序改成如下, 负责重启服务:vendor.gnss_service 

    1. int main(int argc, char *argv[])
    2. {
    3. print_android_version();
    4. CplusTestPropString();
    5. property_set("vendor.new.prop.test.name", "qh100");
    6. #if 0
    7. set_adbd_tcp_port(0);
    8. property_set("ctl.stop", "adbd");
    9. property_set("ctl.start", "adbd");
    10. #else
    11. property_set("ctl.restart", "vendor.gnss_service");
    12. #endif
    13. while(1);
    14. return 0;
    15. }

     需要定义如下selinux规则:

    1. 设置自定义属性new.prop.test.name的安全上下文, 同时定义prop_test文件的安全上下文
    2. prop_test特定的进程域.
    3. 定义进程于的规则

     selinux规则文件结构: 

    device/rockchip/qh100_rk3399/test_se/

    └── sepolicy

        ├── device.te

    ├── myse_test.te

    ├── file_contexts :定义prop_test可执行程序文件的安全上下文。

        ├── property_contexts  : 定义属性对应的安全上下文。

    └── prop_test.te: 定义prop_test进程对应的进程域和权限策略。

    └── property.te :  定义属性对应的类型。

    制定属性相关的selinux类型(vendor.new.prop.test.name):

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/property.te

    type vendor_myprop_prop, property_type;

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/property_contexts

    vendor.new.prop.test.name  u:object_r:vendor_myprop_prop:s0

    可执行程序文件prop_test对应的selinux格则:

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/prop_test.te

    # subject context in proccess status

    type  myprop_test_dt, domain;

    # object context as a file

    type myprop_test_dt_exec, exec_type, vendor_file_type, file_type;

    #grant perm as domain

    init_daemon_domain(myprop_test_dt)

    domain_auto_trans(shell, myprop_test_dt_exec, myprop_test_dt)

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/file_contexts

    /vendor/bin/myse_test                   u:object_r:myse_test_dt_exec:s0

    /vendor/bin/prop_test                   u:object_r:myprop_test_dt_exec:s0

    /dev/myse_dev    u:object_r:myse_testdev_t:s0

    编译:

    make selinux_policy -j16

    得到:

    out/target/product/qh100_rk3399/vendor/etc/selinux/

    out/target/product/qh100_rk3399/odm/etc/selinux/

     开发板更新selinux目标操作:

    ProperyCode\selinux\binary\v1-onlyContext>adb push vendor\selinux  /vendor/etc/

    vendor\selinux\: 10 files pushed, 0 skipped. 15.2 MB/s (1023122 bytes in 0.064s)

    ProperyCode\selinux\binary\v1-onlyContext>adb push odm\selinux  /odm/etc/

    odm\selinux\: 3 files pushed, 0 skipped. 14.5 MB/s (480980 bytes in 0.032s)

    重启开发板, 执行验证, 注意此时可以在permissive模式下验证, 这样可以获取到更多的权限报错信息:

    qh100_rk3399:/ $ ls -lZ /vendor/bin/prop_test

    -rwxrwxrwx 1 root shell u:object_r:myprop_test_dt_exec:s0 11616 2022-08-25 12:28 /vendor/bin/prop_test

    qh100_rk3399:/ $ prop_test

     发现prop_test并没有报权限错误, 查看进程域, 发现进程域安全上下文发生了变化:

    qh100_rk3399:/ $ ps -elfZ | grep prop_test

    u:r:myprop_test_dt:s0          shell         1824  1710 94 12:41:04 pts/0 00:00:14 prop_test

    u:r:shell:s0                   shell         1842  1828 2 12:41:19 pts/1 00:00:00 grep prop_test

    但是属性是否也被改变了呢?

    qh100_rk3399:/ $ getprop | grep new

    [vendor.new.prop.test.name]: [qh100]

    qh100_rk3399:/ $ getprop -Z vendor.new.prop.test.name

    u:object_r:vendor_myprop_prop:s0

    自定义的属性也是按照规则文件来设置了安全上下文。

    gnss服务在prop_test启动前后的pid有变化,说明程序代码没问题,selinux规则也生效了。

    qh100_rk3399:/ $ ps -elf | grep gns

    gps           2056     1 0 14:35:01 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2190  2068 0 14:36:57 pts/1 00:00:00 grep gns

    qh100_rk3399:/ $ ps -elf | grep gns

    gps           2198     1 1 14:37:02 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2208  2068 0 14:37:06 pts/1 00:00:00 grep gns

    保存avc日志: logcat  | grep  avc  

    获取到权限: audit2allow  -i avc_log.txt, 得到如下需要补充的权限格则: 

    #============= myprop_test_dt ==============

    allow myprop_test_dt adbd:fd use;

    allow myprop_test_dt devpts:chr_file { read write };

    allow myprop_test_dt init:unix_stream_socket connectto;

    allow myprop_test_dt property_socket:sock_file write;

    allow myprop_test_dt shell:fd use;

    切换到enforce模式:

    qh100_rk3399:/ $ su

    :/ # setenforce  1

    :/ # getenforce

    Enforcing

    qh100_rk3399:/ $ prop_test

    Segmentation fault

    肯定是缺少权限,增加之前获取到的权限:

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/prop_test.te

    #============= myprop_test_dt ==============

    allow myprop_test_dt adbd:fd use;

    allow myprop_test_dt devpts:chr_file { read write };

    allow myprop_test_dt init:unix_stream_socket connectto;

    allow myprop_test_dt property_socket:sock_file write;

    allow myprop_test_dt shell:fd use;

    编译之后,重新运行:一定要在enforce模式下,运行 prop_test,此时不会退出,

    qh100_rk3399:/ $ getenforce

    Enforcing

    qh100_rk3399:/ $ prop_test

     但是获取属性是没有的:

    qh100_rk3399:/ $ su

    :/ # getprop | grep new  #即使切换到su用户,也无法获取到属性,因为设置不成功。

    qh100_rk3399:/ $ ps -elf | grep gnss

    gps            246     1 0 14:42:27 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2046  2021 4 14:47:09 pts/1 00:00:00 grep gnss

    第二次运行prop_test时:

    qh100_rk3399:/ $ ps -elf | grep gnss

    gps            246     1 0 14:42:27 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2056  2021 0 14:47:16 pts/1 00:00:00 grep gnss

    gnss服务没有重启成功, 同时自定义属性vendor.new.prop.test.name也没有设置成功, 也就是说selinux规则已经有了, 但是设置属性的规则还是没有的。

    三, 增加属性selinux权限规则

    根据我们需要修改的属性的安全上下文, 我们配置对应的属性规则:

    vim device/rockchip/qh100_rk3399/test_se/sepolicy/prop_test.te 后面添加:

    set_prop(myprop_test_dt, vendor_myprop_prop);

    #set_prop(myprop_test_dt, shell_prop);

    set_prop(myprop_test_dt, ctl_default_prop);

    注意, 上面注释的部分,打开之后,编译会报错, 大家可以自己试试,根据我们之前学习到的知识,自我分析一下。

    编译之后,重新运行:一定要在enforce模式下验证,运行 prop_test:

    qh100_rk3399:/ $ su

    :/ # setenforce 1

    :/ # exit

    qh100_rk3399:/ $ getenforce

    Enforcing

    qh100_rk3399:/ $ prop_test

    执行结果如下:

    1|qh100_rk3399:/ $ ps -elf | grep gnss

    gps            247     1 0 14:55:01 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2207  2193 1 15:02:38 pts/1 00:00:00 grep gnss

    第二次运行prop_test时:

    qh100_rk3399:/ $ ps -elf | grep gnss

    gps           2216     1 0 15:02:42 ?     00:00:00 android.hardware.gnss@1.0-service

    shell         2235  2193 5 15:02:55 pts/1 00:00:00 grep gnss

    说明在enforcing模式下,可以重启gnss服务。

    获取自定义属性时:

    qh100_rk3399:/ $ getprop | grep new 

     #此时没有结果,是因为在shell命令行执行getprop时, shell进程域没有权限获取vendor.new.prop.test.name

    需要切换到root用户下才能看到:

    qh100_rk3399:/ $ su

    :/ # getprop | grep new

    [vendor.new.prop.test.name]: [qh100]

    四, 总结

    一般在pemissive模式下, 修改属性时, 权限问题不是很突出, 但是一旦在enfocing模式,权限配置就非常重要, 甚至有些时候非常麻烦, 所以希望大家通过这几次实战selinux编程, 对selinux的规则有深刻理解。

  • 相关阅读:
    Apacha Flume
    【图文详解】深入理解 Hbase 架构 Deep Into HBase Architecture
    还在不停切换聊天窗口进行回复的客服请看过来
    代码随想录训练营day3:链表part1
    150. 以前编写好能够正常运行的 SAP UI5 代码,几个月后忽然不能运行了该怎么办?
    CentOS网络设置
    Linux安装Jenkins
    1086 就不告诉你
    Flink 1. 13(七)Flink SQL
    车辆检测:An Efficient Wide-Range Pseudo-3D Vehicle Detection Using A Single Camera
  • 原文地址:https://blog.csdn.net/ldswfun/article/details/126753372