在 Android 4.3版本之前,Android通过DAC(Discretionary Access Control)自主访问控制来进行权限管理。
DAC 的核心思想很简单,通俗的来讲就是“谁创造了我,我就拥有谁的权利”。比如, root 用户启动 Camera,那么 Camera 就有 root 用户的权限,在 Linux 系统上能干任何事情。
很显然,DAC 管理太过宽松,只要想办法在 Android 系统上获取到 root 权限就可以了。所以在Android5.0版本之前,android系统很容易被破坏,设备厂商也经常在保修单中明确说明“Root不保修”的政策。
那么该如何解决这个问题呢? Google在android4.3版本上便引入了SElinux,只不过是默认关闭的状态,在Android5.0上默认强制打开。
SElinux是一种新的安全模型,这中模型叫 MAC(Mandatory Access Control),翻译为强制访问控制。在Linux系统中,相信大家都听过一句话叫作“一切皆文件”,但是文件可分为两种“活的”和“死的”,“活的”是进程,映射到软件层面的意思是:活的进程能发起动作,例如它能打开文件并操作它,而死的文件只能被进程操作。
SELinux的政策规定进程如果想干事情,都必须在《安全策略文件》中赋予权限,凡是没有出现在安全策略文件中的权限都会被拒绝。
在 SELinux 中,每种东西都会被赋予一个安全属性,官方说法叫做 Security Context,Security Context 是一个字符串,同时也分为进程和文件两种
进程的Security Context:
例如通过 ps -Z | grep sharplogcat 命令查看sharplogcat进程:
lcd_xxgae7a:/ # ps -AZ | grep sharplogcat
u:r:sharplogcat:s0 system 2640 1 9188 3092 __skb_wait_for_more_packets 0 S sharplogcat
其中
- u 为user的意思,SEAndroid 中定义了一个 SELinux 用户,值为 u
- r 为 role 的意思,role 是角色之意,它是 SELinux 中一个比较高层次,更方便的权限管理思路。简单点说,一个 u 可以属于多个 role,不同的 role 具有不同的权限。
- sharplogcat代表该进程所属的 Domain(域) 为 init 。MAC强制访问控制 的基础管理思路其实是 Type Enforcement Access Control(简称TEAC,一般用TE表示),对进程来说,Type 就是 Domain,比如 sharplogcat需要什么权限,都需要通过 allow 语句在 te 文件中进行说明。
- s0 是 SELinux 为了满足军用和教育行业而设计的 Multi-Level Security(MLS)机制有关。简单点说,MLS 将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问
文件的Security Context:
例如通过 ls -AZ vendor/bin/sharplogcat 命令查看sharplogcat文件:
lcd_xxgae7a:/ # ls -AZ vendor/bin/sharplogcat
u:object_r:sharplogcat_exec:s0 vendor/bin/sharplogcat
其中
u:同样是 user 之意,它代表创建这个文件的 SELinux user
object_r:文件是死的东西,它没法扮演角色,所以在 SELinux 中,死的东西都用 object_r 来表示它的 role
sharplogcat_exec,和进程的 Domain 是一个意思,它表示 sharplogcat 文件所属的 Type 是 sharplogcat_exec
s0:MLS 的等级
SELinux 规范
allow domains types:classes permissions;
- Domain - 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
- Type - 一个对象(例如,文件、套接字)或一组对象的标签。
- Class - 要访问的对象(例如,文件、套接字)的类型。
- Permission - 要执行的操作(例如,读取、写入)。
= allow : 允许主体对客体进行操作
= neverallow :拒绝主体对客体进行操作
= dontaudit : 表示不记录某条违反规则的决策信息
= auditallow :记录某项决策信息,通常 SElinux 只记录失败的信息,应用这条规则后会记录成功的决策信息。
实例介绍
以上面介绍的sharplogcat为例:在系统rc文件创建sharplogcat进程(该进程类似于原生的logcat,用于记录android log),默认不自启动,通过程序控制启动
service sharplogcat /vendor/bin/sharplogcat -n 1 -r ${persist.sys.logbuffer} -v time -f ${sys.android.log}
user system
group system
disabled
oneshot
system/sepolicy/目录下是Android系统默认的策略文件,这些文件在编译后会包含 SELinux 内核安全政策,并涵盖上游 Android 操作系统。但我们在配置添加SELinux策略文件时并不是在该目录下,而是在/device/manufacturer/device-name/sepolicy 目录中,如HISI平台的为device/hisilicon/bigfish/external/sepolicy目录下。
1. 配置新的sharplogcat.te政策文件,在编译到单个 SELinux 内核政策文件时,新的政策文件会与现有的政策文件组合在一起,te文件中按照sharplogcat所需要的权限进行配置(切记不可为了方便,把所有的权限加进去,应该是需要哪些加哪些):
# Policy for sharplogcat
type sharplogcat, domain;
type sharplogcat_exec, exec_type, file_type, vendor_file_type;
init_daemon_domain(sharplogcat)
allow sharplogcat sharplogcat:capability { dac_override sys_nice };
allow sharplogcat sharp_log_file:dir rw_dir_perms;
allow sharplogcat sharp_log_file:file { create read open write append rename getattr setattr rw_file_perms };
allow sharplogcat logdr_socket:sock_file { write };
allow sharplogcat logd:unix_stream_socket { connectto read };
2. file_contexts,该文件用于为文件分配标签,并且可供多种用户空间组件使用。在创建新政策时,请创建或更新该文件,以便为文件分配新标签:
/(vendor|system/vendor)/bin/sharplogcat u:object_r:sharplogcat_exec:s0
SELinux 相关设置
SElinux共有两种等级可以设置,可通过getenforce查看
- 宽容模式(permissive) - 仅记录但不强制执行 SELinux 安全政策。
- 强制模式(enforcing) - 强制执行并记录安全政策。如果失败,则显示为 EPERM 错误。
1.临时关闭
setenforce 命令修改的是 /sys/fs/selinux/enforce 节点的值,是 kernel 意义上的修改 selinux 的策略,缺点是断电之后,节点值会复位。
setenforce 0
2.永久关闭
第一种方法:修改system/core/init/Android.mk
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
#HISILICON add begin
#reboot. Disable dumping when rebooting in non-user mode.
init_options +=
-DALLOW_LOCAL_PROP_OVERRIDE=1
-DALLOW_PERMISSIVE_SELINUX=1 //1:permissive
-DREBOOT_BOOTLOADER_ON_PANIC=1
-DDUMP_ON_UMOUNT_FAILURE=0
#HISILICON add end
else
init_options +=
-DALLOW_LOCAL_PROP_OVERRIDE=0
-DALLOW_PERMISSIVE_SELINUX=1 //1:permissive
-DREBOOT_BOOTLOADER_ON_PANIC=0
-DDUMP_ON_UMOUNT_FAILURE=0
endif
第二种方法:修改system/core/init/init.cpp,需要重新编译boot分区并烧录该分区。
static bool selinux_is_enforcing(void) //直接注释掉内容,reture false即可。
{
if (ALLOW_PERMISSIVE_SELINUX) {
return selinux_status_from_cmdline() == SELINUX_ENFORCING;
}
return true;
}
第三种方法:开机时修改bootargs。开机时不断Ctrl+c进入fastboot模式,printenv获取当前参数配置,修改其中androidboot.selinux=permissive,再setenv->saveenv->reset即可。
bootargs=selinux=1 androidboot.selinux=permissive firmware_class.path=/vendor/firmware/ console=ttyAMA0,115200 loglevel=7 no_console_suspend blkdevparts=mmcblk0:1M(fastboot),1M(bootargs),40M(recovery),8M(panelparam),2M(deviceinfo),38M(logo),2M(btfw),40M(kernel),1M(dtb),2M(atf),25M(trustedcore),10M(securestore),1M(versioninfo),1M(misc),3072M(system),300M(vendor),50M(atv),50M(db),2048M(cache),-(userdata) mtdparts=hi_sfc:-(hi_sfc) pci=nomsi mem=3072M dma_zone=2G mmz=ddr,0,1996M,48M mdlid=0 cmode=0 finit=0 panelsize=0 androidboot.sharp.serialno= androidboot.productname=--
ver=Fastboot 3.3.0-00015-g327655d-dirty (build@serd-build-008) (Mar 18 2019 - 09:17:15)
在实际的开发中,配置selinux是非常繁琐和枯燥的,但是作为官方推广的安全策略,还是希望大家能够了解一些,以上就是本文的全部内容,希望对大家的学习有所帮助。