SeLinux & 自启动-实战

935 阅读6分钟

SeLinux 权限总结

SELinux 背景

  • 在SELinux之前,Linux中使用的安全机制称为DAC,自主访问控制(Discretionary Access Control)。在自主访问控制下,主要根据文件所属的分组来限制对资源的访问。分组有3种,分别表示拥有者、同组用户和其他用户。DAC是一种很粗略的权限管理方法,只能控制对资源的读、写和执行,但是不能进行更精细的控制。
  • SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则).

    简单理解: 服务进程需要什么权限,便给什么权限,没有用到的权限,就不给.

调试 SELinux 命令

命令列表

命令含义
getenforce获取当前seLinux状态
setenforce 1打开seLinux
setenforce 0关闭seLinux

getenforce 命令

# getenforce
Enforcing		===> 表示: SELinux 打开, 程序会受到 Selinux 权限限制
Permissive		===> 表示: SELinux 关闭, 程序 不会受到 Selinux 权限限制

setenforce 命令

# setenforce 0		===> 关闭 SELinux   

# setenforce 1		===> 打开 SELinux   

SELinux 常见问题 及 解决办法

获取 SELinux log

dmesg | grep denied

SELinux 标志 log

log:
`[   53.024184] init: avc:  denied  { set } for property=SP3_Screen_state pid=2535 uid=1000 gid=1000 scontext=u:r:system_server:s0 tcontext=u:object_r:default_prop:s0 tclass=property_service permissive=0`

avc: denied { xx } xx permissive=0

log:
`[   53.024184] init: avc:  denied  { set } for property=SP3_Screen_state pid=2535 uid=1000 gid=1000 scontext=u:r:system_server:s0 tcontext=u:object_r:default_prop:s0 tclass=property_service permissive=0`
  1. 解析其含义:
  • 源类型 -> sourcecontext 指的是 scontext=u:r:system_server:s0 的 system_server
  • 目标类型 -> stargetcontext 指的是 tcontext=u:object_r:default_prop:s0 中的 default_prop,
  • 访问类型 -> sclass 指的是 tclass=property_service 中的 property_service
  • 操作权限 -> s许可指的是 denied { set } 中的 set
  1. 找到 scontext 对应的 .te 文件. find device/qcom/sepolicy -name system_server.te

  2. 修改 .te 文件, 添加如下格式的一行语句:(结尾别忘了分号)

格式:allow 源类型 目标类型:访问类型 {操作权限};
eg:
	allow system_server default_prop:property_service set;

编译 SELinux

编译 SELinux(正常模式)
编译 .rc 文件 , .te 文件:
	编译:
		make  bootimage -j30
	生成文件:
		out/target/product/msm8909/obj/ETC/sepolicy_intermediates/policy.conf
	
	reboot bootloader
	fastboot flash boot boot.img
	fastboot reboot
编译 SELinux(Recovery模式)
编译 Recovery SeLinux:
	编译:
		make recoveryimage -j30  --> 会编译 kernal , 和 recovery 
	烧录:
		boot.img
			编译:
				make  bootimage -j30
				
				reboot bootloader
				fastboot flash boot boot.img
				fastboot reboot
			
		recovery.img
			代码目录:
				bootable/recovery/
			编译命令:
				make recoveryimage -j30
			生成文件:
				out/target/product/msm8909/recovery.img
			烧入到板子:
				reboot bootloader
				fastboot flash recovery recovery.img
				fastboot reboot

selinux 编译时 neverallow 报错

`libsepol.report_failure: neverallow on line 344 of system/sepolicy/domain.te (or line 9216 of policy.conf) violated by allow system_server default_prop:property_service { set };
libsepol.check_assertions: 1 neverallow failures occurred`

按照 log 提示 找到对应的 .te: system/sepolicy/domain.te

修改 .te 在 nerverallow 中用 {} 里用 -xx 排除某个

system/sepolicy/domain.te

-neverallow { domain -init -healthd } default_prop:property_service set;
+neverallow { domain -init -healthd -system_server } default_prop:property_service set;
  • 类似这样的补丁.

image-20220315222023342

自定义 SeLinux 安全策略(最高权限使用)

作用

解决: 类似这类问题

  • 如果开机,需要自动安装 APK , 那么在启动脚本便需要执行 pm install命令来安装APK, 如果没有 自定义SElinux 安全策略,可能会遇到类似这种报错。

    [   42.857882] init: cannot find 'pm' (No such file or directory), disabling 'exec 14 (pm)'
    
    • 而解决这中问题,需要在脚本中使用 /system/bin/sh /system/bin/pm install xx.apk
    • 但这种办法,我做为强迫症,觉得很麻烦,故我选择采用 自定义 SeLinux 安全策略(最高权限使用) 来解决这类问题.
    • 仅仅需要在脚本执行 pm install xx.apk 便可以安装 APK了. 而不需要添加上 一大堆前缀.
定义 nsc_elan_hr40 Selinux 安全策略:
参考 qti-testscripts.te
device/qcom/sepolicy/test/qti-testscripts.te
新建、编辑 nsc_elan_hr40.te
  • device/qcom/sepolicy/test/nsc_elan_hr40.te
# Copyright (c) 2015, The Linux Foundation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
#     * Neither the name of The Linux Foundation nor the names of its
#       contributors may be used to endorse or promote products derived
#       from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

userdebug_or_eng(`
  type nsc_elan_hr40, domain, domain_deprecated, mlstrustedsubject;
  permissive nsc_elan_hr40;
  domain_trans(init, shell_exec, nsc_elan_hr40)

  #super_user - start
  # Add nsc_elan_hr40 to various domains
  net_domain(nsc_elan_hr40)
  app_domain(nsc_elan_hr40)

  dontaudit nsc_elan_hr40 self:capability_class_set *;
  dontaudit nsc_elan_hr40 kernel:security *;
  dontaudit nsc_elan_hr40 kernel:system *;
  dontaudit nsc_elan_hr40 self:memprotect *;
  dontaudit nsc_elan_hr40 domain:process *;
  dontaudit nsc_elan_hr40 domain:fd *;
  dontaudit nsc_elan_hr40 domain:dir *;
  dontaudit nsc_elan_hr40 domain:lnk_file *;
  dontaudit nsc_elan_hr40 domain:{ fifo_file file } *;
  dontaudit nsc_elan_hr40 domain:socket_class_set *;
  dontaudit nsc_elan_hr40 domain:ipc_class_set *;
  dontaudit nsc_elan_hr40 domain:key *;
  dontaudit nsc_elan_hr40 fs_type:filesystem *;
  dontaudit nsc_elan_hr40 {fs_type dev_type file_type}:dir_file_class_set *;
  dontaudit nsc_elan_hr40 node_type:node *;
  dontaudit nsc_elan_hr40 node_type:{ tcp_socket udp_socket rawip_socket } *;
  dontaudit nsc_elan_hr40 netif_type:netif *;
  dontaudit nsc_elan_hr40 port_type:socket_class_set *;
  dontaudit nsc_elan_hr40 port_type:{ tcp_socket dccp_socket } *;
  dontaudit nsc_elan_hr40 domain:peer *;
  dontaudit nsc_elan_hr40 domain:binder *;
  dontaudit nsc_elan_hr40 property_type:property_service *;
  dontaudit nsc_elan_hr40 service_manager_type:service_manager *;
  dontaudit nsc_elan_hr40 keystore:keystore_key *;
  dontaudit nsc_elan_hr40 domain:debuggerd *;
  dontaudit nsc_elan_hr40 domain:drmservice *;
  dontaudit nsc_elan_hr40 unlabeled:filesystem *;
  #super_user - end

  #Added below rule in same file to keep all debug policies
  #under one common file.

  # All domains can read proc enrty of nsc_elan_hr40
  r_dir_file(domain, nsc_elan_hr40)
  r_dir_file(nsc_elan_hr40, domain)

  allow adbd nsc_elan_hr40:process dyntransition;
  allow { domain -mediaextractor -mediacodec } nsc_elan_hr40:unix_stream_socket connectto;
  allow domain nsc_elan_hr40:fd use;
  allow { domain -mediaextractor -mediacodec } nsc_elan_hr40:unix_stream_socket { getattr getopt read write shutdown };
  binder_call({ domain -init -netd }, nsc_elan_hr40)
  allow domain nsc_elan_hr40:fifo_file { write getattr };
  allow domain nsc_elan_hr40:process sigchld;
  diag_use(radio)
')

  • device/qcom/sepolicy/Android.mk 会自动把 device/qcom/sepolicy/test/ 目录下的 所有的 .te 进行编译使用.

新建、编辑 init.nsc_elan_hr40.rc 服务文件
  • init.nsc_elan_hr40.rc

    # Copyright (C) 2012 The Android Open Source Project
    #
    # for NSC ELAN HR40 Project
    #
    
    service ElanHR40 /system/bin/sh /system/etc/ElanHR40.sh
        class late_start
        user root
        disabled
        oneshot
        seclabel u:r:nsc_elan_hr40:s0             # ----> 使用 nsc_elan_hr40 自定义 SELinux安全策略
    
新建、编辑 ElanHR40.sh 启动脚本
  • /system/etc/ElanHR40.sh
#!/system/bin/sh
Tag="ELAN HR40: "


main()
{
	log "$Tag just test customized Selinux."
	sleep 1
	log "$Tag done."
}

main
init.rc 导入 init.nsc_elan_hr40.rc
  • init.rc 导入 init.nsc_elan_hr40.rc

    import /init.nsc_elan_hr40.rc
    

    image-20221124223245127

启动 ElanHR40 服务
  • init.qcom.rc

    • 在完全启动成功时, on property:sys.boot_completed=1, 启动 ElanHR40 服务

      start ElanHR40
      

      image-20221124223204351

验证是否启动脚本成功
  • 然后重启Android 板子, 看看 logcat 是否打印启动脚本对应的log , 来判断是否开机自启动脚本成功.

image-20221125000141324

  • 通过log , 可以看到开机自启动启动脚本成功。

Kernel 关闭 SELinux

修改kernel/arch/arm/configs/msm8909-1gb_defconfig文件(xxx一般为手机产品名), 去掉CONFIG_SECURITY_SELINUX=y 的配置项

NOTE: garen 还没有实践验证过.

Selinux 其他问题

does not have a SELinux domain defined.

  • /init.nsc_elan_hr40.rc

    on property:PowerUpIR=Enable
    	exec /system/bin/gpioTest.sh 68 1
    	exec /system/bin/gpioTest.sh 69 1
    	exec /system/bin/gpioTest.sh 89 1
    	setprop PowerUpIR none
    
  • 执行 setprop PowerUpIR Enable

    • 报错 init: Service exec 8 (/system/bin/gpioTest.sh) does not have a SELinux domain defined.
  • 排查分析:

    • 查询 security context:
      	ls -lZ /system/bin/gpioTest.sh
      	-rwxr-xr-x 1 root shell u:object_r:system_file:s0 430 2022-03-02 02:42 
      
      /system/bin/gpioTest.sh ---> 排查发现 gpioTest.sh 有 定义 SELinux domain的.
      
  • 原因 : system_file 属性 的 /system/bin/gpioTest.sh 不能直接被 exec ?

  • 解决: 添加 "/system/bin/sh"

    • image-20220317145054777