本文介紹瞭如何構建 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 項目,用於構建 HOST 命令行實用程序以編譯 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.0 及更早版本
本節介紹如何在 Android 7.x 及更早版本中構建 SELinux 策略。
構建 SELinux 策略
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
:
sepolicy
文件由多個源文件組成:
- 純文本
policy.conf
是通過依次連接security_classes
、initial_sids
、*.te
文件、genfs_contexts
和port_contexts
的。 - 對於每個文件(例如
security_classes
),其內容是system/sepolicy/
和BOARDS_SEPOLICY_DIRS
下同名文件的串聯。 -
policy.conf
被發送到 SELinux 編譯器進行語法檢查並編譯為二進制格式作為設備上的sepolicy
。
SELinux 文件
編譯後,運行 7.x 及更早版本的 Android 設備通常包含以下 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 處於許可模式(而不是強制模式)。 init 進程執行以下任務:
- 通過
/sys/fs/selinux/load
將sepolicy
文件從 ramdisk 加載到內核中。 - 將 SELinux 切換到強制模式。
- 運行
re-exec()
以將 SELinux 域規則應用於自身。
要縮短啟動時間,請盡快對init
進程執行re-exec()
。
Android 8.0 及更高版本
在 Android 8.0 中,SELinux 策略分為平台和供應商組件,以允許獨立的平台/供應商策略更新,同時保持兼容性。
平台 sepolicy 進一步分為平台私有和平台公共部分,以將特定類型和屬性導出給供應商策略編寫者。保證平台公共類型/屬性作為給定平台版本的穩定 API 進行維護。使用平台映射文件可以保證多個版本與以前的平台公共類型/屬性的兼容性。
平台公共政策
平台公共 sepolicy 包括在system/sepolicy/public
下定義的所有內容。平台可以假設公共政策下定義的類型和屬性是給定平台版本的穩定 API。這構成了平台導出的 sepolicy 的一部分,供應商(即設備)策略開發人員可以在該平台上編寫額外的設備特定策略。
類型根據編寫供應商文件的策略版本進行版本控制,由PLATFORM_SEPOLICY_VERSION
構建變量定義。然後,版本化的公共政策包含在供應商政策中,並(以其原始形式)包含在平台政策中。因此,最終策略包括私有平台策略、當前平台的公共 sepolicy、特定於設備的策略以及與編寫設備策略的平台版本相對應的版本化公共策略。
平台私有sepolicy
平台私有 sepolicy 包括/system/sepolicy/private
下定義的所有內容。這部分策略形成平台功能所需的純平台類型、權限和屬性。這些不會導出到vendor/device
策略編寫者。非平台策略編寫者不得根據平台私有 sepolicy 中定義的類型/屬性/規則編寫策略擴展。此外,這些規則可以被修改或作為僅框架更新的一部分消失。
平台私有映射
平台私有映射包括將先前平台版本的平台公共策略中暴露的屬性映射到當前平台公共sepolicy中使用的具體類型的策略語句。這可確保基於先前平台公共 sepolicy 版本中的平台公共屬性編寫的供應商策略繼續有效。版本控制基於 AOSP 中為給定平台版本設置的PLATFORM_SEPOLICY_VERSION
構建變量。每個先前的平台版本都存在一個單獨的映射文件,該平台預期從該版本接受供應商策略。有關更多詳細信息,請參閱兼容性。
Android 11 及更高版本
system_ext 和產品 sepolicy
在 Android 11 中,添加了 system_ext 策略和產品策略。與平台 sepolicy 一樣,system_ext 策略和產品策略也分為公共策略和私有策略。
公共政策被導出到供應商。類型和屬性成為穩定的 API,供應商策略可以參考公共策略中的類型和屬性。類型根據PLATFORM_SEPOLICY_VERSION
進行版本控制,並且版本控制策略包含在供應商策略中。原始策略包含在每個 system_ext 和 product 分區中。
私有策略包含 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 通用中間語言 (CIL) 格式,具體而言:
- 公共平台策略(system + system_ext + product)
- 私人+公共政策相結合
- 公共 + 供應商和
BOARD_SEPOLICY_DIRS
政策
- 作為供應商政策的一部分,對公眾提供的政策進行版本控制。通過使用生成的公共 CIL 策略通知組合的公共 + 供應商 +
BOARD_SEPOLICY_DIRS
策略,哪些部分必須轉換為將鏈接到平台策略的屬性來完成。 - 創建鏈接平台和供應商部件的映射文件。最初,這只是將公共策略中的類型與供應商策略中的相應屬性聯繫起來;稍後它還將為在未來平台版本中維護的文件提供基礎,從而與針對該平台版本的供應商政策兼容。
- 組合策略文件(描述設備上和預編譯的解決方案)。
- 結合映射、平台和供應商政策。
- 編譯輸出二進制策略文件。
-
/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
都不存在。或者兩者都存在並且相同。
構建 SELinux 策略
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 | 供應商政策 |
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、system_ext、product、vendor 和 odm 策略組件。步驟包括:
預編譯的 SELinux 策略
在init
打開 SELinux 之前, init
從分區( system
、 system_ext
、 product
、 vendor
和odm
)收集所有 CIL 文件並將它們編譯成二進制策略,該格式可以加載到內核中。由於編譯需要時間(通常為 1-2 秒),因此 CIL 文件在構建時進行預編譯,並與 sha256 哈希一起放置在/vendor/etc/selinux/precompiled_sepolicy
或/odm/etc/selinux/precompiled_sepolicy
中的輸入 CIL 文件。在運行時, init
通過比較哈希值來檢查是否有任何策略文件已更新。如果沒有任何變化, init
會加載預編譯的策略。如果沒有, init
會即時編譯並使用它而不是預編譯的。
更具體地說,如果滿足以下所有條件,則使用預編譯策略。這裡, {partition}
表示預編譯策略所在的分區: vendor
或odm
。
如果其中任何一個不同, init
將退回到設備上的編譯路徑。有關更多詳細信息,請參見system/core/init/selinux.cpp
。