本頁說明如何建構 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 專案,用於建構主機指令列公用程式,以編譯 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 中的檔案,請參閱「實作 SELinux」。
Android 7.x 以下版本
本節說明如何在 Android 7.x 以下版本中建構 SELinux 政策。
Android 7.x 以下版本的建構程序
SELinux 政策是結合核心 AOSP 政策和裝置專屬自訂項目所建立。然後,系統會將合併後的政策傳遞至政策編譯器和各種檢查工具。裝置專屬自訂作業是透過裝置專屬 Boardconfig.mk 檔案中定義的 BOARD_SEPOLICY_DIRS 變數完成。這個全域建構變數包含目錄清單,指定搜尋其他政策檔案的順序。
舉例來說,SoC 供應商和 ODM 可能會各自新增一個目錄,一個用於 SoC 專屬設定,另一個用於裝置專屬設定,以便為特定裝置產生最終的 SELinux 設定:
BOARD_SEPOLICY_DIRS += device/SOC/common/sepolicyBOARD_SEPOLICY_DIRS += device/SoC/DEVICE/sepolicy
system/sepolicy 和 BOARD_SEPOLICY_DIRS 中的 file_contexts 檔案內容會串連,以在裝置上產生 file_contexts.bin:
圖 1. SELinux 建構邏輯。
sepolicy 檔案包含多個來源檔案:
- 純文字
policy.conf是依序串連security_classes、initial_sids、*.te檔案、genfs_contexts和port_contexts所產生。 - 每個檔案 (例如
security_classes) 的內容都是system/sepolicy/和BOARDS_SEPOLICY_DIRS底下同名檔案的串連。 policy.conf會傳送至 SELinux 編譯器進行語法檢查,並在裝置上編譯為sepolicy的二進位格式。
圖 2. SELinux 政策檔案。
SELinux 檔案
編譯後,搭載 Android 7.x 以下版本的裝置通常會包含下列 SELinux 相關檔案:
selinux_version- sepolicy:合併政策檔案後產生的二進位輸出內容 (例如
security_classes、initial_sids和*.te) file_contextsproperty_contextsseapp_contextsservice_contextssystem/etc/mac_permissions.xml
詳情請參閱「導入 SELinux」。
SELinux 初始化
系統啟動時,SELinux 會處於寬鬆模式 (而非強制執行模式)。初始化程序會執行下列工作:
- 透過
/sys/fs/selinux/load將sepolicy檔案從 RAM 磁碟載入核心。 - 將 SELinux 切換為強制執行模式。
- 執行
re-exec(),將 SELinux 網域規則套用至自身。
為縮短啟動時間,請盡快執行re-exec()init程序。
Android 8.0 以上版本
在 Android 8.0 中,SELinux 政策會分成平台和供應商元件,以便獨立更新平台/供應商政策,同時維持相容性。
平台 sepolicy 會進一步分割為平台私有和平台公開部分,以便將特定類型和屬性匯出給供應商政策撰寫者。平台公開型別/屬性保證會維持穩定 API 的狀態,適用於特定平台版本。使用平台對應檔案,即可確保多個版本與先前的平台公開類型/屬性相容。
Android 8.0 的建構程序
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 |
供應商 sepolicy |
BOARD_ODM_SEPOLICY_DIRS (Android 9 以上版本) |
Odm sepolicy |
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_ext、產品、供應商和 ODM 政策元件。步驟如下:
- 將政策轉換為 SELinux Common Intermediate Language (CIL) 格式,具體來說:
- 公開平台政策 (system + system_ext + product)
- 私人和公共政策合併
- public + vendor 和
BOARD_SEPOLICY_DIRSpolicy
- 將公眾提供的政策納入供應商政策,並進行版本控管。
方法是使用產生的公開 CIL 政策,告知合併的公開 + 廠商 +
BOARD_SEPOLICY_DIRS政策,哪些部分必須轉換為將連結至平台政策的屬性。 - 建立對應檔案,連結平台和供應商零件。 一開始,這只會將公開政策中的型別與供應商政策中的對應屬性連結;之後,這也會成為未來平台版本中維護檔案的基礎,確保與指定這個平台版本的供應商政策相容。
- 合併政策檔案 (說明裝置端和預先編譯的解決方案)。
- 合併對應、平台和供應商政策。
- 編譯輸出二進位政策檔案。
平台 public sepolicy
平台公開 sepolicy 包含
system/sepolicy/public 下定義的所有項目。平台可以假設公用政策中定義的型別和屬性,是特定平台版本的穩定 API。這會形成平台匯出的 sepolicy 一部分,供應商 (即裝置) 政策開發人員可在此撰寫其他裝置專屬政策。
類型會根據供應商檔案編寫時所依據的政策版本進行版本控管,並由 PLATFORM_SEPOLICY_VERSION 建構變數定義。然後,版本化的公開政策會納入供應商政策,並以原始形式納入平台政策。因此,最終政策包含私有平台政策、目前平台的公開安全政策、裝置專屬政策,以及與裝置政策編寫時所用平台版本對應的版本化公開政策。
平台私有 sepolicy
平台私有 sepolicy 包含
/system/sepolicy/private 下定義的所有項目。這部分政策會說明平台功能所需的平台專屬類型、權限和屬性。這些內容不會匯出給 vendor/device 政策撰寫者。非平台政策撰寫者不得根據平台私有 sepolicy 中定義的類型/屬性/規則,撰寫政策擴充功能。此外,這些規則可能會在僅限架構的更新中修改或消失。
平台私人對應
平台私有對應包含政策聲明,可將先前平台版本平台公開政策中公開的屬性,對應至目前平台公開 sepolicy 中使用的具體型別。這樣可確保根據先前平台公開 sepolicy 版本撰寫的供應商政策,能繼續運作。版本控管是根據特定平台版本的 Android 開放原始碼計畫中設定的 PLATFORM_SEPOLICY_VERSION 建構變數。每個先前平台版本都有個別的對應檔案,這個平台預計會接受這些版本供應商的政策。詳情請參閱「相容性」。
Android 11 以上版本
system_ext 和產品 sepolicy
Android 11 新增了 system_ext 政策和產品政策。與平台政策類似,system_ext 政策和產品政策會分為公開政策和私有政策。
公開政策會匯出給供應商。類型和屬性會成為穩定的 API,且供應商政策可參照公開政策中的類型和屬性。類型會根據 PLATFORM_SEPOLICY_VERSION 進行版本控管,且版本控管的政策會納入供應商政策。每個 system_ext 和產品分割區都包含原始政策。
私有政策包含 system_ext-only 和 product-only 類型、權限,以及 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。
請參閱範例,瞭解如何新增 redbull 裝置產品區隔的對應檔案。
預先編譯的 SELinux 政策
init 開啟 SELinux 前,會先從各個分割區 (system、system_ext、product、vendor 和 odm) 收集所有 CIL 檔案,並編譯成二進位政策,這種格式可載入核心。init由於編譯需要時間 (通常為 1 到 2 秒),CIL 檔案會在建構時預先編譯,並放置在 /vendor/etc/selinux/precompiled_sepolicy 或 /odm/etc/selinux/precompiled_sepolicy,以及輸入 CIL 檔案的 sha256 雜湊。在執行階段,init 會比較雜湊,檢查是否有任何政策檔案已更新。如果沒有任何變更,init 會載入預先編譯的政策。如果沒有,init 會即時編譯,並使用該編譯結果,而非預先編譯的結果。
具體來說,如果符合下列所有條件,系統就會使用預先編譯的政策。其中,{partition} 代表預先編譯政策所在的分割區:vendor 或 odm。
-
/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」都不存在。或兩者皆存在且相同。
如果其中任何一項不同,init 就會改用裝置端編譯路徑。詳情請參閱
system/core/init/selinux.cpp。