1. SELinux的基础原则
默认拒绝原则 - 任何未经明确允许的行为都会被拒绝(即:白名单制)
2. SELinux的两种执行模式
宽容模式 - 权限拒绝事件会被记录下来,但不会被强制执行。(权限不够时,仅警告)
强制模式 - 权限拒绝事件会被记录下来并强制执行。(权限不够时,拒绝执行)
3. SELinux在安卓平台上的演变
低于安卓4.3 - 默认不支持SELinux
安卓4.3 - 宽容模式
安卓4.4 - 部分强制模式(多数设备依然是宽容模式)
安卓5.1 - 默认强制模式
高于安卓8.0 - 强制模式且Sepolicy规则被分成多个部分
4. 核心规则
路径:system/sepolicy
核心规则会被所有设备使用。
5. 设备规则
路径:device/<vendor>/<board>/sepolicy
设备规则会被对应的产品使用。
6. 添加规则目录
在Android.mk中设置BOARD_SEPOLICY_DIRS可以添加Sepolicy的搜寻目录,如:
BOARD_SEPOLICY_DIRS += device/samsung/tuna/sepolicy
7. 关于多部分规则
从安卓8.0开始,sepolicy规则被分成了多个部分。
笔者个人认为:是进行了可移植性改造,及多版本兼容,因此将规则分散到了多个目录中以增强其可移植性,及兼容性。
public - PLAT_PUBLIC_POLICY,平台公开规则,会被导出给其他非平台相关的规则。
private - PLAT_PRIVATE_POLICY,平台私有规则,不会向vendor部分暴露。
vendor - PLAT_VENDOR_POLICY,厂商规则,可引用public的规则,不能引用private的规则。
mapping - 规则映射表,将旧版本的public规则映射到当前规则中,来保证旧版本可用,如xxx.cil文件。
8. Sepolicy编译过程
1) 将所有规则转换成CIL
- private + public platform policy 转换到CIL
- mapping文件转储到CIL
- non-platform public policy 转换到CIL
- non-platform public policy + private policy 转换到CIL
2) 属性化规则
3) 合并规则文件
- 合并 mapping,platform 及 non-platform 规则
- 合并输出二进制规则文件
9. Sepolicy的编译目标
selinux_policy
10. Sepolicy写法实操
10.1 重要文件:
te_macros - 相当于宏定义,定义了一些语句的组合,如:init_daemon_domain
#####################################
# init_daemon_domain(domain)
# Set up a transition from init to the daemon domain
# upon executing its binary.
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
tmpfs_domain($1)
')
attributes - 定义了所有的属性,相当于类型定义,如:exec_type
# All types used for files that can exist on a labeled fs.
# Do not use for pseudo file types.
# On change, update CHECK_FC_ASSERT_ATTRS
# definition in tools/checkfc.c.
attribute file_type;
# All types used for domain entry points.
attribute exec_type;
global_macros - 相当于宏定义,将一些对象及权限的组合定义成一组,如:
define(`devfile_class_set', `{ chr_file blk_file }')
define(`r_file_perms', `{ getattr open read ioctl lock map }')
define(`w_file_perms', `{ open append write lock map }')
define(`rw_file_perms', `{ r_file_perms w_file_perms }')
file_contexts - 为指定路径的目录或文件设置其type,如:
/dev/enginectrl u:object_r:enginectrl_device:s0
/storage(/.*)? u:object_r:storage_file:s0
file.te - 文件type名在这里定义,并制定type所属的属性,如:
type storage_file, file_type;
type logcat_exec, exec_type, file_type;
笔者备注:属性相当于一个组如“file_type”,type是最小权限单位,不同type的东西可以在同一个属性下面,如上的storage_file和logcat_exec这两个type都同属于file_type属性,因此对于有些针对file_type的规则就能同时限制到这两个type。
xxx.te - 针对xxx这个type的权限定义,包含了type定义以及这个type的权限配置,以atcid.te为例:
type atcid, domain; # 定义type:atcid,指定其属于domain
type atcid_exec, exec_type, file_type, vendor_file_type;
#...
# 配置允许atcid访问ttyGS_device的chr_file:read/write/ioctl/open权限
allow atcid ttyGS_device:chr_file { read write ioctl open };
#...
# 配置允许atcid访问所有的mtk_atci_prop类属性
set_prop(atcid, mtk_atci_prop);
#...
property.te - 这个文件里定义了property属性的type,以及type所属的属性:
type persist_service_atci_prop, property_type, mtk_core_property_type;
type mtk_atci_prop, property_type, mtk_core_property_type;
property_contexts - 这个文件里规定了各个property的type:
persist.vendor.service.atci u:object_r:persist_service_atci_prop:s0
vendor.mtk.atci u:object_r:mtk_atci_prop:s0
10.2 类型定义:
进程、资源,都被抽象成类型了。
type 类型名 [alias 别名集] [,属性集];
一个简单的实例:
type rootfs, fs_type;
此例中定义了一个名为rootfs的类型,这个类型属于fs_type属性(笔者认为,将这里的attribute翻译为“属性组”更为贴切)。
可以将多个类型指定到同一属性组,这样配置权限时就可以针对一组属性来设置权限,而不必精确的去针对每个类型设置权限。
除了在定义类型的时候关联属性,也可以用typeattribute来设置类型的属性。
10.3 属性定义:
attribute 属性名;
实例:
# All types used for filesystems.
# On change, update CHECK_FC_ASSERT_ATTRS
# definition in tools/checkfc.c.
attribute fs_type;
此例定义了一个名为fs_type的属性组。
10.4 访问向量(Access Vector):
访问规则名 源类型 目标类型 : 权限类 权限集;
用来描述主体(源)对客体(目标)的访问规则
示例:
allow atcid ttyGS_device:chr_file { read write ioctl open };
10.4.1 访问规则名
通常有4种:
allow - 允许主体对客体执行许可的操作。
neverallow - 表示不允许主体对客体执行制定的操作。
auditallow - 表示允许操作并记录访问决策信息。
dontaudit - 表示不记录违反规则的决策信息,切违反规则不影响运行。
10.4.2 源类型和目标类型
是由type定义的,分散在各个te文件中,如:
type platform_app, domain;
这个是定义在platform_app.te中的
10.4.3 权限类
是由class所定义的权限类,如access_vectors文件中定义的:
class service_manager { add find list }
10.4.4 权限集
指定此条规则的权限范围,权限集必须是权限类所支持权限的子集,如:
allow platform_app recovery_service:service_manager find;
这条规则的意思:允许platform_app访问recovery_service的service_manager:find权限。
更直白的意思是:让platform_app可以找到recovery_service。
后话:
type 是起名,比如小明,小红。
attribute 是属性组,比如:人类,男性,女性,有驾照。
权限类是特定场景的权限,比如:洗浴,驾驶
权限集是针对某场景的各种可能的限制,如:洗浴这个场景,权限有:前往大门,交费,进入男浴室,进入女浴室
然后我们可以这样定义一个权限规则来定义小明与小红的权限:
# 下面定义了此系统中的属性
attribute 人类;
attribute 男性;
attribute 女性;
attribute 有驾照;
attribute 洗浴中心;
attribute 机动车;
# 下面定义了此系统中的type(权限对象)
type 小红, 女性, 人类;
type 小明, 有驾照, 男性, 人类;
type 大浪淘沙澡堂, 洗浴中心;
type 本田缤智, 机动车;
# 下面定义了此系统中的权限类
class 洗浴 { 前往大门, 交费, 进入男浴室, 进入女浴室 }
class 驾乘 { 开车门, 驾驶, 乘坐 }
############################################
# 下面定义了小明和小红在此系统中的权限
############################################
# 小红不能进男浴室
allow 小红 大浪淘沙澡堂:洗浴 {前往大门, 交费, 进入女浴室};
# 小红没有驾照不能开车
allow 小红 本田缤智:驾乘 {开车门, 乘坐};
# 小明不能进女浴室
allow 小明 大浪淘沙澡堂:洗浴 {前往大门, 交费, 进入男浴室};
# 小明有驾照可以开车
allow 小明 本田缤智:驾乘 {开车门, 驾驶, 乘坐};
# 禁止所有没有驾照的人驾驶机动车
neverallow {人类 -有驾照} {机动车}:驾乘 {驾驶};
参考材料:
[1] system\sepolicy\README
[2] system\sepolicy\Android.mk
[3] https://www.jianshu.com/p/e95cd0c17adc
[4] https://blog.youkuaiyun.com/kongbaidepao/article/details/61416862
[5] https://www.jianshu.com/p/72061c66a176
[6] https://source.android.com/security/selinux/concepts