浅谈SEAndroid安全机制及应用方法
吐槽:准备学习一下SELinux/SEAndroid手里有一本书《深入理解Android内核设计思想》,看完章节“我是谁?我在哪?”能理解四层的意思,我发现另外的六层都是给会的人写的,头大难搞。趁着假期查资料看博客,一点一点修补本文章,有理解偏差或理解不到位的地方望大佬们纠正。
内容提纲:
➢SEAndroid/SELinux简介
➢SEAndroid/SELinux框架
➢SELinux Policy介绍
➢安全策略文件(TE文件)
➢SELinux安全问题分析
----➢SELinux设备文件权限解决办法
----➢SELinux服务权限解决办法
----➢SELinux可执行权限解决办法
➢补充
----➢客体类型添加
一.SEAndroid/SELinux简介
SELinux呢这里就不展开讲述了,直接进行SEAndroid机制。前段时间u盘插上板子,作者利用串口交互,以root用户想要删除U盘里的内容,就会报错误权限不足,这就得益于SEAndroid对设备的全面保护。
SEAndroid是Google在nlet 4.4 上正式推出的一套以SELinux为基础于核的系统安全机制。而SELinux则是由美国NSA (国安局)和一些公司( RedHat、Tresys )设计的一 个针对 的安全加强系统。NSA最初设计的安全模型叫FLASK ,全称为Flux Advanced Security Kernel (由Uta大学和美国国防部开发,后来由NSA将其开源) , 当时这套模型针对DTOS系统。后来, NSA觉得Linux更具发展和普及前景,所以就在Linux系统上重新实现了FLASK,称之为SELinux。
两种安全机制DAC(Discretionary Access Control)和MAC(Mandatory Access Control)。通俗地讲,这两个机制的区别是。在DAC里,如果个应用获取了一个用户权限,如Root,那他的所有操作操作都是基于这个用户权限。而MAC就简单霸道好多,无论你是谁,甚至是有Root用户权限,文件权限为777,但每个动作都是需要被允许之后可以被执行。这里可以是在安全策略文件中被允许也可以是用户手动允许 。
二.SEAndroid/SELinux框架
用户看到的:服务权限、文件权限、属性权限、APP权限。
SELinux最终编译成libselinux.so文件,为上层提供服务。
三.SELinux Policy介绍
SELinux两个最基本的对象是主体( Subject )和客体(Object )。主体和客体分别对应的是"进程”和“文件”。这里的文件并不单指的是实际存在的文件,而是指Linux里"一 切皆文件”里指的文件。如Socket ,系统属性等。
在SEAndroid中对主体和客体进行了进一步形式上的封装和扩展,其实差不多。SEAndroid里细分为 :系统文件,服务,系统属性,Binder和Socket.这里的系统属性指的是build.prop里的属性,也是getprop命令查询出来的属性。
1.ps - Z可以查看当前进程(主体)安全上下文。
root@rk3288:/ # ps -Z
LABEL USER PID PPID NAME
u:r:init:s0 root 1 0 /init
u:r:kernel:s0 root 2 0 kthreadd
u:r:kernel:s0 root 3 2 ksoftirqd/0
u:r:kernel:s0 root 5 2 kworker/0:0H
u:r:kernel:s0 root 7 2 migration/0
u:r:kernel:s0 root 8 2 rcu_preempt
u:r:kernel:s0 root 9 2 rcu_bh
u:r:kernel:s0 root 10 2 rcu_sched
u:r:kernel:s0 root 11 2 watchdog/0
u:r:kernel:s0 root 12 2 watchdog/1
u:r:kernel:s0 root 13 2 migration/1
u:r:kernel:s0 root 14 2 ksoftirqd/1
u:r:kernel:s0 root 16 2 kworker/1:0H
u:r:kernel:s0 root 17 2 watchdog/2
u:r:kernel:s0 root 18 2 migration/2
u:r:kernel:s0 root 19 2 ksoftirqd/2
u:r:kernel:s0 root 21 2 kworker/2:0H
u:r:kernel:s0 root 22 2 watchdog/3
u:r:kernel:s0 root 23 2 migration/3
u:r:kernel:s0 root 24 2 ksoftirqd/3
u:r:kernel:s0 root 26 2 kworker/3:0H
u:r:kernel:s0 root 27 2 khelper
u:r:kernel:s0 root 28 2 kdevtmpfs
左边的一列是Security Context。u:r:init:s0的意思是:
-
u,是指user,它代表SELinux的一个用户。
-
r,为role(角色)即Role Based Access(基于角色的访问控制,简称为RBAC),它是SELinux中比较高层次。简单点说,一个u可以属于多个role,不同的role具有不同的权限。
-
init/kernel,代表该进程所属的Domain(域)。
-
s0,SELinux为了满足军用和教育行业而设计的MultiLevel Security(MLS)机制。简单点说,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应的级别的进程才能进行访问。
2.ls - Z可以查看当前文件(客体)安全上下文。
root@rk3288:/ # ls -Z
drwxr-xr-x root root u:object_r:cgroup:s0 acct
drwxrwxrwx root root u:object_r:rootfs:s0 bin
drwxrwx--- system cache u:object_r:cache_file:s0 cache
lrwxrwxrwx root root u:object_r:rootfs:s0 charger -> /sbin/healthd
dr-x------ root root u:object_r:rootfs:s0 config
lrwxrwxrwx root root u:object_r:rootfs:s0 d -> /sys/kernel/debug
drwxrwx--x system system u:object_r:system_data_file:s0 data
-rw-r--r-- root root u:object_r:rootfs:s0 default.prop
drwxr-xr-x root root u:object_r:device:s0 dev
drwx------ root root u:object_r:rootfs:s0 dmb
-rw-r--r-- root root u:object_r:rootfs:s0 drmboot.ko
drwxrwxrwx root root u:object_r:rootfs:s0 env_flag
lrwxrwxrwx root root u:object_r:rootfs:s0 etc -> /system/etc
-rw-r--r-- root root u:object_r:rootfs:s0 file_contexts
lrwxrwxrwx root root u:object_r:rootfs:s0 fstab.rk30board -> /fstab.rk30board.bootmode.emmc
-rw-r----- root root u:object_r:rootfs:s0 fstab.rk30board.bootmode.emmc
-rw-r----- root root u:object_r:rootfs:s0 fstab.rk30board.bootmode.unknown
drwxrwxrwx root root u:object_r:rootfs:s0 home
-rwxr-x--- root root u:object_r:init_exec:s0 init
-rwxr-x--- root root u:object_r:rootfs:s0 init.connectivity.rc
-rwxr-x--- root root u:object_r:rootfs:s0 init.environ.rc
-rwxr-x--- root root u:object_r:rootfs:s0 init.rc
-rw-r--r-- root root u:object_r:rootfs:s0 张志路-root.txt
- u,是user的意思,表示创建这个文件的SELinux user。
- object_r,这个标志位在文件里代表一个用户角色(role),不同的role具有不同的权限。
- 这是一个type的标志位,也是TE里最重要的一个标志位。不然怎么怎么称为TE(Type Enforcement);它表示root目录对应的Type的rootfs。
- s0,MLS的级别。
在这里细心的朋友就会注意到:“之前我们Linux的label不是UID/GID吗?怎么变成了user:role:type:security了呢?”没错这都是SEAndroid替换的,注意我说的是‘替换’。SEAndroid呢,主要通过label中的Type来定义安全策略的(这就是Type Enforment)这就是我们.te文件的由来。
读到这里你可能就要问了,上面分析的这些信息在哪里被设置定义的呢?这些信息都在xxx_contexts文件中被登记在案的,前提是要先type定义客体,这个下面还会讨论。
- file_contexts
即包括编译过程中文件的安全标签,也用于在运行时态对设备节点、socket端口、init.rc产生的/data目录进行安全标签的规划。当你创建新的安全策略时,在某些情况下需要更新这个文件夹分配新的标签。而为了让新标签生效,这里就要重新编译image或者执行restorecon命令。 - genfs_contexts
- 这个文件用于为不支持扩展属性的文件系统(列如proc和vfat)添加标签。这个配置将作为核心策略的一部分被加载。
- property_contexts
这个文件用于定制Android系统各属性的标签,以确认哪些进程可以设置他们。它将在系统启动时的init进程中被加载,或者是当selinux.reload_policy被置为1时被重新加载。 - seapp_contexts
这个文件用于为APP进程和/data/data文件夹指定标签。系统将在三个时机读取seapp_contexts文件:1.当一个APP被zygote进程孵化时;2.当installd在启动时;3.当selinux.reload_policy属性被置为1时。
四.安全策略文件(TE文件)
1.介绍
MAC的安全策略文件学名是TEAC(Type Enforcement Access Control)。简称TE。里面的语言被称为强制类型语言。
在Android源码中对应的TE文件所在的路径为Android源码/external/sepolicy/
2.语法
在SELinux当中,所有访问都必须明确授权,SEL inx默认不允许任何访问,完全不考虑当前UG0结构,即不考虑用户/组ID是什么。这也就意味着,在这里没有超级用户了。那么如果主体需要对客体进行访问该如何进行呢?
在SELinux当中,通常是使用allow规则来指定主体类型(即域)对客体类型授子访问权限,也就是allow规则规定了哪些类型的进程可以访问哪些客体。allow规则由四部分组成:
/* 主体 客体 */
allow domains types:classes permissons
- domains,原类型(Source type (s) )主体类型, 即域。用于单一进程或一系列进程。
- types,目标类型(Target type(s)) 客体类型。用于标识客体(文件、Socket等)或一系列客体。
- classes,客体类别(Object class (es) )客体的类别。被访问的客体(文件、Socket等)的具体种类。
- permissons,许可(Permission (s) )主体可以对客体执行哪些操作(读、写等)我们称之为访问向量。
3.两种模式
SELinux Mode,SELinux Mode 有两种模式Permissve Mode(宽容模式)和Enforcing Mode(强制模式)。区别在于宽容模式只会打印SELinux Log。而强制模式会进行真正拦截。如果被拦截,kernel log中的关键字“avc:denied“。可以通过cat /sys/fs/selinux/enforc命令进行查看权限。
setenforce命令:
- setenforce 0 关闭权限。
- setenforce 1 打开权限。
五.SELinux安全问题分析
大致流程:
1.用type关键字定义客体。(这里就发挥一下我的联想类比能力。就好比出生去type一张身份证)
2.将定义的客体放到【file_contexts】或者【service_contexts】文件中,告诉系统你的客体。(就好像结婚登记)
3.用allow关键字添加说明主体访问客体的权限。(就好像修订自己家规家法)
log内容分析:
avc:denied{connectto} for pid=2671 comm="ping"
path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
- {connectto},代表的是发生的行为。整个句子表示有人尝试去链接一个unix stream socket。
- scontext,代表的是发生上述行为的主体的具体环境。在这个例子中就是某个以shell运行的程序。
- tcontext,代表的是客体的具体环境。在这个例子中就是一个unix_stream_socket的所有者netd。
- comm,comm="ping"表示的是当denial发生时究竟执行了什么语句。
1.SELinux设备文件权限解决办法
[53692.570392] type=1400 audit(12565266.940:42): avc: denied
{ read write } for pid=10794 comm="m.example.hello" name="led1"
dev="tmpfs" ino=39430 scontext=u:r:untrusted_app:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=0
分析:
- 缺少什么权限: read write
- 谁缺少权限: scontext=u:r:untrusted_app:s0 untrusted_app
- 对那个文件缺少权限:tcontext=u:object_r:device:s0 device
- 什么类型的文件: tclass=chr_file chr_file
解决办法:在untrusted_app.te文件中添加
Allow untrusted_app device:chr_file {read write }
把缺少的权限添加上去,添加的过程如下:
先进去Android源码下的/external/sepolicy/下
①修改file_contexts
/dev/led1 u:object_r:led1_device:s0
②修改device.te
type led1_device, dev_type(, mlstrustedobject); (括号内为6.0权限)
③修改untrusted_app.te
allow untrusted_app led1_device:chr_file rw_file_perms;
添加好了之后重新编译Android的源码,烧写system.img和boot.img
2.SELinux服务权限解决办法
131 E SELinux : avc: denied { add } for service=Hello
scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0
tclass=service_manager
分析:
- 缺少什么权限: { add }权限,
- 谁缺少权限: system_server
- 对哪个文件缺少权限:default_android_service
- 什么类型的文件: tclass=service_manager
解决方法:在system_server.te中添加
allow system_server default_android_service:service_manager add;
先进去Android源码下的/external/sepolicy/下
①在service.te文件中添加
type Hello_service, (app_api_service,)service_manager_type; (括号内为6.0权限)
②在service_contexts文件中添加
Hello u:object_r:Hello_service:s0
③在system_server.te文件中添加
allow system_server Hello_service: service_manager add;
3.SELinux可执行权限解决办法
12-25 11:51:27.260 147 147 W init : type=1400
audit(0.0:4): avc: denied {execute_no_trans } for
path="/system/bin/test" dev="nandd" ino=476
scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0
tclass=file permissive=0
分析:
- 缺少什么权限: execute_no_trans
- 谁缺少权限: init
- 对哪个文件缺少权限: system_file
- 什么类型的文件: file
解决方法:在init.te中添加
allow init system_file:file execute_no_trans;
先进去Android源码下的/external/sepolicy/下
①新建test.te文件中添加
type test,domain;
type test_exec,exec_type,file_type;
init_daemon_domain(test)
②在file_contexts文件中添加
/system/bin/test u:object_r:test_exec:s0
③在init.te文件中添加
allow test system_file:file execute_no_trans;
添加好了之后重新编译Android的源码,烧写system.img和boot.img
六.补充
1.客体类型添加
根据我们上面讲的TE文件语法那一小节,了解到allow语句。注意allow语句是主体访问客体缺少权限,allow语句添加权限信息。
但是系统并不认识我们写的客体,这时,我们就需要用type 语句定义一下我们的客体(客体类型添加),让系统认识一下。
这里我们先看一小段init.te的内容:
类型声明语法:
- type 类型名称 [alias 别名集] [属性集],属性集:设备属性集dev_type,服务属性集service_manager_type;
- 别名集如果有多个别名,可在一对大括号中用空
格将各个别名区别开来,如: alias {aliasa_t aliasb_t}。 - 属性集如果同时指定多个属性标识符,属性之间使用逗号进行分隔,如:bin_ type, file_ type, exec_ type;
2.在Android系统中定义自己的SEAndroid
Android系统是允许设备厂商定制自己的安全策略的。先留个尾巴,后续再写。