444 lines
15 KiB
Markdown
444 lines
15 KiB
Markdown
|
# Android SELinux 详解
|
|||
|
|
|||
|
## 1.Kernel SELinux 模块
|
|||
|
|
|||
|
## 2.模式控制
|
|||
|
|
|||
|
SELinux 有三种工作模式:强制模式(enforcing)、宽容模式(permissive)和关闭模式(disabled)
|
|||
|
|
|||
|
* enforcing:代表 SELinux 运作中,且会执行实际的限制;
|
|||
|
* permissive:代表 SELinux 运作中,但只会记录警告讯息并,不执行实际的限制;
|
|||
|
* disabled:代表 SELinux 不会实际运作。
|
|||
|
|
|||
|
临时设置 SELinux 为 permissive 的方法如下:
|
|||
|
|
|||
|
```bash
|
|||
|
adb root
|
|||
|
adb shell setenforce 0
|
|||
|
```
|
|||
|
|
|||
|
在 Android 系统下,可通过设置 Bootargs 来改变 SELinux 的工作模式,参数、取值范围及说明如下:
|
|||
|
|
|||
|
```ini
|
|||
|
# 设置 SELinux 为强制模式
|
|||
|
androidboot.selinux=enforcing
|
|||
|
# 设置 SELinux 为宽容模式
|
|||
|
androidboot.selinux=permissive
|
|||
|
# 设置 SELinux 为关闭模式
|
|||
|
androidboot.selinux=disabled
|
|||
|
```
|
|||
|
|
|||
|
## 3.TE 文件
|
|||
|
|
|||
|
在 Android 系统中,可在系统源码中,通过 TE 文件设置程序/文件的 SELinux 属性。
|
|||
|
|
|||
|
SELinux 分为文件属性和进程属性(运行属性),文件属性被 file_contexts 使用:
|
|||
|
|
|||
|
```bash
|
|||
|
# file_contexts
|
|||
|
/(vendor|system/vendor)/bin/demo u:object_r:demo_exec:s0
|
|||
|
```
|
|||
|
|
|||
|
可通过 ls -Z 查看谋文件的 SELinux 文件属性,通过 ps -Z 查看谋运行中程序的进程属性,属性非为 4 组,如:
|
|||
|
|
|||
|
```bash
|
|||
|
u:r:init:s0
|
|||
|
```
|
|||
|
|
|||
|
上述的 u 为 Android 的唯一 user(有待确认);第二个参数 r 表示进程,object_r 表示文件;第三个参数是这个进程的 type,在 Android 里面,定义了 100 多个 type;第四个参数 s0 是一个安全等级。
|
|||
|
|
|||
|
在 TE 文件中,我们一般遇到的语法是这样的:
|
|||
|
|
|||
|
```bash
|
|||
|
# rule_name :规则名称,除了有 allow 还有 dontaudit,auditallow 和 neverallow
|
|||
|
# source_type :源类型,主要作用是用来填写一个域(domain)
|
|||
|
# target_type :目标的类型,即安全上下文,SELinux 一个重要的判断对象
|
|||
|
# class :类别,目标(客体)是哪种类别,主要有 File、Dir、Socket、SEAndroid 还有 Binder 等,在这些基础上又细分出设备字符类型(chr_file),链接文件(lnk_file)等。可以通过 ls -l 查看文件类型
|
|||
|
# perm_set :动作集
|
|||
|
rule_name source_type target_type:class perm_set
|
|||
|
```
|
|||
|
|
|||
|
解读为:为 source_type 设置一个 rule_name 的规则,规则是对 target_type 的 class 进行 perm_set 的操作,如:
|
|||
|
|
|||
|
```bash
|
|||
|
# 用中文来表述是:允许 factory 域里的进程或服务对类型为 ttyMT_device 的类别为文件(file)进行 open,read,write,ioctl 操作
|
|||
|
allow factory ttyMT_device:chr_file { read write open ioctl};
|
|||
|
```
|
|||
|
|
|||
|
TE 表达式基本上就是这样,下文将按顺序介绍 rule_name、source_type、target_type、class 和 perm_set。
|
|||
|
|
|||
|
### 3.1.rule_name
|
|||
|
|
|||
|
allow:允许某个进程执行某个动作。
|
|||
|
|
|||
|
auditallow:audit含义就是记录某项操作。默认SELinux只记录那些权限检查失败的操作。 auditallow则使得权限检查成功的操作也被记录。注意,allowaudit只是允许记录,它和赋予权限没关系。赋予权限必须且只能使用allow语句。
|
|||
|
|
|||
|
dontaudit:对那些权限检查失败的操作不做记录。
|
|||
|
|
|||
|
neverallow:没有被allow到的动作默认就不允许执行的。neverallow只是显式地写出某个动作不被允许,如果添加了该动作的allow,则会编译错误。
|
|||
|
|
|||
|
### 3.2.source_type
|
|||
|
|
|||
|
指定一个“域”(domain),一般用于描述进程,该域内的的进程,受该条TE语句的限制。用type关键字,把一个自定义的域与原有的域相关联
|
|||
|
|
|||
|
最简单地定义一个新域的方式为:
|
|||
|
|
|||
|
```bash
|
|||
|
type shell, domain
|
|||
|
```
|
|||
|
|
|||
|
上面这句话的意思是,赋予 shell 给 domain 属性,同时,shell 与属于 domain 这个集合里。如果有一个 allow domain xxxxx 的语句,同样地也给了 shell xxxxx 的属性。
|
|||
|
|
|||
|
### 3.3.target_type
|
|||
|
|
|||
|
指定进程需要操作的客体(文件,文件夹等)类型(安全上下文),同样是用 type 与一些已有的类型,属性相关联
|
|||
|
|
|||
|
以上面的 ttyMT_device 为例:
|
|||
|
|
|||
|
```bash
|
|||
|
# 定义一个类型,属于 dev_type 属性
|
|||
|
type ttyMT_device, dev_type;
|
|||
|
# 属性 dev_type 在 external/sepolicyattributes 的定义如下
|
|||
|
attribute dev_type;
|
|||
|
```
|
|||
|
|
|||
|
attribute 关键字定义一个属性,type 可以与一个或多个属性关联,如
|
|||
|
|
|||
|
```bash
|
|||
|
type usb_device, dev_type, mlstrustedobject;
|
|||
|
```
|
|||
|
|
|||
|
另外,还有一个关键字 typeattribute,type 有两个作用,定义(声明)并关联某个属性。可以把这两个作用分开,type 定义,typeattribute 进行关联
|
|||
|
|
|||
|
```bash
|
|||
|
# 定义 httpd_user_content_t,并关联两个属性
|
|||
|
type httpd_user_content_t, file_type, httpdcontent;
|
|||
|
# 分成两条语句进行表述:
|
|||
|
# 定义 httpd_user_content_t
|
|||
|
type httpd_user_content_t;
|
|||
|
# 关联属性
|
|||
|
typeattribute httpd_user_content_t file_type, httpdcontent;
|
|||
|
```
|
|||
|
|
|||
|
这些类型(安全上下文)会显示地与一个“文件”想关联,如:
|
|||
|
|
|||
|
file_contexts 里面显式定义了哪些文件属于 ttyMT_device 类型,即用 ls -Z 显示出来文件的安全上下文
|
|||
|
|
|||
|
```bash
|
|||
|
/dev/ttyMT.* u:object_r:ttyMT_device:s0
|
|||
|
```
|
|||
|
|
|||
|
虚拟文件系统的标识方式与普通的文件系统文件标识方式不一样,用 genfscon 来配置。
|
|||
|
|
|||
|
```bash
|
|||
|
# genfscon 的语法是:
|
|||
|
genfscon fs_type pathprefix [-file_type] context
|
|||
|
```
|
|||
|
|
|||
|
把 /proc/mtk_demo/demo_file 文件的安全上下文设置成 demo_context:
|
|||
|
|
|||
|
```bash
|
|||
|
genfscon proc /mtk_demo/demo_file u:object_r:demo_context:s0
|
|||
|
```
|
|||
|
|
|||
|
#### 3.3.1.网络对象上下文
|
|||
|
|
|||
|
```bash
|
|||
|
# 例1:定义端口的上下文
|
|||
|
portcon tcp 80 system_u:object_r:http_port_t
|
|||
|
portcon tcp 8080 system_u:object_r:http_port_t
|
|||
|
# 例2:定义网络接口的上下文:
|
|||
|
netifcon eth0 system_u:object_r:netif_eth0_t system_u:object_r:netmsg_eth0_t
|
|||
|
# 例3:定义节点的上下文
|
|||
|
nodecon 10.33.10.66 255.255.255.255 system_u:object_r:node_zeus_t;
|
|||
|
nodecon 10.33.10.0 255.255.255.0 system_u:object_r:node_any_t
|
|||
|
```
|
|||
|
|
|||
|
然后你会有一个疑问,这么多属性,这些属性有什么作用,这些属性会有一个地方显式地说明这个属性拥有什么权限,在 external/sepolicy/domain 里就有非常详细的描述。另个在 external/sepolicy/attributes 里定义了很多属性,下面截取了一些常见的定义。
|
|||
|
|
|||
|
```bash
|
|||
|
# All types used for devices.
|
|||
|
attribute dev_type;
|
|||
|
# All types used for processes.
|
|||
|
attribute domain;
|
|||
|
# All types used for filesystems.
|
|||
|
attribute fs_type;
|
|||
|
# All types used for files that can exist on a labeled fs.
|
|||
|
# Do not use for pseudo file types.
|
|||
|
attribute file_type;
|
|||
|
# All types used for domain entry points.
|
|||
|
attribute exec_type;
|
|||
|
# All types used for property service
|
|||
|
attribute property_type;
|
|||
|
# All service_manager types created by system_server
|
|||
|
attribute system_server_service;
|
|||
|
# All domains that can override MLS restrictions.
|
|||
|
# i.e. processes that can read up and write down.
|
|||
|
attribute mlstrustedsubject;
|
|||
|
# All types that can override MLS restrictions.
|
|||
|
# i.e. files that can be read by lower and written by higher
|
|||
|
attribute mlstrustedobject;
|
|||
|
# All domains used for apps.
|
|||
|
attribute appdomain;
|
|||
|
# All domains used for apps with network access.
|
|||
|
attribute netdomain;
|
|||
|
# All domains used for binder service domains.
|
|||
|
attribute binderservicedomain;
|
|||
|
```
|
|||
|
|
|||
|
### 3.4.class
|
|||
|
|
|||
|
客体的具体类别。用 class 来定义一个客体类别,具体定义方式 如下
|
|||
|
|
|||
|
```bash
|
|||
|
# [external/sepolicy/security_classes示例]
|
|||
|
# file-related classes
|
|||
|
class filesystem
|
|||
|
class file # 代表普通文件
|
|||
|
class dir # 代表目录
|
|||
|
class fd # 代表文件描述符
|
|||
|
class lnk_file # 代表链接文件
|
|||
|
class chr_file # 代表字符设备文件
|
|||
|
......
|
|||
|
# network-related classes
|
|||
|
class socket # socket
|
|||
|
class tcp_socket
|
|||
|
class udp_socket
|
|||
|
......
|
|||
|
class binder # Android 平台特有的 binder
|
|||
|
class zygote # Android 平台特有的 zygote
|
|||
|
```
|
|||
|
|
|||
|
### 3.5.perm_set
|
|||
|
|
|||
|
具体的操作,系统的定义在 external/sepolicy/access_vectors。有两种定义方法。
|
|||
|
|
|||
|
用 common 命令定义:
|
|||
|
|
|||
|
```bash
|
|||
|
# 格式为:
|
|||
|
common common_name { permission_name ... }
|
|||
|
# common 定义的 perm set 能被另外一种 perm set 命令 class 所继承
|
|||
|
# 如:
|
|||
|
common file {
|
|||
|
ioctl read write create getattr setattr lock relabelfrom relabelto
|
|||
|
append unlink link rename execute swapon quotaon mounton
|
|||
|
```
|
|||
|
|
|||
|
用 class 命令定义:
|
|||
|
|
|||
|
```bash
|
|||
|
class class_name [ inherits common_name ] { permission_name ... }
|
|||
|
# inherits 表示继承了某个 common 定义的权限
|
|||
|
# 注意,class 命令它不能被其他 class 继承
|
|||
|
# 继承一个 common,如继承了 file common
|
|||
|
|
|||
|
class dir
|
|||
|
inherits file
|
|||
|
{
|
|||
|
add_name
|
|||
|
remove_name
|
|||
|
reparent
|
|||
|
search
|
|||
|
rmdir
|
|||
|
open
|
|||
|
audit_access
|
|||
|
execmod
|
|||
|
}
|
|||
|
# 不继承任何 common,如
|
|||
|
class binder
|
|||
|
{
|
|||
|
impersonate
|
|||
|
call
|
|||
|
set_context_mgr
|
|||
|
transfer
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
然后是一些特殊的配置文件:
|
|||
|
|
|||
|
```bash
|
|||
|
# 所有定义的 attributes 都在这个文件
|
|||
|
external/sepolicy/attributes
|
|||
|
# 对应了每一个class可以被允许执行的命令
|
|||
|
external/sepolicy/access_vectors
|
|||
|
# Android 中只定义了一个 role,名字就是r,将 r 和 attribute domain 关联起来
|
|||
|
external/sepolicy/roles
|
|||
|
# 其实是将 user 与 roles 进行了关联,设置了 user 的安全级别,s0 为最低级是默认的级别,mls_systemHigh 是最高的级别
|
|||
|
external/sepolicy/users
|
|||
|
# 指的是上文命令中的 class,个人认为这个 class 的内容是指在 android 运行过程中,程序或者系统可能用到的操作的模块
|
|||
|
external/sepolicy/security_classes
|
|||
|
# 系统定义的宏全在 te_macros 文件
|
|||
|
external/sepolicy/te_macros
|
|||
|
# 一些配置的文件,包含了各种运行的规则
|
|||
|
external/sepolicy/***.te
|
|||
|
```
|
|||
|
|
|||
|
### 3.6.TE 的正则表达式和集合
|
|||
|
|
|||
|
TE 文件支持正则表达式,从下面可以看到,通配符是常用的通配符,可以度娘
|
|||
|
|
|||
|
```bash
|
|||
|
/sys/devices/system/cpu(/.*)? u:object_r:sysfs_devices_system_cpu:s0
|
|||
|
/sys/power/wake_lock -- u:object_r:sysfs_wake_lock:s0
|
|||
|
/sys/power/wake_unlock -- u:object_r:sysfs_wake_lock:s0
|
|||
|
/sys/kernel/uevent_helper -- u:object_r:usermodehelper:s0
|
|||
|
/sys/module/lowmemorykiller(/.*)? -- u:object_r:sysfs_lowmemorykiller:s0
|
|||
|
#############################
|
|||
|
# asec containers
|
|||
|
/mnt/asec(/.*)? u:object_r:asec_apk_file:s0
|
|||
|
/mnt/asec/[^/]+/[^/]+\.zip u:object_r:asec_public_file:s0
|
|||
|
```
|
|||
|
|
|||
|
需要注意的是上面的"--",这里的“--”表示二进制文件,类似的还有
|
|||
|
|
|||
|
```bash
|
|||
|
#‘-b’ - Block Device ‘-c’ - Character Device
|
|||
|
#‘-d’ - Directory ‘-p’ - Named Pipe
|
|||
|
#‘-l’ - Symbolic Link ‘-s’ - Socket
|
|||
|
#‘--’ - Ordinary file
|
|||
|
```
|
|||
|
|
|||
|
TE 表达式里可以用“{}”来表示一个集合,如:
|
|||
|
|
|||
|
```bash
|
|||
|
# 允许user_t对bin_t类型的文件和文件夹执行read,getattr操作
|
|||
|
allow user_t bin_t : { file dir } { read getattr };
|
|||
|
# 允许domain对exec_type,sbin_t类型的文件执行execute的动作
|
|||
|
allow domain { exec_type sbin_t } : file execute;
|
|||
|
```
|
|||
|
|
|||
|
可以在集合里使用“*”,“-” 和 “~” 三个通配符
|
|||
|
|
|||
|
```bash
|
|||
|
# 允许user_t对bin_t类型的文件和文件夹执行所有操作
|
|||
|
allow user_t bin_t : { file dir } *;
|
|||
|
# 允许user_t对bin_t类型的文件和文件夹执行除了read,getattr以外的所有操作
|
|||
|
allow user_t bin_t : { file dir } ~{ read getattr };
|
|||
|
# 允许domain对exec_type类型的文件执行execute的动作,除了sbin_t以外
|
|||
|
allow domain { exec_type -sbin_t } : file execute;
|
|||
|
```
|
|||
|
|
|||
|
### 3.7.TE 的类型转换规则
|
|||
|
|
|||
|
为什么要转换类型?
|
|||
|
|
|||
|
init 进程拥有系统的最高权限,如果由 Init 进程 fork,exec 出来的进程默认是与 init 相同的权限,这肯定是不安全的。另一个场景是,由 init 生成的文件,默认也是 init 的读写权限,不方便其他低权限的文件进行访问。
|
|||
|
|
|||
|
类型转换有两种类型转换:
|
|||
|
|
|||
|
1. 主体的域的转换
|
|||
|
2. 客体的转换
|
|||
|
|
|||
|
#### 3.7.1.域的转换
|
|||
|
|
|||
|
type_transition 的完整格式为:
|
|||
|
|
|||
|
```bash
|
|||
|
type_transition source_type target_type : class default_type;
|
|||
|
```
|
|||
|
|
|||
|
举个例子
|
|||
|
|
|||
|
```bash
|
|||
|
type_transition init_t apache_exec_t : process apache_t;
|
|||
|
```
|
|||
|
|
|||
|
init_t 进程执行 type 为 apache_exec_t 的可执行文件时,新的进程转换到 apache_t 域
|
|||
|
|
|||
|
但是上面只是告诉了转换的过程,却没有说明,有转换的权限,如果要上面的转换成功,还需要下面的语句:
|
|||
|
|
|||
|
```bash
|
|||
|
#首先,你得让init_t域中的进程能够执行type为apache_exec_t的文件
|
|||
|
allow init_t apache_exec_t : file execute;
|
|||
|
#然后,你还得告诉SELiux,允许init_t做DT切换以进入apache_t域
|
|||
|
allow init_t apache_t : process transition;
|
|||
|
#最后,你还得告诉SELinux,切换入口(对应为entrypoint权限)为执行pache_exec_t类型的文件
|
|||
|
allow apache_t apache_exec_t : file entrypoint;
|
|||
|
```
|
|||
|
|
|||
|
#### 3.7.2.客体的转换
|
|||
|
|
|||
|
例子:
|
|||
|
|
|||
|
```bash
|
|||
|
type_transition passwd_t tmp_t : file passwd_tmp_t;
|
|||
|
```
|
|||
|
|
|||
|
passwd_t 在 tmp_t 目录下创建文件时,该文件的类型转化为 passwd_tmp_t。这里默认隐含了一个 tmp_t 类型 dir,因为 file 的容器只能是个 dir。同样的,如果要上面的语句运行成功,与需要有相应的权限说明。
|
|||
|
|
|||
|
对应的必须有两个前提条件:
|
|||
|
|
|||
|
* The source domain needs permission to add file entries into the directory(这个 process 必须有在这个目录下添加文件的权限).
|
|||
|
* The source domain needs permission to create file entries(这个 process 必须有在这个目录下创建以这个 Security Context 为 Label 的文件权限).
|
|||
|
|
|||
|
如果每个转换之前都需要这样繁锁地权限声音实在很麻烦。TE里允许把这些相同的,重复使用的语句定义成一个宏,类似于函数一样。
|
|||
|
|
|||
|
### 3.8.TE的宏
|
|||
|
|
|||
|
如果把上面domain转换的例子定义成一个宏,应该定义如下:
|
|||
|
|
|||
|
```bash
|
|||
|
#定义domain_auto_trans宏,$1,$2等等代表宏的第一个,第二个....参数
|
|||
|
define(`domain_auto_trans', `
|
|||
|
# 先allow相关权限,domain_trans宏定义在后面
|
|||
|
domain_trans($1,$2,$3)
|
|||
|
# 然后设置type_transition
|
|||
|
type_transition $1 $2:process $3;
|
|||
|
')
|
|||
|
#定义domain_trans宏。
|
|||
|
define(`domain_trans', `
|
|||
|
# SEAndroid在上述三个最小权限上,还添加了自己的一些权限
|
|||
|
allow $1 $2:file { getattr open read execute };
|
|||
|
allow $1 $3:process transition;
|
|||
|
allow $3 $2:file { entrypoint read execute };
|
|||
|
allow $3 $1:process sigchld;
|
|||
|
dontaudit $1 $3:process noatsecure;
|
|||
|
allow $1 $3:process { siginh rlimitinh };
|
|||
|
')
|
|||
|
```
|
|||
|
|
|||
|
上面的宏定义在 external/sepolicy/te_macros 里。客体的转换定义如下:
|
|||
|
|
|||
|
```bash
|
|||
|
#####################################
|
|||
|
# file_type_auto_trans(domain, dir_type, file_type)
|
|||
|
# Automatically label new files with file_type when
|
|||
|
# they are created by domain in directories labeled dir_type.
|
|||
|
#
|
|||
|
define(`file_type_auto_trans', `
|
|||
|
# Allow the necessary permissions.
|
|||
|
file_type_trans($1, $2, $3)
|
|||
|
# Make the transition occur by default.
|
|||
|
type_transition $1 $2:dir $3;
|
|||
|
type_transition $1 $2:notdevfile_class_set $3;
|
|||
|
')
|
|||
|
|
|||
|
define(`file_type_trans', `
|
|||
|
# Allow the domain to add entries to the directory.
|
|||
|
allow $1 $2:dir ra_dir_perms;
|
|||
|
# Allow the domain to create the file.
|
|||
|
allow $1 $3:notdevfile_class_set create_file_perms;
|
|||
|
allow $1 $3:dir create_dir_perms;
|
|||
|
')
|
|||
|
```
|
|||
|
|
|||
|
TE 的集合也可以定义成一个宏代替,如读写文件操作集的宏:
|
|||
|
|
|||
|
```bash
|
|||
|
define(`x_file_perms', `{ getattr execute execute_no_trans }')
|
|||
|
define(`r_file_perms', `{ getattr open read ioctl lock }')
|
|||
|
define(`w_file_perms', `{ open append write }')
|
|||
|
define(`rx_file_perms', `{ r_file_perms x_file_perms }')
|
|||
|
define(`ra_file_perms', `{ r_file_perms append }')
|
|||
|
define(`rw_file_perms', `{ r_file_perms w_file_perms }')
|
|||
|
define(`rwx_file_perms', `{ rw_file_perms x_file_perms }')
|
|||
|
define(`create_file_perms', `{ create rename setattr unlink rw_file_perms }')
|
|||
|
```
|
|||
|
|
|||
|
使用方式是:
|
|||
|
|
|||
|
```bash
|
|||
|
allow demo demo_device:chr_file rw_file_perms;
|
|||
|
```
|