<devsite-heading text="供應商 init" for="%E4%BE%9B%E5%BA%94%E5%95%86-init" level="h1" class="devsite-page-title"># 供應商 init</devsite-heading>
init 進程具有幾乎不受限制的權限,并可使用系統(tǒng)分區(qū)和供應商分區(qū)中的輸入腳本在啟動過程中初始化系統(tǒng)。該訪問權限會導致 Treble 系統(tǒng)/供應商拆分中出現(xiàn)巨大漏洞,因為供應商腳本可能會指示 init 訪問不屬于穩(wěn)定系統(tǒng)-供應商 ABI(應用二進制接口)的文件、屬性等。
供應商 init 已設計為使用單獨的安全增強型 Linux (SELinux) 域 vendor_init,以利用供應商專屬權限來運行 /vendor 中的命令,從而填補此漏洞。
<devsite-heading text="機制" for="mechanism" level="h2" link="" toc="" class="" back-to-top="">## 機制</devsite-heading>
<devsite-heading text="機制" for="mechanism" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>
供應商 init 會在啟動過程的早期派生在 SELinux 環(huán)境 u:r:vendor_init:s0 中運行的 init 子進程。此 SELinux 環(huán)境具有的權限明顯少于默認 init 環(huán)境,并且其訪問權限僅限于供應商專用或屬于穩(wěn)定系統(tǒng)-供應商 ABI 的文件、屬性等。
Init 會檢查它加載的每個腳本以查看其路徑是否以 /vendor 開頭,如果是,則添加標記以指示其命令必須在供應商 init 環(huán)境中運行。每個內置 init 都使用布爾值進行注釋,該布爾值指定是否必須在供應商 init 子進程中運行相應命令:
- 訪問文件系統(tǒng)的大多數(shù)命令都被注釋為在供應商 init 子進程中運行,因此受供應商 init SEPolicy 的約束。
- 大多數(shù)會影響內部 init 狀態(tài)的命令(例如,啟動和停止服務)都在普通 init 進程中運行。這些命令能獲知供應商腳本正在調用它們來處理它們自己的非 SELinux 權限。
Init 的主處理循環(huán)包含一項檢查,以檢查是否會發(fā)生以下情況:如果某個命令被注釋為在供應商子進程中運行并且源自供應商腳本,則系統(tǒng)會通過進程間通信 (IPC) 將該命令發(fā)送到供應商 init 子進程,然后這個子進程會運行該命令并將結果發(fā)送回 init。
<devsite-heading text="使用供應商 init" for="using-vendor-init" level="h2" link="" toc="" class="" back-to-top="">## 使用供應商 init</devsite-heading> <devsite-heading text="使用供應商 init" for="using-vendor-init" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>
供應商 init 默認處于啟用狀態(tài),其限制適用于 /vendor 分區(qū)中存在的所有 init 腳本。對于其腳本尚未訪問系統(tǒng)專用文件、屬性等的供應商,供應商 init 應該是透明的。
但是,如果給定供應商腳本中的命令違反了供應商 init 限制,則這些命令將無法運行。如果命令運行失敗,系統(tǒng)會在 init 內核日志中記錄一行(可通過 dmesg 查看)來指示其運行失敗。因 SELinux 政策限制而運行失敗的任何命令都會伴有 SELinux 審核。包含 SELinux 審核的失敗示例如下:
<devsite-code no-copy=""><pre class="" is-upgraded="">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</pre></devsite-code>
如果某個命令運行失敗,則有兩種選擇:
- 如果該命令是因既有限制而運行失?。ɡ?,如果該命令訪問的是系統(tǒng)文件或屬性),則必須以適合 Treble 的方式重新實現(xiàn)該命令,并僅采用穩(wěn)定的接口。Neverallow 規(guī)則禁止添加訪問不屬于穩(wěn)定系統(tǒng)-供應商 ABI 的系統(tǒng)文件的權限。
- 如果 SELinux 標簽是新的且尚未在系統(tǒng)
vendor_init.te中為其授予權限,也未通過 neverallow 規(guī)則為其排除權限,則可以在設備專用vendor_init.te中為這個新標簽授予權限。
對于搭載 Android 9 之前版本的設備,可以通過將 data_between_core_and_vendor_violators 類型屬性添加到設備專用 vendor_init.te 文件來繞過 neverallows 規(guī)則。
<devsite-heading text="代碼位置" for="code-locations" level="h2" link="" toc="" class="" back-to-top="">## 代碼位置</devsite-heading>
<devsite-heading text="代碼位置" for="code-locations" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>
供應商 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)。