制定 SELinux 政策

本文介紹了 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.imgboot.img ),然後獨立於平台更新來更新這些映像。

然而,由於模組化的 SELinux 策略檔案儲存在/vendor分區上,因此init進程必須提前掛載系統和供應商分區,以便它可以從這些分區讀取SELinux 檔案並將它們與系統目錄中的核心SELinux 檔案合併(然後將它們載入到核心)。

原始檔

建置 SELinux 的邏輯位於下列檔案中:

  • external/selinux :外部 SELinux 項目,用於建立 HOST 命令列實用程式來編譯 SELinux 策略和標籤。
  • system/sepolicy :核心 Android SELinux 政策配置,包含上下文和政策檔案。主要的sepolicy建置邏輯也在這裡( system/sepolicy/Android.mk )。

有關system/sepolicy Implementing 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/sepolicyBOARD_SEPOLICY_DIRS中的 file_contexts 檔案的內容串連起來在裝置上產生file_contexts.bin

此圖顯示了 Android 7.x 的 SELinux 建置邏輯。
圖1 。 SELinux 建構邏輯

sepolicy檔案由多個來源檔案組成:

  • 純文字policy.conf是透過依序連接security_classesinitial_sids*.te檔案、 genfs_contextsport_contexts來產生的。
  • 對於每個檔案(例如security_classes ),其內容是system/sepolicy/BOARDS_SEPOLICY_DIRS下同名檔案的串聯。
  • policy.conf傳送到SELinux編譯器進行語法檢查,並編譯成二進位格式作為裝置上的sepolicy
    此圖顯示了為 Android 7.x 產生 SELinux 策略檔案的檔案。
    圖2 . SELinux 策略文件

SELinux 文件

編譯後,執行 7.x 及更早版本的 Android 裝置通常包含以下 SELinux 相關檔案:

  • selinux_version
  • sepolicy:組合策略檔案後的二進位輸出(例如security_classesinitial_sids*.te
  • file_contexts
  • property_contexts
  • seapp_contexts
  • service_contexts
  • system/etc/mac_permissions.xml

有關更多詳細信息,請參閱實施 SELinux

SELinux 初始化

當系統啟動時,SELinux 處於寬容模式(而不是強制模式)。 init 行程執行以下任務:

  • 透過/sys/fs/selinux/loadsepolicy檔案從 ramdisk 載入到核心中。
  • 將 SELinux 切換到強制模式。
  • 執行re-exec()以將 SELinux 域規則套用至自身。

為了縮短啟動時間,請盡快對init進程執行re-exec()

安卓 8.0 及更高版本

在 Android 8.0 中,SELinux 策略分為平台和供應商元件,以允許獨立的平台/供應商策略更新,同時保持相容性。

平台 sepolicy 進一步分為平台私有部分和平台公共部分,以將特定類型和屬性匯出給供應商策略編寫者。平台公共類型/屬性保證作為給定平台版本的穩定 API 進行維護。使用平台映射檔案可以保證多個版本與先前平台公共類型/屬性的兼容性。

平台公共政策

平台 public sepolicy 包含system/sepolicy/public下定義的所有內容。平台可以假定公共政策下定義的類型和屬性是給定平台版本的穩定 API。這構成了由平台導出的 sepolicy 的一部分,供應商(即設備)策略開發人員可以在該平台上編寫其他特定於設備的策略。

類型根據寫入供應商文件的策略版本進行版本控制,由PLATFORM_SEPOLICY_VERSION建構變數定義。然後,版本化的公共策略包含在供應商策略中並(以其原始形式)包含在平台策略中。因此,最終策略包括私有平台策略、目前平台的公共策略、設備特定策略以及與編寫設備策略所針對的平台版本相對應的版本化公共策略。

平台隱私權政策

平台私有 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 和產品分區中。

私有原則包含 system_ext 和產品分區功能所需的僅限 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
  • 參考新增紅牛設備產品分區對映檔案的範例

    制定 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 及更高版本)奧德姆安全政策
    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 策略元件。步驟包括:

    1. 將策略轉換為 SELinux 通用中間語言 (CIL) 格式,具體來說:
      1. 公共平台政策(system + system_ext + 產品)
      2. 私人+公共政策結合
      3. 公共 + 供應商和BOARD_SEPOLICY_DIRS政策
    2. 對公眾提供的策略進行版本控制,作為供應商策略的一部分。透過使用產生的公共 CIL 策略來通知組合的公共 + 供應商 + BOARD_SEPOLICY_DIRS策略來完成哪些部分必須轉換為將連結到平台策略的屬性。
    3. 建立連結平台和供應商部件的對應檔案。最初,這只是將公共策略中的類型與供應商策略中的相應屬性連結起來;稍後,它還將為未來平台版本中維護的文件提供基礎,從而實現與針對該平台版本的供應商策略的兼容性。
    4. 組合策略檔案(描述裝置上和預編譯的解決方案)。
      1. 結合映射、平台和供應商政策。
      2. 編譯輸出二進位策略檔。

    預編譯 SELinux 策略

    init開啟SELinux之前, init會從分區( systemsystem_extproductvendorodm )收集所有CIL文件,並將它們編譯成二進位策略,也就是可以載入到核心的格式。由於編譯需要時間(通常為 1-2 秒),因此 CIL 檔案在建置時進行預編譯,並與 sha256 雜湊值一起放置在/vendor/etc/selinux/precompiled_sepolicy/odm/etc/selinux/precompiled_sepolicy輸入CIL 檔案的數量。在運行時, init透過比較雜湊值來檢查是否有任何策略檔案已更新。如果沒有任何變化, init將載入預編譯策略。如果沒有, init會動態編譯並使用它而不是預先編譯的。

    更具體地說,如果滿足以下所有條件,則使用預編譯策略。這裡, {partition}表示預編譯策略所在的分割區: vendorodm

    • /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