本文介绍了 Android 如何处理平台 OTA 的政策兼容性问题,在平台 OTA 中,新的平台 SELinux 设置可能与旧的供应商 SELinux 设置不同。
基于 Treble 的 SELinux 政策设计考虑了平台政策和供应商政策之间的二元区分;如果供应商分区生成依赖项(例如 platform
< vendor
< oem
),则该方案会变得更加复杂。
在 Android 8.0 及更高版本中,SELinux 全局政策分为私有组件和公共组件。公共组件包括政策和相关基础架构,这些政策和基础架构保证可用于平台版本。此政策将向供应商政策编写者公开,使供应商能够构建供应商政策文件,该文件在与平台提供的政策结合使用时,将为设备生成功能齐全的政策。
- 对于版本控制,导出的平台公共政策将编写为属性。
- 为了便于政策编写,导出的类型将在政策构建过程中转换为版本化属性。公共类型也可以直接用于供应商上下文文件提供的标签决策中。
Android 维护平台政策中导出的具体类型与每个平台版本的相应版本化属性之间的映射。 这可确保当对象标有类型时,不会破坏先前版本中平台公共政策保证的行为。此映射通过为每个平台版本保持最新的映射文件来维护,该文件保留公共政策中导出的每种类型的属性成员资格信息。
对象所有权和标签
在 Android 8.0 及更高版本中自定义政策时,必须为每个对象明确定义所有权,以保持平台政策和供应商政策的分离。例如,如果供应商标记 /dev/foo
,而平台在后续 OTA 中标记 /dev/foo
,则会出现未定义的行为。对于 SELinux,这表现为标签冲突。设备节点只能有一个标签,该标签解析为最后应用的标签。因此:
- 需要访问未成功应用的标签的进程将失去对资源的访问权限。
- 获得对文件访问权限的进程可能会中断,因为创建了错误的设备节点。
系统属性也可能发生命名冲突,这可能会导致系统出现未定义的行为(以及 SELinux 标签问题)。平台标签和供应商标签之间的冲突可能会发生在具有 SELinux 标签的任何对象上,包括属性、服务、进程、文件和套接字。为避免这些问题,请明确定义这些对象的所有权。
除了标签冲突外,SELinux 类型/属性名称也可能冲突。类型/属性名称冲突始终会导致政策编译器错误。
类型/属性命名空间
SELinux 不允许多次声明相同的类型/属性。具有重复声明的政策将无法编译。为避免类型和属性名称冲突,所有供应商声明都应以 vendor_
开头的命名空间。
type foo, domain; → type vendor_foo, domain;
系统属性和进程标签所有权
使用属性命名空间是解决标签冲突的最佳方法。为轻松识别平台属性并在重命名或添加导出的平台属性时避免名称冲突,请确保所有供应商属性都有自己的前缀
属性类型 | 可接受的前缀 |
---|---|
控制属性 | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor.
|
可读写 | vendor. |
只读 | ro.vendor. ro.boot. ro.hardware.
|
持久性 | persist.vendor. |
供应商可以继续使用 ro.boot.*
(来自内核 cmdline)和 ro.hardware.*
(明显的硬件相关属性)。
init rc 文件中的所有供应商服务都应为非系统分区的 init rc 文件中的服务使用 vendor.
。类似的规则也适用于供应商属性的 SELinux 标签(供应商属性使用 vendor_
)。
文件所有权
防止文件冲突具有挑战性,因为平台政策和供应商政策通常都为所有文件系统提供标签。与类型命名不同,文件命名空间是不切实际的,因为其中许多文件是由内核创建的。为防止这些冲突,请遵循本节中文件系统的命名指南。对于 Android 8.0,这些是没有任何技术强制措施的建议。将来,这些建议将由供应商测试套件 (VTS) 强制执行。
系统 (/system)
只有系统映像必须通过 file_contexts
、service_contexts
等为 /system
组件提供标签。如果在 /vendor
政策中添加了 /system
组件的标签,则可能无法进行仅框架 OTA 更新。
供应商 (/vendor)
AOSP SELinux 政策已标记平台与之交互的 vendor
分区的部分内容,这使编写 SELinux 规则成为可能,以便平台进程能够与 vendor
分区的部分内容进行通信和/或访问。示例
/vendor 路径 |
平台提供的标签 | 依赖于标签的平台进程 |
---|---|---|
/vendor(/.*)?
|
vendor_file
|
框架中的所有 HAL 客户端、ueventd 等。 |
/vendor/framework(/.*)?
|
vendor_framework_file
|
dex2oat 、appdomain 等。 |
/vendor/app(/.*)?
|
vendor_app_file
|
dex2oat 、installd 、idmap 等。 |
/vendor/overlay(/.*)
|
vendor_overlay_file
|
system_server 、zygote 、idmap 等。 |
因此,在标记 vendor
分区中的其他文件时,必须遵循特定规则(通过 neverallows
强制执行)
vendor_file
必须是vendor
分区中所有文件的默认标签。平台政策要求这样做才能访问直通式 HAL 实现。- 通过供应商 SEPolicy 在
vendor
分区中添加的所有新exec_types
都必须具有vendor_file_type
属性。这是通过 neverallows 强制执行的。 - 为避免与未来的平台/框架更新发生冲突,请避免在
vendor
分区中标记exec_types
以外的文件。 - AOSP 标识的同一进程 HAL 的所有库依赖项都必须标记为
same_process_hal_file.
。
Procfs (/proc)
/proc
中的文件只能使用 genfscon
标签进行标记。在 Android 7.0 中,平台和 供应商政策都使用 genfscon
来标记 procfs
中的文件。
建议:只有平台政策标记 /proc
。如果 vendor
进程需要访问 /proc
中当前标记有默认标签 (proc
) 的文件,则供应商政策不应显式标记它们,而应使用通用 proc
类型来为供应商域添加规则。这允许平台更新适应未来通过 procfs
公开的内核接口,并根据需要显式标记它们。
Debugfs (/sys/kernel/debug)
Debugfs
可以在 file_contexts
和 genfscon
中标记。在 Android 7.0 到 Android 10 中,平台和供应商都标记 debugfs
。
在 Android 11 中,debugfs
无法在生产设备上访问或挂载。设备制造商应移除 debugfs
。
Tracefs (/sys/kernel/debug/tracing)
Tracefs
可以在 file_contexts
和 genfscon
中标记。在 Android 7.0 中,只有平台标记 tracefs
。
建议:只有平台可以标记 tracefs
。
Sysfs (/sys)
/sys
中的文件可以使用 file_contexts
和 genfscon
进行标记。在 Android 7.0 中,平台和供应商都使用 genfscon
来标记 sysfs
中的文件。
建议:平台可以标记非特定于设备的 sysfs
节点。否则,只有供应商可以标记文件。
tmpfs (/dev)
/dev
中的文件可以在 file_contexts
中标记。在 Android 7.0 中,平台和供应商都标记此处的文件。
建议:供应商只能标记 /dev/vendor
中的文件(例如,/dev/vendor/foo
、/dev/vendor/socket/bar
)。
Rootfs (/)
/
中的文件可以在 file_contexts
中标记。在 Android 7.0 中,平台和供应商都标记此处的文件。
建议:只有系统可以标记 /
中的文件。
Data (/data)
数据通过 file_contexts
和 seapp_contexts
的组合进行标记。
建议:禁止供应商在 /data/vendor
之外进行标记。只有平台可以标记 /data
的其他部分。
Genfs 标签版本
从供应商 API 级别 202504 开始,在 system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil
中使用 genfscon
分配的较新 SELinux 标签对于旧的供应商分区是可选的。这允许旧的供应商分区保留其现有的 SEPolicy 实现。这由 Makefile 变量 BOARD_GENFS_LABELS_VERSION
控制,该变量存储在 /vendor/etc/selinux/genfs_labels_version.txt
中。
示例
- 在供应商 API 级别 202404 中,默认情况下
/sys/class/udc
节点标记为sysfs
。 - 从供应商 API 级别 202504 开始,
/sys/class/udc
标记为sysfs_udc
。
但是,/sys/class/udc
可能正被使用 API 级别 202404 的供应商分区使用,使用的标签可能是默认的 sysfs
标签或供应商特定的标签。无条件地将 /sys/class/udc
标记为 sysfs_udc
可能会破坏与这些供应商分区的兼容性。通过检查 BOARD_GENFS_LABELS_VERSION
,平台可以继续为旧的供应商分区使用以前的标签和权限。
BOARD_GENFS_LABELS_VERSION
可以大于或等于供应商 API 级别。例如,使用 API 级别 202404 的供应商分区可以将 BOARD_GENFS_LABELS_VERSION
设置为 202504,以采用 202504 中引入的新标签。请参阅 202504 特定 genfs 标签列表。
在标记 genfscon
节点时,平台必须考虑旧的供应商分区,并在需要时实施回退机制以实现兼容性。平台可以使用仅限平台的库来查询 genfs 标签版本。
- 在原生代码中,使用
libgenfslabelsversion
。请参阅genfslabelsversion.h
,了解libgenfslabelsversion
的标头文件。 - 在 Java 中,使用
android.os.SELinux.getGenfsLabelsVersion()
。
兼容性属性
SELinux 政策是特定对象类和权限的源类型和目标类型之间的交互。受 SELinux 政策影响的每个对象(进程、文件等)可能只有一个类型,但该类型可能具有多个属性。
政策主要根据现有类型编写
allow source_type target_type:target_class permission(s);
之所以可行,是因为政策是在了解所有类型的情况下编写的。但是,如果供应商政策和平台政策使用特定类型,并且特定对象的标签仅在其中一个政策中更改,则另一个政策可能包含以前依赖的已获得或丢失访问权限的政策。例如:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
可以更改为
File_contexts: /sys/A u:object_r:sysfs_A:s0
尽管供应商政策保持不变,但由于缺少针对新 sysfs_A
类型的政策,v_domain
将失去访问权限。
通过根据属性定义政策,我们可以为底层对象提供一个类型,该类型具有与平台代码和供应商代码的政策相对应的属性。这可以针对所有类型完成,以有效创建属性政策,其中永远不会使用具体类型。实际上,这仅对于平台和供应商之间重叠的政策部分是必需的,这些部分被定义和提供为平台公共政策,并作为供应商政策的一部分构建。
将公共政策定义为版本化属性满足了两个政策兼容性目标:
- 确保供应商代码在平台更新后继续工作。 通过向与供应商代码所依赖的对象相对应的具体类型添加属性来实现,从而保留访问权限。
- 弃用政策的能力。 通过将政策集清晰地划分为属性来实现,这些属性可以在不再支持其对应的版本后立即移除。平台可以继续开发,因为它知道旧政策仍然存在于供应商政策中,并且会在升级时自动移除。
政策可写性
为了实现无需了解政策开发特定版本变更的目标,Android 8.0 包含平台公共政策类型及其属性之间的映射。类型 foo
映射到属性 foo_vN
,其中 N
是目标版本。vN
对应于 PLATFORM_SEPOLICY_VERSION
构建变量,格式为 MM.NN
,其中 MM
对应于平台 SDK 编号,NN
是平台 sepolicy 特定版本。
公共政策中的属性未进行版本控制,而是作为平台和供应商政策可以构建的 API 而存在,以保持两个分区之间的接口稳定。平台和供应商政策编写者都可以继续按照今天的编写方式编写政策。
平台公共政策导出为 allow source_foo target_bar:class perm;
,包含在供应商政策中。在编译期间(包括相应的版本),它会转换为将进入设备供应商部分的政策(在转换后的通用中间语言 (CIL) 中显示)
(allow source_foo_vN target_bar_vN (class (perm)))
由于供应商政策永远不会领先于平台,因此它不应关注以前的版本。但是,平台政策需要知道供应商政策回溯到多远,在其类型中包含属性,并设置与版本化属性对应的政策。
政策差异
如果不跨版本差异映射属性到类型,则通过在每种类型的末尾添加 _vN
来自动创建属性是没有任何作用的。Android 维护属性版本之间的映射以及类型到这些属性的映射。这在上述映射文件中使用语句完成,例如 (CIL)
(typeattributeset foo_vN (foo))
平台升级
以下部分详细介绍了平台升级的场景。
相同类型
当对象在政策版本中未更改标签时,会发生这种情况。源类型和目标类型都是如此,并且可以在 /dev/binder
中看到,它在所有版本中都标记为 binder_device
。它在转换后的政策中表示为:
binder_device_v1 … binder_device_vN
当从 v1
→ v2
升级时,平台政策必须包含:
type binder_device; -> (type binder_device) (in CIL)
在 v1 映射文件 (CIL) 中:
(typeattributeset binder_device_v1 (binder_device))
在 v2 映射文件 (CIL) 中:
(typeattributeset binder_device_v2 (binder_device))
在 v1 供应商政策 (CIL) 中:
(typeattribute binder_device_v1) (allow binder_device_v1 …)
在 v2 供应商政策 (CIL) 中:
(typeattribute binder_device_v2) (allow binder_device_v2 …)
新类型
当平台添加了新类型时,会发生这种情况,这可能发生在添加新功能或政策强化期间。
- 新功能。 当类型标记以前不存在的对象(例如新的服务进程)时,供应商代码以前没有直接与之交互,因此不存在相应的政策。与该类型对应的新属性在前一个版本中没有属性,因此无需在针对该版本的映射文件中添加条目。
- 政策强化。 当类型表示政策强化时,新类型属性必须链接回与前一个属性对应的一系列属性(类似于之前的示例将
/sys/A
从sysfs
更改为sysfs_A
)。供应商代码依赖于启用对sysfs
访问权限的规则,并且需要将该规则作为新类型的属性包含在内。
当从 v1
→ v2
升级时,平台政策必须包含:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
在 v1 映射文件 (CIL) 中:
(typeattributeset sysfs_v1 (sysfs sysfs_A))
在 v2 映射文件 (CIL) 中:
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
在 v1 供应商政策 (CIL) 中:
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
在 v2 供应商政策 (CIL) 中:
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
已移除类型
当类型被移除时,会发生这种情况(很少见),这可能发生在底层对象:
- 仍然存在,但获得了不同的标签。
- 被平台移除。
在政策放宽期间,会移除一种类型,并且标记有该类型的对象会被赋予不同的、已存在的标签。这表示属性映射的合并:供应商代码仍然必须能够通过它过去拥有的属性访问底层对象,但系统的其余部分现在必须能够通过其新属性访问它。
如果已切换到的属性是新的,则重新标记与新类型的情况相同,但当使用现有标签时,添加旧属性新类型将导致也使用此标签标记的其他对象变为新可访问。这基本上是平台所做的事情,并且被认为是保持兼容性的可接受的权衡。
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
示例版本 1:折叠类型(移除 sysfs_A)
当从 v1
→ v2
升级时,平台政策必须包含:
type sysfs; (type sysfs) (in CIL)
在 v1 映射文件 (CIL) 中:
(typeattributeset sysfs_v1 (sysfs)) (type sysfs_A) # in case vendors used the sysfs_A label on objects (typeattributeset sysfs_A_v1 (sysfs sysfs_A))
在 v2 映射文件 (CIL) 中:
(typeattributeset sysfs_v2 (sysfs))
在 v1 供应商政策 (CIL) 中:
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
在 v2 供应商政策 (CIL) 中:
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
示例版本 2:完全移除(foo 类型)
当从 v1
→ v2
升级时,平台政策必须包含:
# nothing - we got rid of the type
在 v1 映射文件 (CIL) 中:
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
在 v2 映射文件 (CIL) 中:
# nothing - get rid of it
在 v1 供应商政策 (CIL) 中:
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
在 v2 供应商政策 (CIL) 中:
(typeattribute sysfs_v2) (allow sysfs_v2 …)
新类/权限
当平台升级引入以前版本中不存在的新政策组件时,会发生这种情况。例如,当 Android 添加了 servicemanager
对象管理器(它创建了 add、find 和 list 权限)时,想要向 servicemanager
注册的供应商守护程序需要不可用的权限。在 Android 8.0 中,只有平台政策可以添加新类和权限。
为了允许所有可能由供应商政策创建或扩展的域使用新类而不受阻碍,平台政策需要包含类似于以下的规则:
allow {domain -coredomain} *:new_class perm;
这甚至可能需要允许所有接口(公共政策)类型访问的政策,以确保供应商映像获得访问权限。如果这导致不可接受的安全政策(就像 servicemanager 变更可能导致的那样),则可能会强制供应商升级。
已移除类/权限
当对象管理器被移除时(例如 ZygoteConnection
对象管理器),会发生这种情况,并且不应导致问题。对象管理器类和权限可以保留在政策中定义,直到供应商版本不再使用它为止。这通过将定义添加到相应的映射文件来完成。
针对新类型/重新标记类型的供应商自定义
新的供应商类型是供应商政策开发的核心,因为它们需要描述新的进程、二进制文件、设备、子系统和存储的数据。因此,必须允许创建供应商定义的类型。
由于供应商政策始终是设备上最旧的政策,因此无需自动将所有供应商类型转换为政策中的属性。平台不依赖于供应商政策中标记的任何内容,因为平台对此一无所知;但是,平台将提供它用于与标记有这些类型的对象交互的属性和公共类型(例如 domain
、sysfs_type
等)。为了使平台继续与这些对象正确交互,必须适当应用属性和类型,并且可能需要将特定规则添加到可自定义的域(例如 init
)。
Android 9 的属性变更
升级到 Android 9 的设备可以使用以下属性,但使用 Android 9 启动的设备不得使用。
违规属性
Android 9 包括以下与域相关的属性:
data_between_core_and_vendor_violators
。 用于所有违反不通过路径在vendor
和coredomains
之间共享文件的要求的域的属性。平台进程和供应商进程不应使用磁盘上的文件进行通信(不稳定的 ABI)。建议:- 供应商代码应使用
/data/vendor
。 - 系统不应使用
/data/vendor
。
- 供应商代码应使用
system_executes_vendor_violators
。 用于所有违反不执行供应商二进制文件的要求的系统域(init
和shell domains
除外)的属性。执行供应商二进制文件具有不稳定的 API。平台不应直接执行供应商二进制文件。建议:- 此类平台对供应商二进制文件的依赖项必须位于 HIDL HAL 之后。
或
- 需要访问供应商二进制文件的
coredomains
应移至供应商分区,从而不再是coredomain
。
- 此类平台对供应商二进制文件的依赖项必须位于 HIDL HAL 之后。
不受信任的属性
托管任意代码的不受信任的应用不应访问 HwBinder 服务,但被认为对于此类应用访问而言足够安全的服务除外(请参阅下面的安全服务)。这主要有两个原因:
- HwBinder 服务器不执行客户端身份验证,因为 HIDL 当前不公开调用方 UID 信息。即使 HIDL 公开了此类数据,许多 HwBinder 服务要么在低于应用的级别(例如 HAL)运行,要么不得依赖应用身份进行授权。因此,为了安全起见,默认假设是每个 HwBinder 服务都将其所有客户端视为有同等权限执行该服务提供的操作。
- HAL 服务器(HwBinder 服务的一个子集)包含的代码的安全问题发生率高于
system/core
组件,并且可以访问堆栈的较低层(一直到硬件),从而增加了绕过 Android 安全模型的机会。
安全服务
安全服务包括:
same_process_hwservice
。这些服务(根据定义)在客户端的进程中运行,因此具有与进程运行所在的客户端域相同的访问权限。coredomain_hwservice
。这些服务不会带来与原因 #2 相关的风险。hal_configstore_ISurfaceFlingerConfigs
。此服务专为任何域使用而设计。hal_graphics_allocator_hwservice
。这些操作也由surfaceflinger
Binder 服务提供,应用被允许访问该服务。hal_omx_hwservice
。这是mediacodec
Binder 服务的 HwBinder 版本,应用被允许访问该服务。hal_codec2_hwservice
。这是hal_omx_hwservice
的较新版本。
可用属性
所有未被视为安全的 hwservices
都具有属性 untrusted_app_visible_hwservice
。相应的 HAL 服务器具有属性 untrusted_app_visible_halserver
。使用 Android 9 启动的设备不得使用任何 untrusted
属性。
建议:
- 非信任的应用应与系统服务对话,而系统服务再与供应商 HIDL HAL 对话。例如,应用可以与
binderservicedomain
对话,然后mediaserver
(它是一个binderservicedomain
)反过来与hal_graphics_allocator
对话。或
- 需要直接访问
vendor
HAL 的应用应具有其自己供应商定义的 sepolicy 域。
文件属性测试
Android 9 包含构建时测试,以确保特定位置中的所有文件都具有适当的属性(例如,sysfs
中的所有文件都具有所需的 sysfs_type
属性)。
平台公共策略
平台公共策略是遵循 Android 8.0 架构模型的内核,而无需简单地维护 v1 和 v2 中平台策略的联合。供应商可以看到平台策略的一个子集,其中包含可用的类型和属性以及关于这些类型和属性的规则,这些规则随后成为供应商策略的一部分(即 vendor_sepolicy.cil
)。
类型和规则在供应商生成的策略中自动转换为 attribute_vN
,以便所有平台提供的类型都是版本化的属性(但属性未版本化)。平台负责将它提供的具体类型映射到适当的属性,以确保供应商策略继续运行,并确保包含为特定版本提供的规则。平台公共策略和供应商策略的组合满足 Android 8.0 架构模型的独立平台和供应商构建的目标。
映射到属性链
当使用属性映射到策略版本时,类型会映射到一个或多个属性,从而确保可以使用与其先前类型对应的属性访问用该类型标记的对象。
维护从策略编写者处隐藏版本信息的目标意味着自动生成版本化的属性并将它们分配给适当的类型。在静态类型的常见情况下,这很简单:type_foo
映射到 type_foo_v1
。
对于对象标签更改,例如 sysfs
→ sysfs_A
或 mediaserver
→ audioserver
,创建此映射并非易事(并在上面的示例中进行了描述)。平台策略维护者必须确定如何在对象的转换点创建映射,这需要了解对象及其分配的标签之间的关系,并确定何时发生这种情况。为了向后兼容,这种复杂性需要在平台侧进行管理,平台侧是唯一可以升级的分区。
版本升级
为简单起见,当新的发布分支被切断时,Android 平台会发布 sepolicy 版本。如上所述,版本号包含在 PLATFORM_SEPOLICY_VERSION
中,格式为 MM.nn
,其中 MM
对应于 SDK 值,nn
是在 /platform/system/sepolicy
中维护的私有值。例如,Kitkat 为 19.0
,Lollipop 为 21.0
,Lollipop-MR1 为 22.0
,Marshmallow 为 23.0
,Nougat 为 24.0
,Nougat-MR1 为 25.0
,Oreo 为 26.0
,Oreo-MR1 为 27.0
,Android 9 为 28.0
。升级并不总是整数。例如,如果 MR 升级到某个版本需要对 system/sepolicy/public
进行不兼容的更改,但不需要 API 升级,则该 sepolicy 版本可能是:vN.1
。开发分支中存在的版本是永远不会在发货设备中使用的 10000.0
。
Android 可能会在升级时弃用最旧的版本。为了获得何时弃用版本的输入,Android 可能会收集运行该 Android 版本并仍在接收主要平台更新的供应商策略的设备数量。如果数量小于某个阈值,则该版本将被弃用。
多个属性的性能影响
如 https://github.com/SELinuxProject/cil/issues/9 中所述,分配给类型的attribute数量过多会导致策略缓存未命中时的性能问题。
这已被证实是 Android 中的一个问题,因此 进行了更改,以在 Android 8.0 中删除策略编译器添加到策略中的属性,以及删除未使用的属性。这些更改解决了性能回归问题。
system_ext 公共策略和 product 公共策略
从 Android 11 开始,允许 system_ext
和 product
分区将其指定的公共类型导出到供应商分区。与平台公共策略类似,供应商使用自动转换为版本化属性的类型和规则,例如,从 type
转换为 type_N
,其中 N
是供应商分区所针对构建的平台版本。
当 system_ext
和 product
分区基于相同的平台版本 N
时,构建系统会生成基本映射文件到 system_ext/etc/selinux/mapping/N.cil
和 product/etc/selinux/mapping/N.cil
,其中包含从 type
到 type_N
的身份映射。供应商可以使用版本化属性 type_N
访问 type
。
如果仅更新了 system_ext
和 product
分区,例如从 N
到 N+1
(或更高版本),而供应商仍停留在 N
,则供应商可能会失去对 system_ext
和 product
分区的类型的访问权限。为了防止损坏,system_ext
和 product
分区应提供从具体类型到 type_N
属性的映射文件。如果合作伙伴要支持 N
供应商与 N+1
(或更高版本)system_ext
和 product
分区,则每个合作伙伴都负责维护映射文件。
为此,合作伙伴应执行以下操作
- 将生成的基准映射文件从
N
system_ext
和product
分区 复制到其源代码树。 - 根据需要修改映射文件。
-
将映射文件安装到
N+1
(或更高版本)system_ext
和product
分区。
例如,假设 N
system_ext
具有一个名为 foo_type
的公共类型。那么 N
system_ext
分区中的 system_ext/etc/selinux/mapping/N.cil
将如下所示
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
如果 bar_type
被添加到 N+1
system_ext,并且如果 bar_type
应该映射到 foo_type
以用于 N
供应商,则 N.cil
可以从以下内容更新
(typeattributeset foo_type_N (foo_type))
到
(typeattributeset foo_type_N (foo_type bar_type))
然后安装到 N+1
system_ext 的分区。N
供应商可以继续访问 N+1
system_ext 的 foo_type
和 bar_type
。
SELinux 上下文标记
为了支持平台 sepolicy 和供应商 sepolicy 之间的区别,系统以不同的方式构建 SELinux 上下文文件,以保持它们的分离。
文件上下文
Android 8.0 引入了以下 file_contexts
的更改
- 为了避免在设备启动期间增加额外的编译开销,
file_contexts
不再以二进制形式存在。相反,它们是可读的正则表达式文本文件,例如{property, service}_contexts
(与 7.0 之前的版本一样)。 file_contexts
分为两个文件plat_file_contexts
- Android 平台
file_context
,除了标记/vendor
分区的部分(必须精确标记以确保 sepolicy 文件正常运行)外,没有特定于设备的标签。 - 必须位于
system
分区中的/system/etc/selinux/plat_file_contexts
,并在启动时由init
与供应商file_context
一起加载。
- Android 平台
vendor_file_contexts
- 设备特定的
file_context
,通过组合在设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的file_contexts
构建。 - 必须安装在
vendor
分区中的/vendor/etc/selinux/vendor_file_contexts
,并在启动时由init
与平台file_context
一起加载。
- 设备特定的
属性上下文
在 Android 8.0 中,property_contexts
分为两个文件
plat_property_contexts
- Android 平台
property_context
,没有特定于设备的标签。 - 必须位于
system
分区中的/system/etc/selinux/plat_property_contexts
,并在启动时由init
与供应商property_contexts
一起加载。
- Android 平台
vendor_property_contexts
- 设备特定的
property_context
,通过组合在设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的property_contexts
构建。 - 必须位于
vendor
分区中的/vendor/etc/selinux/vendor_property_contexts
,并在启动时由init
与平台property_context
一起加载。
- 设备特定的
服务上下文
在 Android 8.0 中,service_contexts
分为以下文件
plat_service_contexts
- 用于
servicemanager
的 Android 平台特定的service_context
。service_context
没有特定于设备的标签。 - 必须位于
system
分区中的/system/etc/selinux/plat_service_contexts
,并在启动时由servicemanager
与供应商service_contexts
一起加载。
- 用于
vendor_service_contexts
- 设备特定的
service_context
,通过组合在设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的service_contexts
构建。 - 必须位于
vendor
分区中的/vendor/etc/selinux/vendor_service_contexts
,并在启动时由servicemanager
与平台service_contexts
一起加载。 - 尽管
servicemanager
在启动时查找此文件,但对于完全兼容TREBLE
的设备,vendor_service_contexts
必须不存在。这是因为vendor
和system
进程之间的所有交互必须通过hwservicemanager
/hwbinder
进行。
- 设备特定的
plat_hwservice_contexts
- 用于
hwservicemanager
的 Android 平台hwservice_context
,没有特定于设备的标签。 - 必须位于
system
分区中的/system/etc/selinux/plat_hwservice_contexts
,并在启动时由hwservicemanager
与vendor_hwservice_contexts
一起加载。
- 用于
vendor_hwservice_contexts
- 设备特定的
hwservice_context
,通过组合在设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的hwservice_contexts
构建。 - 必须位于
vendor
分区中的/vendor/etc/selinux/vendor_hwservice_contexts
,并在启动时由hwservicemanager
与plat_service_contexts
一起加载。
- 设备特定的
vndservice_contexts
- 用于
vndservicemanager
的设备特定的service_context
,通过组合在设备的Boardconfig.mk
中由BOARD_SEPOLICY_DIRS
指向的目录中找到的vndservice_contexts
构建。 - 此文件必须位于
vendor
分区中的/vendor/etc/selinux/vndservice_contexts
,并由vndservicemanager
在启动时加载。
- 用于
Seapp 上下文
在 Android 8.0 中,seapp_contexts
分为两个文件
plat_seapp_contexts
- Android 平台
seapp_context
,没有特定于设备的更改。 - 必须位于
system
分区中的/system/etc/selinux/plat_seapp_contexts.
- Android 平台
vendor_seapp_contexts
- 平台
seapp_context
的设备特定扩展,通过组合在设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的seapp_contexts
构建。 - 必须位于
vendor
分区中的/vendor/etc/selinux/vendor_seapp_contexts
。
- 平台
MAC 权限
在 Android 8.0 中,mac_permissions.xml
分为两个文件
- 平台
mac_permissions.xml
- Android 平台
mac_permissions.xml
,没有特定于设备的更改。 - 必须位于
system
分区中的/system/etc/selinux/.
- Android 平台
- 非平台
mac_permissions.xml
- 平台
mac_permissions.xml
的设备特定扩展,从设备的Boardconfig.mk
文件中由BOARD_SEPOLICY_DIRS
指向的目录中找到的mac_permissions.xml
构建。 - 必须位于
vendor
分区中的/vendor/etc/selinux/.
- 平台