本文转载自:https://zhuanlan.zhihu.com/p/32868074

 本人对于 SELinux for Android 理解不深,下文中的各文件及安全规则虽都是我所编写,但也是一边查阅文档一边试验得出的。在此强行为文,若有理解错误之处,请各位工程师同仁热情指出。

  感谢

指出文章不足。按照 Project Treble 的要求,这种需求的规范做法应该是通过 HIDL 进行调用并添加上相应的 SELinux 权限,所以下文中的做法只能算是一种 workaround。相关机制我还在研究中,后续我再按规范来修改文章内容,如果有工程师朋友已经按照 Treble 规范实现过这样的需求了,非常欢迎留言沟通交流。

  文章就不删了,作为对自己的警醒。身为工程师,不当浮躁趋名,而应谨慎稳重、厚积薄发。

------------------------------------ 分割线下内容作废 -------------------------------------

一、需求描述

  项目上需要在 Android 8.0 上实现开机自动调用可执行文件 /system/bin/aaa 去处理 /vendor/lib/bbb.so,并将处理后的文件保存为 /tmp/ds/ccc.so。这期间 /system/bin/aaa在处理文件时会去访问 /dev/ddd 节点,并且在开机时 /tmp/ds/ 目录并不存在,需要每次开机时创建。
  其中 /system/bin/aaa 和 /dev/ddd 是自定义添加的可执行文件和设备节点,在原生 Android 8.0 系统中并不存在。

二、实现思路

  • 编写一个脚本实现调用 /system/bin/aaa 对文件 /vendor/lib/bbb.so 进行处理。
  • 在 .rc 文件中新增创建 /tmp/ds/ 目录的代码和新增一个 service 用于启动 步骤1 中编写的脚本。
  • 新增 .te 文件并编写相应 sepolicy 规则以解决权限问题。

三、实现过程

  首先编写开机启动脚本。因为 Google 启动了 Treble 计划,对 system 分区和 vendor 分区进行严格的分离,所以这样的自定义脚本我们最好不要放在 /system/bin/ 目录下。因为我工作于芯片公司,即 vendor 厂商,所以我把它放在 /vendor/bin/ 目录下。同时,从 Android 8.0开始,SELinux for Android 也进行了模块化,为了避免不必要的权限问题,我们使用 /vendor/bin/sh 作为脚本解释器。我编写的开机脚本是 prepare_ds.sh,内容很简单,如下:

#!/vendor/bin/sh
/system/bin/aaa /vendor/lib/bbb.so /tmp/ds/ccc.so

  脚本应该在编译时自动拷贝到 vendor/bin/ 目录下,所以我们还要在 makefile 中添加拷贝命令。以我这个项目为例,对应的 makefile 文件是 product_mbox.mk,为其添加如下代码:

# aaa Security
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/../../prepare_ds.sh:/vendor/bin/prepare_ds.sh

  然后在相应的 .rc 文件中添加代码。这是为了在开机时创建 /tmp/ds/ 目录,以及以 service 的形式运行脚本 prepare_ds.sh。以我这个项目为例,需要在 init.vendorName.board.rc 中添加如下语句:

on init
mkdir /tmp 0770 root root
mkdir /tmp/ds 0770 root root
mount tmpfs tmpfs /tmp/ds on boot
#aaa security
chmod 0666 /dev/ddd
chmod 0777 /system/bin/aaa
chmod 0666 /vendor/lib/bbb.so
start aaa_security
chmod 0666 /tmp/ds/ccc.so service aaa_security /vendor/bin/sh /vendor/bin/prepare_ds.sh
user root
group root
disabled
oneshot
seclabel u:r:aaa_security:s0

  这几行命令的意思是在系统 init 阶段创建 /tmp/ds/ 目录,定义名为 aaa_security 的服务,并在 boot 阶段以 root 身份显式启动且仅启动服务一次。
  接着我们还要为上一步骤里定义的 aaa_sercurity 服务编写 .te 文件,定义其所属的安全域(SELinux domain)。否则设备在开机后无法执行这个 service,并且我们可以在 dmesg 中看到下方这样的警告:

[    9.910511] init: service aaa_security does not have a SELinux domain defined

  在 device/<vendorName>/common/sepolicy/ 目录下新建 aaa_security.te 文件。我们可能并不清楚开机运行这个脚本并执行相应的调用需要哪些权限,所以我们可以先在 .te 文件中添加上基本的定义。这些基本的文件内容如下:

########################################
# sepolicy rules for aaa_security
########################################
type aaa_security, domain;
type aaa_security_exec, exec_type, vendor_file_type, file_type; permissive aaa_security;
init_daemon_domain(aaa_security)

  其中 aaa_security 这个域对应 .rc 文件中定义的服务 aaa_security,aaa_security_exec 对应脚本文件 prepare_ds.sh。语句 permissive aaa_security 是暂时添加的,目的是使服务在遇到权限问题时也可以正常执行,但会将所需的权限类型打印出来。init_daemon_domain 是一个宏,用来使 aaa_security 域生效。
  因为 /system/bin/aaa 在处理文件时要访问 /dev/ddd 节点,所以我们也要为这个设备节点编写文件 aaa_device.te。内容如下:

########################################
# sepolicy rules for aaa_device
########################################
type aaa_device, file_type, dev_type;

  最后,在 device/<vendorName>/sepolicy/file_contexts 里为这些新增的文件指定要使用的安全上下文,我们的工作就接近完成了。新增语句如下:

/vendor/bin/prepare_ds.sh     u:object_r:aaa_security_exec:s0
/dev/aaa u:object_r:aaa_device:s0

  为了验证我们的修改是否有效,需要编译并烧写 boot.img 和 vendor.img,然后重启设备。
  不过最初编写的 aaa_security.te 文件中,往往赋予开机脚本的权限会有不足,我们需要通过查看 dmesg 中的打印来添加上相应的权限。比如我们可能会看到下面这样的权限缺失提示:

[   10.368517] type=1400 audit(1483292256.112:14): avc: denied { execute_no_trans } for pid=2768 comm="prepare_ds.sh" path="/vendor/bin/toybox_vendor" dev="mmcblk0p14" ino=222 scontext=u:r:aaa_security:s0 tcontext=u:object_r:vendor_toolbox_exec:s0 tclass=file permissive=1
[ 10.434460] type=1400 audit(1483292256.112:14): avc: denied { execute_no_trans } for pid=2768 comm="prepare_ds.sh" path="/vendor/bin/toybox_vendor" dev="mmcblk0p14" ino=222 scontext=u:r:aaa_security:s0 tcontext=u:object_r:vendor_toolbox_exec:s0 tclass=file permissive=1
[ 10.662017] type=1400 audit(1483292256.408:16): avc: denied { read write } for pid=2775 comm="aaa" name="aaa" dev="tmpfs" ino=1287 scontext=u:r:aaa_security:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
[ 10.666135] type=1400 audit(1483292256.408:16): avc: denied { read write } for pid=2775 comm="aaa" name="aaa" dev="tmpfs" ino=1287 scontext=u:r:aaa_security:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
[ 10.666145] type=1400 audit(1483292256.408:17): avc: denied { open } for pid=2775 comm="aaa" path="/dev/ddd" dev="tmpfs" ino=1287 scontext=u:r:aaa_security:s0 tcontext=u:object_r:aaa_device:s0 tclass=chr_file permissive=1
[ 10.666264] type=1400 audit(1483292256.408:17): avc: denied { open } for pid=2775 comm="aaa" path="/dev/ddd" dev="tmpfs" ino=1287 scontext=u:r:aaa_security:s0 tcontext=u:object_r:aaa_device:s0 tclass=chr_file permissive=1
[ 10.666271] type=1400 audit(1483292256.408:18): avc: denied { ioctl } for pid=2775 comm="aaa" path="/dev/ddd" dev="tmpfs" ino=1287 ioctlcmd=0x10 scontext=u:r:aaa_security:s0 tcontext=u:object_r:aaa_device:s0 tclass=chr_file permissive=1
[ 10.679685] type=1400 audit(1483292256.408:18): avc: denied { ioctl } for pid=2775 comm="aaa" path="/dev/ddd" dev="tmpfs" ino=1287 ioctlcmd=0x10 scontext=u:r:aaa_security:s0 tcontext=u:object_r:aaa_device:s0 tclass=chr_file permissive=1

  那么我们就应该在 .te 文件中添加上这些权限,然后删除掉 permissive aaa_security 语句。以我的项目为例,添加上所需全部权限后,完整的 aaa_security.te 文件内容如下:

########################################
# sepolicy rules for aaa_security
########################################
type aaa_security, domain;
type aaa_security_exec, exec_type, vendor_file_type, file_type; r_dir_file(aaa_security, rootfs)
r_dir_file(aaa_security, system_file)
r_dir_file(aaa_security, sysfs_type)
r_dir_file(aaa_security, aaa_device) #permissive aaa_security;
init_daemon_domain(aaa_security) allow aaa_security shell_exec:file { read getattr };
allow aaa_security vendor_toolbox_exec:file { read open execute execute_no_trans };
allow aaa_security system_data_file:file { getattr };
allow aaa_security system_data_file:dir { getattr };
allow aaa_security self:capability { dac_override sys_admin };
#allow aaa_security rootfs:filesystem { remount };
allow aaa_security rootfs:dir { write add_name create };
allow aaa_security system_file:file { execute_no_trans };
allow aaa_security aaa_device:chr_file { read write open ioctl };
allow aaa_security cache_file:dir { getattr };
allow aaa_security tee_data_file:dir { getattr };
allow aaa_security storage_file:dir { getattr };
allow aaa_security media_rw_data_file:dir { getattr };
allow dolby_security vendor_shell_exec:file { entrypoint };
allow dolby_security tmpfs:dir { write add_name create };
allow dolby_security dolby_security_tmpfs:file { create open };

  至此,我们的工作就全部完成了。重新编译并烧写 boot.img 和 vendor.img 后,重启设备,可以看到开机脚本工作正常。

为 Android 8.0 添加开机启动脚本【转】的更多相关文章

  1. [转]Ubuntu下添加开机启动脚本

    作者: 王恒 发表于 2012年 11月 5日 1.方法一,编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚本, 所以我们可以直接在/etc/rc.local中 ...

  2. Android 4.0关于开机启动服务

    针对使用App应用管理强制停止的App,重启系统后不能收到开机启动, 需要运行一次后,在下次再启动时,才可以正确收到.

  3. 为Android添加开机启动脚本

    转:https://blog.csdn.net/u014316462/article/details/76438611 本文介绍了一种在Android 4.2.2源码中添加.修改文件或者代码,来达到使 ...

  4. imx6q android 添加开机启动脚本

    1.在xx/out/target/product/sabresd_6dq/root/init.rc中添加以下内容 ========================================== ...

  5. linux添加开机启动脚本

    [root@mysql ~]# ll /etc/rc.local lrwxrwxrwx. 1 root root 13 Mar 12 22:20 /etc/rc.local -> rc.d/rc ...

  6. centos7之添加开机启动服务/脚本

    一.添加开机启动脚本 #!/bin/bash # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES # # It is highly advisable to ...

  7. (转) CentOS 7添加开机启动服务/脚本

    CentOS 7添加开机启动服务/脚本 原文:http://blog.csdn.net/wang123459/article/details/79063703 一.添加开机自启服务 在CentOS 7 ...

  8. elasticsearch设置执行脚本并添加开机启动 (转)

    elasticsearch设置执行脚本并添加开机启动 在/etc/init.d目录下新建文件elasticsearch #!/bin/sh #chkconfig: 2345 80 05 #descri ...

  9. hadoop 与 hbase 添加开机启动,按顺序,先hadoop,后hbase,开机启动脚本,hbase学习

    hadoop安装,hbase单机安装,参考链接,https://blog.csdn.net/LiuHuan_study/article/details/84347262 开机启动脚本,参考, http ...

随机推荐

  1. 14nm或于6月量产,中芯首次披露12nm及第二代FinFET "N+1"计划(详细数据)

    日前中芯国际公布2018年度第四季度业绩,实现营收7.88亿美元,14nm工艺进入客户验证阶段,可望于今年6月份量产,且12nm工艺开发取得突破. 根据中芯国际披露的财报,2018年第四季度实现营业收 ...

  2. webstorm添加调试nodejs

    打开run菜单选择Edit Configurations 展开defaults菜单,选择nodejs 点击+按钮,选择Node.js,出现下面弹出框. 点击ok保存

  3. kubernetes实战(二十):k8s一键部署高可用Prometheus并实现邮件告警

    1.基本概念 本次部署使用的是CoreOS的prometheus-operator. 本次部署包含监控etcd集群. 本次部署适用于二进制和kubeadm安装方式. 本次部署适用于k8s v1.10版 ...

  4. CDN工作过程(第二种版本)

    作者:代希刚链接:https://www.zhihu.com/question/36514327/answer/121026637来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  5. MutationObserver 监听DOM树变化

    1 概述 Mutation observer 是用于代替 Mutation events 作为观察DOM树结构发生变化时,做出相应处理的API.为什么要使用mutation observer 去代替 ...

  6. 加密货币 (Cryptocurrency) 市值 (market capitalization) 列表

    https://coinmarketcap.com/all/views/all/ ico 列表 https://www.icoalert.com/?q=&is_v=1 https://www. ...

  7. html05

    1.js中的对象-内置对象-外部对象-自定义对象 2.常见的内置对象有哪些?-String对象-Number对象-Boolean对象-Array对象-Math对象-Date对象-RegExp正则对象- ...

  8. Twitter OA prepare: Visit element of the array

    分析:就是建立一个boolean array来记录array里面每个元素的访问情况,遇到访问过的元素就停止visiting,返回未访问的结点个数 public int visiting(int[] A ...

  9. Linux系统——Keepalived高可用集群

    #### keepalived服务的三个重要功能1. 管理LVS负载均衡软件Keepalived可以通过读取自身的配置文件,实现通过更底层的接口直接管理LVS的配置以及控制服务的启动,停止功能,这使得 ...

  10. 匹克定理pick

    与POJ1226为例 要知道在一个格点多边形内 知道期内部的点数 Q,边上的点数L,就可以知道他的面积pick定理及 S=Q+L/2-1; 然后 还有边上的点数除了多边形的顶点外,还有一些点该怎么求呢 ...