實作 SELinux

SELinux 的預設設定為「拒絕」,也就是說,每個在核心中具有掛鉤的存取權,都必須由政策明確允許。也就是說,政策檔案包含大量關於規則、類型、類別、權限等的資訊。完整考量 SELinux 的範圍超出本文件的範圍,但在啟用新 Android 裝置時,瞭解如何編寫政策規則是必要的。目前已有許多關於 SELinux 的資訊。如需建議的資源,請參閱支援文件

金鑰檔案

如要啟用 SELinux,請整合最新的 Android 核心,然後納入 system/sepolicy 目錄中找到的檔案。編譯時,這些檔案會包含 SELinux 核心安全性政策,並涵蓋上游 Android 作業系統。

一般來說,您不應直接修改 system/sepolicy 檔案。請改為在 /device/manufacturer/device-name/sepolicy 目錄中新增或編輯專屬的裝置政策檔案。在 Android 8.0 以上版本中,您對這些檔案所做的變更應只會影響供應商目錄中的政策。如要進一步瞭解在 Android 8.0 以上版本中分隔公開的 sepolicy,請參閱「在 Android 8.0 以上版本中自訂 SEPolicy」。無論 Android 版本為何,您仍需修改下列檔案:

政策檔案

結尾為 *.te 的檔案是 SELinux 政策來源檔案,用於定義網域及其標籤。您可能需要在 /device/manufacturer/device-name/sepolicy 中建立新的政策檔案,但請盡可能更新現有檔案。

背景資訊檔案

您可以在背景資訊檔案中指定物件的標籤。

  • file_contexts 會為檔案指派標籤,並由各種使用者空間元件使用。建立新政策時,請建立或更新這個檔案,為檔案指派新標籤。如要套用新的 file_contexts,請重新建構檔案系統映像檔,或在要重新標記的檔案上執行 restorecon。升級時,系統會自動將 file_contexts 的變更套用至系統和 userdata 分割區,作為升級的一部分。在分區掛載為讀寫模式後,您也可以在升級至其他分區時自動套用變更,方法是在 init.board.rc 檔案中新增 restorecon_recursive 呼叫。
  • genfs_contexts 會將標籤指派給不支援擴充屬性的檔案系統,例如 procvfat。這項設定會在核心政策中載入,但可能不會對核心內的 inode 生效,因此需要重新啟動或卸載及重新掛載檔案系統,才能完全套用變更。您也可以使用 context=mount 選項,將特定標籤指派給特定掛載點,例如 vfat
  • property_contexts 會將標籤指派給 Android 系統屬性,以便控管哪些程序可以設定這些屬性。這項設定會在啟動期間由 init 程序讀取。
  • service_contexts 會將標籤指派給 Android 繫結器服務,以控管哪些程序可以新增 (註冊) 及查找 (查詢) 服務的繫結器參照。這項設定會在啟動期間由 servicemanager 程序讀取。
  • seapp_contexts 會為應用程式程序和 /data/data 目錄指派標籤。每次啟動應用程式時,zygote 程序會讀取這項設定,installd 也會在啟動期間讀取這項設定。
  • mac_permissions.xml 會根據應用程式的簽名和選用的套件名稱,為應用程式指派 seinfo 標記。seinfo 標記可用於 seapp_contexts 檔案中的鍵,為所有具有該 seinfo 標記的應用程式指派特定標籤。這項設定會在啟動期間由 system_server 讀取。
  • keystore2_key_contexts 會為 Keystore 2.0 命名空間指派標籤。這些命名空間是由 KeyStore2 守護程序強制執行。KeyStore 一向提供以 UID/AID 為基礎的命名空間。Keystore 2.0 也會強制執行 sepolicy 定義的命名空間。如要進一步瞭解這個檔案的格式和慣例,請參閱這篇文章

BoardConfig.mk makefile

編輯或新增政策和內容檔案後,請更新 /device/manufacturer/device-name/BoardConfig.mk 的 makefile,以便參照 sepolicy 子目錄和每個新的政策檔案。如要進一步瞭解 BOARD_SEPOLICY 變數,請參閱 system/sepolicy/README 檔案

BOARD_SEPOLICY_DIRS += \
        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_UNION += \
        genfs_contexts \
        file_contexts \
        sepolicy.te

重建後,裝置就會啟用 SELinux。您現在可以自訂 SELinux 政策,以便根據「自訂」一節所述,為 Android 作業系統新增自訂項目,或是根據「驗證」一節所述,驗證現有設定。

新政策檔案和 BoardConfig.mk 更新完成後,系統會自動將新政策設定建構至最終核心政策檔案。如要進一步瞭解如何在裝置上建構 sepolicy,請參閱「建構 sepolicy」。

實作

如要開始使用 SELinux,請按照下列步驟操作:

  1. 在核心中啟用 SELinux: CONFIG_SECURITY_SELINUX=y
  2. 變更 kernel_cmdline 或 bootconfig 參數,以便:
    BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
    BOARD_BOOTCONFIG := androidboot.selinux=permissive
    這項參數僅供裝置政策的初始開發作業使用。建立初始引導政策後,請移除這個參數,以便裝置強制執行或通過 CTS。
  3. 以寬鬆模式啟動系統,查看開機時遇到的拒絕:
    在 Ubuntu 14.04 以上版本中:
    adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
    
    在 Ubuntu 12.04 上:
    adb pull /sys/fs/selinux/policy
    adb logcat -b all | audit2allow -p policy
    
  4. 評估輸出內容是否有類似 init: Warning! Service name needs a SELinux domain defined; please fix! 的警告。如需操作說明和工具,請參閱「驗證」。
  5. 找出需要標示的裝置和其他新檔案。
  6. 為物件使用現有或新的標籤。查看 *_contexts 檔案,瞭解先前如何標示項目,並利用標籤含義的知識指派新標籤。理想情況下,這是符合政策的現有標籤,但有時需要新標籤,並且需要該標籤的存取規則。將標籤新增至適當的內容檔案。
  7. 找出應有專屬安全性網域的網域/程序。 您可能需要為每個網域撰寫全新的政策。舉例來說,從 init 衍生的所有服務都應有自己的 下列指令可協助您找出仍在執行的服務 (但所有服務都需要這類處理方式):
    adb shell su -c ps -Z | grep init
    
    adb shell su -c dmesg | grep 'avc: '
    
  8. 檢查 init.device.rc,找出沒有網域類型的網域。在開發過程中盡早為其提供網域,以免在 init 上新增規則,或將 init 存取權與其自身政策中的存取權混淆。
  9. 設定 BOARD_CONFIG.mk 以使用 BOARD_SEPOLICY_* 變數。如要進一步瞭解如何設定這項功能,請參閱 system/sepolicy 中的 README
  10. 檢查 init.device.rc 和 fstab.device 檔案,並確認每次使用 mount 都對應至正確標示的檔案系統,或指定 context= mount 選項。
  11. 請逐一查看拒絕原因,並建立 SELinux 政策來妥善處理。請參閱「自訂」中的範例。

您應先採用 AOSP 中的政策,然後再根據這些政策進行自訂。如要進一步瞭解政策策略,並深入探討其中一些步驟,請參閱「撰寫 SELinux 政策」。

用途

以下是製作自有軟體和相關 SELinux 政策時,應考慮的特定漏洞利用方法:

符號連結:符號連結會顯示為檔案,因此系統經常會將其視為檔案,進而導致漏洞攻擊。舉例來說,某些具權限的元件 (例如 init) 會變更特定檔案的權限,有時會過度開放。

攻擊者可能會將這些檔案替換為他們控制的程式碼的符號連結,讓攻擊者能夠覆寫任意檔案。不過,如果您知道應用程式從未遍歷符號連結,可以使用 SELinux 禁止這項操作。

系統檔案:請考量系統檔案的類別,這些檔案應僅由系統伺服器修改。不過,由於 netdinitvold 是以 root 身分執行,因此可以存取這些系統檔案。因此,如果 netd 遭到入侵,可能會危害這些檔案,甚至是系統伺服器本身。

您可以使用 SELinux 將這些檔案標示為系統伺服器資料檔案。因此,只有系統伺服器有讀取/寫入存取權。即使 netd 遭到入侵,也無法切換至系統伺服器網域,並以 root 權限存取這些系統檔案。

應用程式資料:另一個例子是必須以 root 權限執行,但不應存取應用程式資料的函式類別。這項功能非常實用,因為您可以提出廣泛的斷言,例如禁止與應用程式資料無關的特定網域存取網際網路。

setattr:針對 chmodchown 等指令,您可以指出相關聯的網域可執行 setattr 的檔案組合。任何超出此範圍的變更都可能遭到禁止,即使是使用 root 權限也一樣。因此,應用程式可能會針對標示為 app_data_files 的裝置執行 chmodchown,但不會針對 shell_data_filessystem_data_files 執行。