SELinux 通过严格的访问控制机制增强了 Linux 系统的安全性。它通过标签和安全策略来控制进程和文件的访问权限,从而保护系统免受未经授权的访问和攻击。
一、策略介绍
1、主要组件
- 安全标签(Security Labels):每个文件、目录、进程等都有一个安全标签。标签包含类型(Type)、角色(Role)、用户(User)和类别(Category)等信息。
- 安全策略(Security Policies):SELinux 支持多种安全策略,包括:
1)Targeted Policy:针对特定类型的系统(如服务器、桌面系统)。
2)Strict Policy:更严格的策略,适用于高度安全的环境。
3)MLS Policy:多级安全策略,支持多级分类的安全需求。
- 安全上下文(Security Context):安全上下文包含标签信息,用于访问控制决策。例如:u:object_r:some_type:s0。
标签概念
SELinux 其实就是一个标签系统。每个进程都有一个 Label(称为 Process Label),每个文件系统所涵盖的文件/目录、网络端口、设备等对象也有一个 Lable(称为 Object Label)。SeLinux通过编写规则来控制一个 Process Label 对一个 Object Label 的访问,这个规则称之为策略(Policy)。SeLinux 的这种安全机制称为 Mandatory Access Control(MAC),是在内核层实现的。
安全上下文
SELinux 给 Linux 的所有对象都分配⼀个安全上下⽂(也称为标签 Label), 描述成⼀个 标准的字符串,例如 u:r:untrusted_app:s0 。安全上下⽂的格式为: user:role:type:sensitivity[:categories] 。可以通过 file_contexts 或运⾏ ls -Z 查看安全上下⽂。
Android 并不会使⽤ SELinux 提供的所有功能,通常可以忽略上下⽂的 user 、role 和 sensitivity 字段:
- 不使⽤ SELinux ⽤⼾。唯⼀定义的⽤⼾是 u 。
- 不使⽤ SELinux ⻆⾊和基于⻆⾊的访问权限控制(RBAC)。定义并使⽤了两个默认⻆⾊:r(适⽤于主题,进程)和 object_r(适⽤于对象,⽂件)。
- 不使⽤ SELinux 敏感度。已始终设置好默认的 s0 敏感度。
- MAC 的基础管理思路基于 Type Enforcement Access Control (简称 TEAC,⼀般⽤ TE 表⽰)
- 进程的安全上下⽂的类型称为 Domain ,⽂件的安全上下⽂中的类型称为 Type 。
通过 adb shell ps -Z 查看进程的 secontext,可以通过 grep 查看指定进程的 secontext。通过 ls -Z 查看⽂件的 secontext。
2、访问控制机制
- 主体(Subject):主体通常是进程或用户。主体具有一个安全标签,用于标识其权限。
- 客体(Object):客体通常是文件、目录或其他资源。客体也有一个安全标签,用于标识其访问控制信息。
- 访问控制决策:SELinux 根据主体和客体的安全标签来决定是否允许某个操作。如果主体的安全标签允许访问客体的安全标签,则操作被允许;否则,操作被拒绝。
SELinux 中的访问控制,就是判定一个 Source 有没有权限去访问 Target。这里的 Source 一般就是进程,Target 最长见的就是文件系统(比如文件、目录、socket、设备等等),当然还有其他类型的 Target。换句话说,SeLinux 的机制就是通过读取一个“规则”,来控制一个进程有没有权限去访问一个文件(或其他类型)
上面说的“规则”,在 SELinux 里的术语叫做 Policy(策略)或叫 Access Vector Rule。是可以由 AOSP 和厂商、供应商来编写的。上面的 Source,还叫做 Subject(主体),上面的 Target,还叫做 Object(对象或客体)。Label、Source、Target、Subject 和 Object,这些都不重要, 在实际语法中并没有相关关键词,只要各种资料里出现这些词的时候知道其所指就可以。
3、主要功能
- 进程隔离:SELinux 可以隔离不同进程,确保它们之间不会相互干扰或攻击。
- 文件访问控制:SELinux 可以精细控制文件和目录的访问权限,防止未经授权的访问。
- 网络访问控制:SELinux 可以控制网络端口和服务的访问权限,防止未经授权的网络通信。
- 审计和日志记录:SELinux 记录所有违反安全策略的操作,便于安全审计和问题排查。
设计
SELinux 在 Android 4~7 和 Android 8 以后采用了不同的设计,Android 4~7 上,SELinux 的策略是作为一个整体来编译和更新的。Android 8 及以后,SELinux 采用了模块化、动态化设计,Platform(可以理解为 AOSP 的部分)、Non-Platform(vendor、odm、oem 的部分,这里总体称为 vendor 部分)的 SELinux 策略分别独立编译、升级。
设备架构图
编译后会生成对应的 img 文件:
- system.img:主要包含了 Android 框架层的文件系统,包括各种应用程序框架和服务,如 Activity Manager、Window Manager 等。
- boot.img:是一个特殊的映像文件,包含了 Linux 内核以及针对 Android 进行优化的补丁集。它是设备启动过程中的关键组成部分。
- vendor.img:存储了与特定 SoC(System on a Chip)相关的代码和配置信息,比如驱动程序等。
- odm.img:包含了设备制造商提供的特定于设备的代码和配置,例如针对不同硬件特性的优化。
- oem.img:包含了 OEM(Original Equipment Manufacturer)或运营商定制的内容,如预装的应用程序、特定的服务等。
- bootloader:是引导加载程序,负责初始化硬件设备、建立内存空间的映射图,为最终调用操作系统内核做准备。
- radio:通常指的是基带处理器软件,负责处理无线通信的部分,这部分通常是厂商专有的实现。
Android 8以后,SeLinux 的策略文件可以伴随相应的 img 独立编译或者 OTA。
二、SEPolicy策略
SEPolicy 是 SELinux 和 SEAndroid 中的安全增强策略的简称。SEPolicy 是 SELinux 系统的核心部分之一,它定义了系统中的安全策略,决定了各个进程、文件、网络端口等资源的访问控制规则。
1、核心策略
在 SELinux 和 SEAndroid 的上下文中,核心策略(Core Policy)是指那些定义了系统基本安全规则的文件集合。这些规则被设计成通用的,以便能够在不同的设备和配置上运行,同时保证一定的安全标准。核心策略通常位于 /system/sepolicy/ 目录下,并且这些规则会被所有基于 SELinux 或 SEAndroid 的设备所使用。
核心策略组成
- policy.conf:主策略文件。这是主要的 SELinux 策略文件,包含了大部分的安全规则。
- types.conf:类型定义。定义了系统中各类对象的类型标签。
- file_contexts:文件上下文。定义了文件系统的路径和其对应的安全上下文。
- port_contexts:端口上下文。定义了网络端口的安全上下文。
- initial_sid.conf:定义了初始安全标识符(SID)。
- users.conf:定义了用户标签。
- roles.conf:定义了角色标签。
- booleans.conf:定义了布尔类型的安全策略变量。
在实际的 SELinux 系统中,policy.conf 等文件可能并不直接存在,而是被拆分成多个文件和模块化的规则集。这是因为 SELinux 的策略文件结构已经演进,变得更加模块化和易于管理。
多模块策略
从安卓8.0开始,sepolicy 策略被分成了多个部分。google 进⾏了可移植性改造,以及多版本兼容,因此将策略⽂件分散到了多个⽬录中,以增强其可移植性及兼容性。
- public - PLAT_PUBLIC_POLICY,平台公开策略,会被导出给其他⾮平台相关的策略。
- private - PLAT_PRIVATE_POLICY,平台私有策略,不会向vendor部分暴露。
- vendor - PLAT_VENDOR_POLICY,⼚商策略,可引⽤public的策略,不能引⽤private的策略。
- mapping - 策略映射表,将旧版本的public策略映射到当前策略中,来保证旧版本可⽤,如xxx.cil ⽂件。
PLAT_PUBLIC_POLICY
平台共有策略全部定义在 /system/sepolicy/public 下, public 下的 type 和 attribute 可以被 nonplatform 中的策略所使⽤,也就是说,设备⼚商的 sepolicy 开发者在 non-platform 下可以对 platform public sepolicy 的策略进⾏扩展。
PLAT_PRIVATE_POLICY
与公有策略相反,被声明为私有策略的 type 或 attribute 对 non-platform 的策略开发者是不可⻅的。以 /system/sepolicy/private/ ⽬录下的 atrace.te 为例。
- system/sepolicy/private/file_contexts 有定义 /system/bin/atrace u:object_r:atrace_exec:s0。
- system/sepolicy/private/atrace.te 有定义 atrace 相关的规则。
- 在 device/qcom/sepolicy/common ⽬录下新增⼀个 atrace.te ⽂件,并添加规则 allow atrace sdcardfs:file read。
- 当执行 make sepolicy 进行编译时会失败,提示"device/qcom/sepolicy/common/atrace.te:2:ERROR 'unknown type atrace' at token ';' on line 23355",也就是说 private 策略中的 type 和 attribute 对我们是不可见的。
但是 scontext 只有平台和⾮平台之分,也就是说,定义在平台 private 下⾯ file_contexts 属性, public 和⾮平台的也可以共享。
2、自定义策略
通常情况下,SEPolicy 策略会根据厂商或产品的不同,定制不同的 SELinux 策略,一般在 device/<vendor>/<board>/sepolicy 或 device/<vendor>/sepolicy 路径下添加和管理 SELinux 策略文件,也可能在 /device/{硬件平台}/{产品}/sepolicy/ 路径下。
这里在对应路径下会创建 private、public 和 vendor 等文件夹,而文件夹下会添加很多 SELinux 策略文件(.te ⽂件)来描述进程对资源的访问许可,这里的设备规则会被对应的产品使⽤。
应⽤添加策略
除了在 device ⽬录中添加 SELinux 策略,我们也可以在应⽤⽬录下添加。
源码位置:/packages/services/Car/car_product/build/car.mk
BOARD_SEPOLICY_DIRS += packages/services/Car/car_product/sepolicy/test
这里同样创建 private、public 和 vendor 等文件夹,并添加对应的 te 文件。
3、te策略文件
假设你在 device/<vendor>/<board>/sepolicy/private 目录中添加了一个名为 example.te 的策略文件:
# example.te# 定义一个新的类型
type example_t;# 允许某个进程访问特定文件
allow example_t data_file:file read;
这里我们先来了解两个关键字 type 和 allow。
- type 关键字:用于定义一个新的 SELinux 类型(type)。example_t 是一个新的类型名称,表示一种新的安全上下文。
- allow 关键字:用于定义一条允许规则,指定某种类型的主体(subject)可以执行某种操作。
- example_t:是前面定义的类型,表示某个进程或实体。
- data_file 是一个对象类(class)或类型,表示某种类型的文件。
- file 是对象类的一个实例,表示普通文件。
- read 是一个权限标志,表示读取操作。
所以,综合来看定义了一个新的 SELinux 类型 example_t。这意味着你可以将进程或其他实体标记为此类型。定义了一条允许规则,使得类型为 example_t 的进程或实体可以对类型为 data_file 的文件执行读取操作。
示例应用
假设有一个进程 example_process 被标记为 example_t 类型,并且有一个文件 example_data 被标记为 data_file 类型。那么这条规则允许 example_process 读取 example_data 文件。
进程安全上下文
将某个进程的安全上下文设置为 example_t:
chcon u:object_r:example_t:s0 /path/to/example_process
文件安全上下文
将某个文件的安全上下文设置为 data_file:
chcon u:object_r:data_file:s0 /path/to/example_data
通过这种方式,你可以精确控制进程对文件的访问权限,增强系统的安全性。
4、添加策略目录
在自定义路径下添加完策略文件,需要在对应目录的 mk 文件中添加 BOARD_SEPOLICY_DIRS 变量,这个变量用于指定 SELinux 策略文件的搜索路径。
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := sepolicy
LOCAL_MODULE_TAGS := optional# 添加策略文件的搜索路径
BOARD_SEPOLICY_DIRS += \device/<vendor>/<board>/sepolicy/private \device/<vendor>/<board>/sepolicy/public \device/<vendor>/<board>/sepolicy/vendorinclude $(BUILD_PHONY_PACKAGE)
- LOCAL_PATH:设置当前路径为 $(call my-dir),即 device/<vendor>/<board>/sepolicy 或 device/<vendor>/sepolicy 目录。
- BOARD_SEPOLICY_DIRS:这个变量用于指定 SELinux 策略文件的搜索路径。你可以添加多个路径,每个路径之间用空格分隔。
5、编译过程
在修改完 Android.mk 文件并添加策略文件后,需要重新编译整个系统。SELinux 策略的编译过程涉及多个步骤,包括将各种策略文件转换为 CIL(Common Intermediate Language)格式,然后进行属性化和规则合并。下面是详细的编译过程:
将所有规则转换成CIL
- 将私有策略(private)和公共平台策略(public platform)文件转换为 CIL
- 将映射文件(mapping)转换为 CIL。
- 将非平台公共策略(non-platform public)文件转换为 CIL。
- 将非平台公共策略与私有策略合并后转换为 CIL。
属性化规则
在将所有策略文件转换为 CIL 之后,需要对规则进行属性化处理。这一步主要是为了确保规则的完整性和一致性。
合并规则⽂件
- 将映射文件(mapping)、公共平台策略(platform)和非平台公共策略(non-platform)的规则合并到最终的 CIL 文件中。
- 将合并后的规则文件转换为二进制格式,以便在系统中使用。
通过这些步骤,可以确保 SELinux 策略文件被正确地编译和合并,从而在系统中生效。