政策兼容性

本文介绍了 Android 如何处理与平台 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 不允许同一类型/属性有多次声明。具有重复声明的政策将无法编译。为了避免类型和属性名称冲突,所有供应商声明都应以 np_ 开头,以明确其所在的命名空间。

type foo, domain; → type np_foo, domain;

系统属性和进程标签所有权

为了避免标签冲突,最有效的解决方法是使用属性命名空间。如需轻松识别平台属性并在重命名或添加导出的平台属性时避免名称冲突,请确保所有供应商属性都有各自的前缀:

属性类型 可接受的前缀
控件属性 ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
可读写 vendor.
只读 ro.vendor.
ro.boot.
ro.hardware.
持久性 persist.vendor.

供应商可以继续使用 ro.boot.*(来自内核命令行)和 ro.hardware.*(明显的硬件相关属性)。

对于非系统分区的 init rc 文件中的服务,init rc 文件中的所有供应商服务都应带有 vendor.。对供应商属性的 SELinux 标签应用类似的规则(供应商属性应带有 vendor_)。

文件所有权

防止文件冲突是一项具有挑战性的工作,因为平台政策和供应商政策通常都为所有文件系统提供标签。与类型命名不同,文件的命名空间并不实用,因为其中很多文件都是由内核创建的。若要避免此类冲突,请遵循本节中文件系统的命名指南。对于 Android 8.0,这些指南只是建议,并不要求在技术上强制执行。将来,这些建议将由供应商测试套件 (VTS) 强制执行。

系统 (/system)

只有系统映像必须通过 file_contextsservice_contexts 等为 /system 组件提供标签。如果在 /vendor 政策中添加了 /system 组件的标签,则仅针对框架的 OTA 更新可能无法实现。

供应商 (/vendor)

AOSP SELinux 政策已经标记了会与平台交互的 vendor 分区部分,这样便可以为平台进程编写 SELinux 规则,使其能够访问 vendor 分区的某些部分并/或与之通信。示例如下:

/vendor 路径 平台提供的标签 依赖于标签的平台进程
/vendor(/.*)? vendor_file 框架中的所有 HAL 客户端、ueventd
/vendor/framework(/.*)? vendor_framework_file dex2oatappdomain
/vendor/app(/.*)? vendor_app_file dex2oatinstalldidmap
/vendor/overlay(/.*) vendor_overlay_file system_serverzygoteidmap

因此,在 vendor 分区中标记额外的文件时,必须遵循特定规则(通过 neverallows 强制执行):

  • vendor_file 必须是 vendor 分区中所有文件的默认标签。平台政策要求使用此标签来访问直通式 HAL 实现。
  • 通过供应商 SEPolicy 在 vendor 分区中添加的所有新 exec_types 均必须具有 vendor_file_type 属性。这一规则通过 neverallows 强制执行。
  • 为了避免与将来的平台/框架更新发生冲突,请避免在 vendor 分区中标记除 exec_types 之外的文件。
  • AOSP 标识的 Same-Process 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_contextsgenfscon 中进行标记。在 Android 7.0 到 Android 10 中,平台和供应商都会标记 debugfs

在 Android 11 中,无法在生产设备上访问或装载 debugfs。设备制造商应移除 debugfs

Tracefs (/sys/kernel/debug/tracing)

Tracefs 可以在 file_contextsgenfscon 中进行标记。在 Android 7.0 中,只有平台会标记 tracefs

建议:只有平台可以标记 tracefs

Sysfs (/sys)

/sys 中的文件可以使用 file_contextsgenfscon 进行标记。在 Android 7.0 中,平台和供应商都使用 file_contextsgenfscon 标记 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)

数据通过 file_contextsseapp_contexts 的组合进行标记。

建议:不允许供应商在 /data/vendor 之外进行标记。只有平台可以标记 /data 的其他部分。

兼容性属性

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 build 变量,格式为 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/Asysfs 更改为 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 对象管理器时,想要向 servicemanager 注册的供应商守护程序需要之前未提供的权限。在 Android 8.0 中,只有平台政策可以添加新的类和权限。

要允许所有可能由供应商政策创建或扩展的域毫无阻碍地使用新类,平台政策需要包含类似于下文的规则:

allow {domain -coredomain} *:new_class perm;

这甚至可能需要政策允许访问所有接口(公共政策)类型,以确保供应商映像获得访问权限。如果这会导致不可接受的安全政策(就像 servicemanager 更改可能会导致的结果一样),则系统可能会强制进行供应商升级。

移除的类/权限

移除对象管理器(例如 ZygoteConnection 对象管理器)会出现这种情况,应该不会导致出现问题。对象管理器类和权限可以一直在政策中保持已定义状态,直到供应商版本不再使用它为止。通过在相应的映射文件中添加定义,可以做到这一点。

新类型/重新标记的类型的供应商自定义设置

新供应商类型是制定供应商政策的核心,这是因为,新供应商类型是描述新进程、二进制文件、设备、子系统和存储的数据所必需的。因此,必须允许创建供应商定义的类型。

由于供应商政策始终是设备上最旧的政策,因此无需自动将所有供应商类型转换为政策中的属性。平台不依赖于在供应商政策中标记的任何内容,因为平台并不知道这些内容;但是,平台将提供它与用这些类型(例如 domainsysfs_type 等)标记的对象进行交互所用的属性和公共类型。为使平台继续与这些对象正确交互,必须适当地应用这些属性和类型,并且可能需要将特定规则添加到可自定义域(例如 init)中。

Android 9 的属性更改

升级到 Android 9 的设备可以使用以下属性,但搭载 Android 9 的设备不能使用这些属性。

违规者属性

Android 9 包含以下与域相关的属性:

  • data_between_core_and_vendor_violators。违反不得按 vendorcoredomains 之间的路径共享文件这一要求的所有域的属性。平台和供应商进程不应使用磁盘文件进行通信(不稳定的 ABI)。 建议:
    • 供应商代码应使用 /data/vendor
    • 系统不应使用 /data/vendor
  • system_executes_vendor_violators。违反不执行供应商二进制文件这一要求的所有系统域(initshell domains 除外)的属性。供应商二进制文件的执行具有不稳定的 API。平台不应直接执行供应商二进制文件。建议:
    • 供应商二进制文件中的此类平台依赖项必须位于 HIDL HAL 之后。

    • 需要访问供应商二进制文件的 coredomains 应移至供应商分区,因此不再是 coredomain

不受信任的属性

托管任意代码的不受信任的应用不应具有 HwBinder 服务的访问权限,但被视为足够安全而可以通过此类应用访问的服务除外(请参阅下面的安全服务)。这主要有以下两个原因:

  1. HwBinder 服务器不会执行客户端身份验证,因为 HIDL 目前未公开调用方 UID 信息。即使 HIDL 确实公开了此类数据,许多 HwBinder 服务也会在低于应用的级别运行(例如 HAL),或者不能依赖应用身份进行授权。因此,为了安全起见,默认假设是每个 HwBinder 服务都将其所有客户端视为具有可执行该服务所提供操作的同等授权。
  2. HAL 服务器(HwBinder 服务的一个子集)包含安全问题发生率高于 system/core 组件的代码,并且可以访问堆栈的较低层级(一直到硬件),从而提升绕过 Android 安全模型的机率。

安全服务

安全服务包括:

  • same_process_hwservice。这些服务(根据定义)在客户端进程中运行,因此与运行该进程的客户端域具有相同的访问权限。
  • coredomain_hwservice。这些服务不会带来与第 2 种原因相关的风险。
  • hal_configstore_ISurfaceFlingerConfigs。此服务专为任何域使用而设计。
  • hal_graphics_allocator_hwservicesurfaceflinger 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 架构模型目标,即允许独立的平台和供应商 build。

映射到属性链

使用属性映射到政策版本时,一个类型会映射到一个或多个属性,确保使用该类型标记的对象可通过与这些对象之前的类型对应的属性访问。

达成向政策编写器隐藏版本信息的目标意味着自动生成版本化属性并分配给适当的类型。对于常见的静态类型,这很简单:type_foo 映射到 type_foo_v1

对于对象标签更改(例如 sysfssysfs_Amediaserveraudioserver),创建此映射非常重要(如上面的示例中所述)。平台政策维护者必须确定如何在对象的转换点处创建映射,这需要了解对象及其所分配的标签之间的关系并确定何时发生这种情况。为了实现向后兼容性,需要在平台端(这是唯一可以升级的分区)管理这种复杂性。

版本升级

为简单起见,Android 平台会在新版本分支发布后推出一个 sepolicy 版本。如上所述,版本号包含在 PLATFORM_SEPOLICY_VERSION 中,其格式为 MM.nn,其中 MM 对应于 SDK 值,nn 是在 /platform/system/sepolicy. 中维护的不公开值。例如,19.0 对应于 Kitkat,21.0 对应于 Lollipop,22.0 对应于 Lollipop-MR1,23.0 对应于 Marshmallow,24.0 对应于 Nougat,25.0 对应于 Nougat-MR1,26.0 对应于 Oreo,27.0 对应于 Oreo-MR1,28.0 对应于 Android 9。升级版本号不一定是整数。例如,如果因 MR 版本递增而需要对 system/sepolicy/public 进行不兼容的更改,但不是 API 递增,则该 sepolicy 版本可以为 vN.1。开发分支中的版本是 10000.0,该版本绝不会用在搭载 Android 的设备中。

Android 可能会在升级时弃用最旧的版本。为了解何时废弃某个版本,Android 可能会根据供应商政策收集运行该 Android 版本且仍在接收主要平台更新的设备数量。如果该数字小于特定阈值,则会废弃该版本。

多个属性的性能影响

https://github.com/SELinuxProject/cil/issues/9 中所述,分配给某个类型的大量属性会在政策缓存未命中时导致性能问题。

这已被证实是 Android 中存在的问题,因此我们对 Android 8.0 进行了更改,以移除政策编译器添加到政策中的属性,另外还移除了未使用的属性。这些更改解决了性能降低问题。

system_ext 公共政策和产品公共政策

从 Android 11 开始,system_ext 和 product 分区可以将其指定的公共类型导出到 vendor 分区。与平台公共政策一样,vendor 使用的类型和规则将自动转换为带版本编号的属性,例如从 type 转换为 type_N,其中 N 是构建 vendor 分区所采用平台的版本。

当 system_ext 和 product 分区基于同一平台版本 N 时,构建系统会生成到 system_ext/etc/selinux/mapping/N.cilproduct/etc/selinux/mapping/N.cil 的基本映射文件,其中包含从 typetype_N 的身份映射。vendor 可以通过版本化属性 type_N 访问 type

如果只有 system_ext 和 product 分区进行了更新,比如说从 N+1 更新为 N(或更高版本),而 vendor 保持在 N,那么 vendor 可能会无法访问 system_ext 和 product 分区类型。为避免中断,system_ext 和 product 分区应提供从具体类型到 type_N 属性的映射文件。每个合作伙伴都应负责维护映射文件,前提是他们支持通过 N+1(或更高版本)的 system_ext 和 product 分区映射到 N vendor 分区。

为此,合作伙伴需要:

  1. 将生成的基本映射文件从 N system_ext 和 product 分区复制到其源代码树
  2. 根据需要修改映射文件。
  3. 将映射文件安装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 vendor),则 N.cil 可以从

(typeattributeset foo_type_N (foo_type))

更新为

(typeattributeset foo_type_N (foo_type bar_type))

然后安装到 N+1 system_ext 的分区中。N vendor 可以继续访问 N+1 system_ext 的 foo_typebar_type

SELinux 上下文标签

为便于区别平台和供应商 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 一起加载)。
    • vendor_file_contexts
      • 设备专用 file_context,通过合并 file_contexts(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
      • 必须安装到 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 一起加载)。
  • vendor_property_contexts
    • 设备专用 property_context,通过合并 property_contexts(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 必须位于 vendor 分区中的 /vendor/etc/selinux/vendor_property_contexts 下,并由 init 在启动时加载(与平台 property_context 一起加载)。

服务上下文

在 Android 8.0 中,service_contexts 拆分成了以下文件:

  • plat_service_contexts
    • servicemanager 的 Android 平台专用 service_contextservice_context 没有设备专用标签。
    • 必须位于 system 分区中的 /system/etc/selinux/plat_service_contexts 下,并由 servicemanager 在启动时加载(与供应商 service_contexts 一起加载)。
  • vendor_service_contexts
    • 设备专用 service_context,通过合并 service_contexts(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 必须位于 vendor 分区中的 /vendor/etc/selinux/vendor_service_contexts 下,并由 servicemanager 在启动时加载(与平台 service_contexts 一起加载)。
    • 虽然 servicemanager 会在启动时查找此文件,但对于完全兼容的 TREBLE 设备,vendor_service_contexts 绝不能存在。这是因为,vendorsystem 进程之间的所有交互都必须通过 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,通过合并 hwservice_contexts(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 必须位于 vendor 分区中的 /vendor/etc/selinux/vendor_hwservice_contexts 下,并由 hwservicemanager 在启动时加载(与 plat_service_contexts 一起加载)。
  • vndservice_contexts
    • vndservicemanager 的设备专用 service_context,通过合并 vndservice_contexts(位于设备的 Boardconfig.mk 中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 此文件必须位于 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. 下。
  • vendor_seapp_contexts
    • 平台 seapp_context 的设备专用扩展,通过合并 seapp_contexts(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 必须位于 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/. 下。
  • 非平台 mac_permissions.xml
    • 平台 mac_permissions.xml 的设备专用扩展,通过 mac_permissions.xml(位于设备的 Boardconfig.mk 文件中由 BOARD_SEPOLICY_DIRS 指向的目录下)进行构建。
    • 必须位于 vendor 分区中的 /vendor/etc/selinux/. 下。