本文介绍了 SELinux 策略是如何构建的。 SELinux 策略是通过核心 AOSP 策略(平台)和设备特定策略(供应商)的组合构建的。 Android 4.4 到 Android 7.0 的 SELinux 策略构建流程合并了所有 sepolicy 片段,然后在根目录中生成整体文件。这意味着每次修改策略时,SoC 供应商和 ODM 制造商都会修改boot.img
(对于非 A/B 设备)或system.img
(对于 A/B 设备)。
在 Android 8.0 及更高版本中,平台和供应商策略是单独构建的。 SOC 和 OEM 可以更新其部分策略、构建其映像(例如, vendor.img
和boot.img
),然后独立于平台更新来更新这些映像。
然而,由于模块化的 SELinux 策略文件存储在/vendor
分区上,因此init
进程必须提前挂载系统和供应商分区,以便它可以从这些分区读取 SELinux 文件并将它们与系统目录中的核心 SELinux 文件合并(然后将它们加载到内核)。
源文件
构建 SELinux 的逻辑位于以下文件中:
-
external/selinux
:外部 SELinux 项目,用于构建 HOST 命令行实用程序来编译 SELinux 策略和标签。-
external/selinux/libselinux
:Android 仅使用外部libselinux
项目的子集以及一些特定于 Android 的自定义。有关详细信息,请参阅external/selinux/README.android
。 -
external/selinux/libsepol
: -
external/selinux/checkpolicy
:SELinux 策略编译器(主机可执行文件:checkpolicy
、checkmodule
和dispol
)。取决于libsepol
。
-
-
system/sepolicy
:核心 Android SELinux 策略配置,包括上下文和策略文件。主要的sepolicy构建逻辑也在这里(system/sepolicy/Android.mk
)。
有关system/sepolicy
Implementing SELinux中文件的更多详细信息。
Android 7.0 及更早版本
本节介绍如何在 Android 7.x 及更早版本中构建 SELinux 策略。
制定 SELinux 政策
SELinux 策略是通过将核心 AOSP 策略与设备特定的自定义相结合来创建的。然后,组合的策略被传递到策略编译器和各种检查器。设备特定的自定义是通过设备特定的Boardconfig.mk
文件中定义的BOARD_SEPOLICY_DIRS
变量完成的。此全局构建变量包含一个目录列表,用于指定搜索其他策略文件的顺序。
例如,SoC 供应商和 ODM 可能各自添加一个目录,一个用于 SoC 特定设置,另一个用于设备特定设置,以生成给定设备的最终 SELinux 配置:
-
BOARD_SEPOLICY_DIRS += device/ SOC /common/sepolicy
-
BOARD_SEPOLICY_DIRS += device/ SoC / DEVICE /sepolicy
system/sepolicy
和BOARD_SEPOLICY_DIRS
中的 file_contexts 文件的内容串联起来在设备上生成file_contexts.bin
:
sepolicy
文件由多个源文件组成:
- 纯文本
policy.conf
是通过按顺序连接security_classes
、initial_sids
、*.te
文件、genfs_contexts
和port_contexts
生成的。 - 对于每个文件(例如
security_classes
),其内容是system/sepolicy/
和BOARDS_SEPOLICY_DIRS
下同名文件的串联。 - 将
policy.conf
发送到SELinux编译器进行语法检查,并编译成二进制格式作为设备上的sepolicy
。
SELinux 文件
编译后,运行 7.x 及更早版本的 Android 设备通常包含以下 SELinux 相关文件:
-
selinux_version
- sepolicy:组合策略文件后的二进制输出(例如
security_classes
、initial_sids
和*.te
) -
file_contexts
-
property_contexts
-
seapp_contexts
-
service_contexts
-
system/etc/mac_permissions.xml
有关更多详细信息,请参阅实施 SELinux 。
SELinux 初始化
当系统启动时,SELinux 处于宽容模式(而不是强制模式)。 init 进程执行以下任务:
- 通过
/sys/fs/selinux/load
将sepolicy
文件从 ramdisk 加载到内核中。 - 将 SELinux 切换到强制模式。
- 运行
re-exec()
以将 SELinux 域规则应用于自身。
为了缩短启动时间,请尽快对init
进程执行re-exec()
。
安卓 8.0 及更高版本
在 Android 8.0 中,SELinux 策略分为平台和供应商组件,以允许独立的平台/供应商策略更新,同时保持兼容性。
平台 sepolicy 进一步分为平台私有部分和平台公共部分,以将特定类型和属性导出给供应商策略编写者。平台公共类型/属性保证作为给定平台版本的稳定 API 进行维护。使用平台映射文件可以保证多个版本与先前平台公共类型/属性的兼容性。
平台公共政策
平台 public sepolicy 包括system/sepolicy/public
下定义的所有内容。平台可以假定公共政策下定义的类型和属性是给定平台版本的稳定 API。这构成了由平台导出的 sepolicy 的一部分,供应商(即设备)策略开发人员可以在该平台上编写其他特定于设备的策略。
类型根据写入供应商文件的策略版本进行版本控制,由PLATFORM_SEPOLICY_VERSION
构建变量定义。然后,版本化的公共策略包含在供应商策略中并(以其原始形式)包含在平台策略中。因此,最终策略包括私有平台策略、当前平台的公共策略、设备特定策略以及与编写设备策略所针对的平台版本相对应的版本化公共策略。
平台隐私政策
平台私有 sepolicy 包括/system/sepolicy/private
下定义的所有内容。这部分策略形成平台功能所需的仅限平台的类型、权限和属性。这些不会导出到vendor/device
策略编写者。非平台策略编写者不得根据平台私有 sepolicy 中定义的类型/属性/规则编写策略扩展。此外,这些规则可以作为仅框架更新的一部分进行修改或可能消失。
平台私有映射
平台私有映射包括将先前平台版本的平台公共策略中公开的属性映射到当前平台公共sepolicy中使用的具体类型的策略语句。这可确保基于先前平台公共 sepolicy 版本的平台公共属性编写的供应商策略继续有效。版本控制基于 AOSP 中为给定平台版本设置的PLATFORM_SEPOLICY_VERSION
构建变量。每个以前的平台版本都存在一个单独的映射文件,该平台预计会接受供应商策略。有关更多详细信息,请参阅兼容性。
Android 11 及更高版本
system_ext 和产品 sepolicy
在Android 11中,添加了system_ext策略和产品策略。与平台sepolicy一样,system_ext策略和产品策略分为公共策略和私有策略。
公共政策被输出给供应商。类型和属性成为稳定的API,供应商策略可以引用公共策略中的类型和属性。类型根据PLATFORM_SEPOLICY_VERSION
进行版本控制,并且版本控制策略包含在供应商策略中。原始策略包含在每个 system_ext 和产品分区中。
私有策略包含 system_ext 和产品分区功能所需的仅限 system_ext 和仅限产品的类型、权限和属性。私人政策对供应商来说是不可见的,这意味着这些规则是内部的并且允许修改。
system_ext 和产品映射
system_ext 和 Product 可以将其指定的公共类型导出到供应商。然而,保持兼容性的责任在于每个合作伙伴自己。为了兼容性,合作伙伴可以提供自己的映射文件,将以前版本的版本属性映射到当前公共 sepolicy 中使用的具体类型。
- 要安装 system_ext 的映射文件,请将包含所需映射信息的 cil 文件放置到
{SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil
,然后将system_ext_{ver}.cil
添加到PRODUCT_PACKAGES
。 - 要安装产品的映射文件,请将包含所需映射信息的 cil 文件放置到
{PRODUCT_PRIVATE_SEPOLICY_DIRS}/compat/{ver}/{ver}.cil
,然后将product_{ver}.cil
添加到PRODUCT_PACKAGES
。 参考添加红牛设备产品分区映射文件的示例。 - 将策略转换为 SELinux 通用中间语言 (CIL) 格式,具体来说:
- 公共平台政策(system + system_ext + 产品)
- 私人+公共政策相结合
- 公共 + 供应商和
BOARD_SEPOLICY_DIRS
政策
- 对公众提供的策略进行版本控制,作为供应商策略的一部分。通过使用生成的公共 CIL 策略来通知组合的公共 + 供应商 +
BOARD_SEPOLICY_DIRS
策略来完成哪些部分必须转换为将链接到平台策略的属性。 - 创建链接平台和供应商部件的映射文件。最初,这只是将公共策略中的类型与供应商策略中的相应属性链接起来;稍后,它还将为未来平台版本中维护的文件提供基础,从而实现与针对该平台版本的供应商策略的兼容性。
- 组合策略文件(描述设备上和预编译的解决方案)。
- 结合映射、平台和供应商政策。
- 编译输出二进制策略文件。
-
/system/etc/selinux/plat_sepolicy_and_mapping.sha256
和/{partition}/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256
均存在且相同。 -
/system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256
和/{partition}/etc/selinux/precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256
都不存在。或者两者都存在并且相同。 -
/product/etc/selinux/product_sepolicy_and_mapping.sha256
和/{partition}/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256
都不存在。或者两者都存在并且相同。
制定 SELinux 政策
Android 8.0 中的 SELinux 策略是通过组合/system
和/vendor
部分制定的。适当设置的逻辑位于/platform/system/sepolicy/Android.mk
中。
策略存在于以下位置:
地点 | 包含 |
---|---|
system/sepolicy/public | 平台的sepolicy API |
system/sepolicy/private | 平台实现细节(厂商可以忽略) |
system/sepolicy/vendor | 供应商可以使用的策略和上下文文件(如果需要,供应商可以忽略) |
BOARD_SEPOLICY_DIRS | 供应商安全政策 |
BOARD_ODM_SEPOLICY_DIRS (Android 9 及更高版本) | 奥德姆安全政策 |
SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS (Android 11 及更高版本) | System_ext的sepolicy API |
SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS (Android 11 及更高版本) | System_ext实现细节(厂商可以忽略) |
PRODUCT_PUBLIC_SEPOLICY_DIRS (Android 11 及更高版本) | 产品的sepolicy API |
PRODUCT_PRIVATE_SEPOLICY_DIRS (Android 11 及更高版本) | 产品实现细节(厂商可以忽略) |
构建系统采用此策略并在相应的分区上生成 system、system_ext、product、vendor 和 odm 策略组件。步骤包括:
预编译 SELinux 策略
在init
打开SELinux之前, init
会从分区( system
、 system_ext
、 product
、 vendor
和odm
)收集所有CIL文件,并将它们编译成二进制策略,即可以加载到内核的格式。由于编译需要时间(通常为 1-2 秒),因此 CIL 文件在构建时进行预编译,并与 sha256 哈希值一起放置在/vendor/etc/selinux/precompiled_sepolicy
或/odm/etc/selinux/precompiled_sepolicy
输入 CIL 文件的数量。在运行时, init
通过比较哈希值来检查是否有任何策略文件已更新。如果没有任何变化, init
将加载预编译策略。如果没有, init
会动态编译并使用它而不是预编译的。
更具体地说,如果满足以下所有条件,则使用预编译策略。这里, {partition}
表示预编译策略所在的分区: vendor
或odm
。
如果其中任何一个不同, init
就会回退到设备上的编译路径。有关详细信息,请参阅system/core/init/selinux.cpp
。