本頁說明如何建構 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/sepolicy
BOARD_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_contexts
property_contexts
seapp_contexts
service_contexts
system/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_DIRS
policy
- 將公眾提供的政策納入供應商政策,並進行版本控管。
方法是使用產生的公開 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
。