AOSP添加新的开机服务的权限

如果想要了解selinux的介绍可以戳AOSP安全策略SElinux_android以及问题排查思路,有助于更深的理解和应用。

1 添加⼀个系统框架服务,例redmine:179485
// ⽤于针对java的binder service,如果需要调⽤到框架的某些接⼝,或是给app提供某些特殊接⼝,可能
// 需要增加java binder服务:
@Override
public void onStart() {
    publishBinderService("ccc_service", new BinderService());
    publishLocalService(CCCServiceInternal.class, new LocalService());
    
    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);
}
# 执⾏命令:'get_build_var BOARD_PLAT_PRIVATE_SEPOLICY_DIR' 后对应的⽬录修改,如:

# 修改 device/rockchip/common/sepolicy/private/service.te
# 在最后⼀⾏添加(关联上下⽂)
type ccc_service, system_api_service, system_server_service,
service_manager_type;
# 然后修改同⽬录下device/rockchip/common/sepolicy/private/service_contexts ⽂件(给服
# 务打上标签,可以在service_context⽬录进⾏)
# 中间插⼊⼀⾏
ccc u:object_r:ccc_service:s0
2 添加⼀个开机⾃启动⼆进制服务 - Android 7.1
  • 增加某个⼆进制程序或某个脚本,想要开机⾃动执⾏,如 rockchip.sample.nougat.sh
#! /system/bin/sh
echo "starting service..."
# 注:如果是脚本,务必保持⾸⾏有shell的路径,如上所⽰,且中!后有空格本节所有要修改的⽂件都位于:get_build_var BOARD_SEPOLICY_DIRS执⾏结果列出的⽂件夹中。
  • 声明服务 在init.rc(任意会加载执⾏到的rc⽂件,或⾃⼰声明⼀个新的rc⽂件)中声明服务
service rockchip-sample-nougat-sh /system/bin/rockchip.sample.nougat.sh 
#格式: service service_name service_path, 注意,脚本务必要可执⾏,服务名后接的直接就是可执⾏程序,
#这个可执⾏程序必须在file_context中指定标签,脚本程序不能写成 /system/bin/sh xxx.sh,这样就代表服务的主体是sh/shell,⽽不是你的脚本!!!
class main #class代表启动阶段,具体需求请⾃⾏搜索修改
user root
group root wifi
oneshot #只启动⼀次就退出;如果不是⾃启动,需要触发需要加 disable 参数,通过start servic_name即可启动服务
  • 错误脚本服务⽰例:
service rockchip-sample-nougat-sh /system/bin/sh /system/bin/rockchip.sample.nougat.sh
    class main
    user root
    group root wifi
    oneshot
  • 声明运⾏域
    sepolicy⽬录下新建 rockchip_sample_nougat.te
type rockchip_sample_nougat, domain;
type rockchip_sample_nougat_exec, exec_type, file_type;
init_daemon_domain(rockchip_sample_nougat)
  • 给⼆进制程序打标签,绑定到te⽂件
    在sepolicy⽬录下的file_contexts⽂件添加:
/system/bin/rockchip\.sample\.nougat\.sh
u:object_r:rockchip_sample_nougat_exec:s0 # 格式: service_path
u:object_r:te_type_name_exec:s0 # 要和上⾯声明的te⽂件相对应,注意转移字符 \
3 添加⼀个开机⾃启动⼆进制服务 - Android 8.0及以上
# 注:本节所有要修改的⽂件都位于:get_build_var BOARD_SEPOLICY_DIRS执⾏结果列出的⽂件夹中。
# 以xxxservice为例。与Android 7.1没有很⼤区别,注意程序或脚本要放在vendor/bin/下:
# 1. init.rc或其他rc
service xxxservice /vendor/bin/xxxservice
    class main
    oneshot
    
# 2. xxxservice.te,与Android 7.1没有很⼤区别,注声明exec type的时候要同时关联
vendor_file_type:
type xxxservice, domain;
type xxxservice_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(xxxservice)

# 3. file_contexts,与Android 7.1⼀致
# 添加⼀条
/vendor/bin/xxxservice u:object_r:xxxservice_exec:s0
4.添加开机启动服务完整实例(以全志R818为例):
1.推送执行文件:

通过peony_perf1.mk ,将执行文件拷贝到/system/bin目录中

# /device/softwinner/peony-perf1/peony_perf1.mk
# 添加如下
#tld filelist
PRODUCT_COPY_FILES += \
    $(LOCAL_PATH)/auto_shell.sh:system/auto_shell.sh \
2.在init.rc下添加对应服务。推荐在对应方案的.rc下新增服务init.device.rc
# /device/softwinner/peony-perf1/init.device.rc
# 在末尾添加
service auto_shell /system/bin/auto_shell.sh
    class core
    critical # 重要服务, 一般与 oneshot 不同时存在
    oneshot # 执行一次
    disabled # 不自己执行,需要被动调用
    seclabel u:r:auto_shell:s0
    shutdown critical

# 或者提前一些执行
service auto_shell_init /system/bin/auto_shell_init.sh
    class core
    critical  # 重要服务, 一般与 oneshot 不同时存在
    oneshot
    seclabel u:r:auto_shell_init:s0
    shutdown critical

# 再或者
service myshell /system/bin/auto_shell.sh
    user root
    group root
    disabled
    seclabel u:r:shell:s0  #使用这个就不需要下一步的自定义.te了
    oneshot

on property:sys.boot_completed=1 # 在引导结束后执行
    start auto_shell   # myshell auto_shell_init
3.添加所需要的权限:
3.1在这/device/softwinner/common/sepolicy/private/  下创建对应脚本名称的.te文件`auto_shell.te`
# 路径:/device/softwinner/common/sepolicy/vendor/auto_shell_init.te
# set_alarm seclabel is specified in init.<board>.rc
type auto_shell, domain, coredomain;
type auto_shell_exec, system_file_type, exec_type, file_type;
init_daemon_domain(auto_shell);

3.2修改文件file_contexts,增加权限:

# 路径:/device/softwinner/common/sepolicy/vendor/file_contexts
# 末尾添加:auto_shell
/system/bin/auto_shell.sh        u:object_r:auto_shell_exec:s0

3.3需要额外修改:

---- system/core/init/selinux.cpp
++++ system/core/init/selinux.cpp
bool IsEnforcing() {
+    return false;
    if (ALLOW_PERMISSIVE_SELINUX) {
        return StatusFromProperty() == SELINUX_ENFORCING;
    }
    return true;
}

权限可通过命令查看:ls -Z filePath

# 命令
ls -Z /system/bin/auto_shell.sh
# 结果
u:object_r:auto_shell_exec:s0 /system/bin/auto_shell.sh

也可以直接关闭selinux的权限校验!

5.修改系统规则以突破限制

注意:修改系统默认的安全规则(尽量不修改,需改要慎重)

问加你位置:
android/system/sepolicy/private/coredomain.te
android/system/sepolicy/prebuilts/api/29.0/private/coredomain.te
具体请自己查阅编译时所报的错误日志。

# coredomain.te 中/sys为例
# /sys
neverallow {
    coredomain
    -init
    -auto_shell_init # this 这里添加是要解决csysfs:file限制的问题
    -ueventd
    -vold
} sysfs:file no_rw_file_perms;

# /dev
neverallow {
    coredomain
    -fsck
    -init
    -auto_shell_init # this 这里添加是要解决console_device:chr_file限制的问题
    -ueventd
} device:{ blk_file file } no_rw_file_perms;

通过log查看auto_shell_init需要的权限:

console:/ # logcat | grep avc   
// 或者 dmesg | grep avc
// 已经将节点和类型都列举出来了
// sysfs:file
cat     : type=1400 audit(0.0:18): avc: denied { read } for name="usb_device" dev="sysfs" ino=22043 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
gpio_pin_contro: type=1400 audit(0.0:37): avc: denied { write } for name="export" dev="sysfs" ino=5998 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
gpio_pin_contro: type=1400 audit(0.0:38): avc: denied { open } for path="/sys/class/gpio/export" dev="sysfs" ino=5998 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1

// shell_exec:file
auto_shell_init: type=1400 audit(0.0:7): avc: denied { read } for path="/system/bin/sh" dev="dm-0" ino=776 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:shell_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:8): avc: denied { execute } for path="/system/bin/sh" dev="dm-0" ino=776 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:shell_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:9): avc: denied { getattr } for path="/system/bin/sh" dev="dm-0" ino=776 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:shell_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:27): avc: denied { read open } for path="/system/bin/sh" dev="dm-0" ino=776 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:shell_exec:s0 tclass=file permissive=1

// console_device:chr_file
auto_shell_init: type=1400 audit(0.0:10): avc: denied { write } for name="console" dev="tmpfs" ino=1259 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:console_device:s0 tclass=chr_file permissive=1
auto_shell_init: type=1400 audit(0.0:11): avc: denied { open } for path="/dev/console" dev="tmpfs" ino=1259 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:console_device:s0 tclass=chr_file permissive=1

// toolbox_exec:file
auto_shell_init: type=1400 audit(0.0:12): avc: denied { getattr } for path="/system/bin/toybox" dev="dm-0" ino=823 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:toolbox_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:14): avc: denied { execute } for name="toybox" dev="dm-0" ino=823 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:toolbox_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:15): avc: denied { read open } for path="/system/bin/toybox" dev="dm-0" ino=823 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:toolbox_exec:s0 tclass=file permissive=1
auto_shell_init: type=1400 audit(0.0:16): avc: denied { execute_no_trans } for path="/system/bin/toybox" dev="dm-0" ino=823 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:toolbox_exec:s0 tclass=file permissive=1

// system_file:file
gpio_pin_contro: type=1400 audit(0.0:29): avc: denied { execute_no_trans } for path="/system/bin/grep" dev="dm-0" ino=595 scontext=u:r:auto_shell_init:s0 tcontext=u:object_r:system_file:s0 tclass=file permissive=1

改进auto_shell_init的定义,我们看一下:

 # set_alarm seclabel is specified in init.<board>.rc
  type auto_shell_init, domain, coredomain;
  type auto_shell_init_exec, system_file_type, exec_type, file_type;
  init_daemon_domain(auto_shell_init)
# add this
  allow auto_shell_init sysfs:file { read open write };
  allow auto_shell_init shell_exec:file { read execute getattr open };
  allow auto_shell_init console_device:chr_file { open write };
  allow auto_shell_init toolbox_exec:file { read execute getattr open execute_no_trans };
  allow auto_shell_init system_file:file { execute_no_trans };

再次提醒:官方不推荐修改系统原有规则,存在很大风险,这里只是拿来简单分享。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容