init 进程具有几乎不受限制的权限,并可使用 system 分区和 vendor 分区中的输入脚本在启动过程中初始化系统。此访问权限会导致 Treble 系统/供应商拆分中出现巨大漏洞,因为供应商脚本可能会指示 init 访问不属于稳定系统-供应商 ABI(应用二进制接口)的文件、属性等。
供应商 init 已设计为使用单独的安全增强型 Linux (SELinux) 域 vendor_init
,以利用供应商专属权限来运行 /vendor
中的命令,从而填补此漏洞。
机制
供应商 init 会在启动过程的早期派生在 SELinux 环境 u:r:vendor_init:s0
中运行的 init 子进程。此 SELinux 环境具有的权限明显少于默认 init 环境,并且其访问权限仅限于供应商专用或属于稳定系统-供应商 ABI 的文件、属性等。
init 会检查它加载的每个脚本以查看其路径是否以 /vendor
开头,如果是,则添加标记以指示其命令必须在供应商 init 环境中运行。每个内置 init 都使用布尔值进行注解,该布尔值指定是否必须在供应商 init 子进程中运行相应命令:
- 访问文件系统的大多数命令都被注释为在供应商 init 子进程中运行,因此受供应商 init SEPolicy 的约束。
- 大多数会影响内部 init 状态的命令(例如,启动和停止服务)都在普通 init 进程中运行。这些命令能获知供应商脚本正在调用它们来处理它们自己的非 SELinux 权限。
init 的主处理循环包含一项检查,以检查是否会发生以下情况:如果某个命令被注解为在供应商子进程中运行并且源自供应商脚本,系统会通过进程间通信 (IPC) 将该命令发送到供应商 init 子进程,然后这个子进程会运行该命令并将结果发送回 init。
使用供应商 init
供应商 init 默认处于启用状态,其限制适用于 /vendor
分区中存在的所有 init 脚本。对于其脚本尚未访问系统专用文件、属性等的供应商,供应商 init 应该是透明的。
但是,如果给定供应商脚本中的命令违反了供应商 init 限制,这些命令将会失败。如果命令运行失败,系统会在 init 内核日志中记录一行(可通过 dmesg 查看)来指示其运行失败。因 SELinux 政策限制而运行失败的任何命令都会伴有 SELinux 审核。包含 SELinux 审核的失败示例如下:
type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm="init" name="nfc" dev="sda45" ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0 init: Command 'write /data/nfc/bad_file_access 1234' action=boot (/vendor/etc/init/hw/init.walleye.rc:422) took 2ms and failed: Unable to write to file '/data/nfc/bad_file_access': open() failed: Permission denied
如果某个命令运行失败,有两种选择:
- 如果该命令是因既有限制而运行失败(例如,如果该命令访问的是系统文件或属性),必须以适合 Treble 的方式重新实现该命令,并仅采用稳定的接口。neverallow 规则禁止添加访问不属于稳定系统-供应商 ABI 的系统文件的权限。
- 如果 SELinux 标签是新的且尚未在系统
vendor_init.te
中被授予权限,也未通过 neverallow 规则被排除权限,则可以在设备专用vendor_init.te
中为这个新标签授予权限。
对于搭载 Android 9 之前版本的设备,可以通过将 data_between_core_and_vendor_violators
类型属性添加到设备专用 vendor_init.te
文件来绕过 neverallows 规则。
代码位置
供应商 init IPC 的大部分逻辑都位于 system/core/init/subcontext.cpp 中。
命令表位于 system/core/init/builtins.cpp 中的 BuiltinFunctionMap
类中,其中包含用于指示是否必须在供应商 init 子进程中运行相应命令的注解。
供应商 init 的 SEPolicy 已被拆分到 system/sepolicy 中的私有目录 (system/sepolicy/private/vendor_init.te) 和公共目录 (system/sepolicy/public/vendor_init.te)。