政策相容性

本頁說明 Android 如何處理平台無線 (OTA) 更新的政策相容性問題,因為新的平台 SELinux 設定可能與舊的供應商 SELinux 設定不同。

物件擁有權和標籤

每個物件都必須明確定義擁有權,才能將平台和供應商政策分開。舉例來說,如果供應商政策標籤 /dev/foo 和平台政策標籤 /dev/foo 在後續的 OTA 中,有未定義的行為 (例如意外拒絕),或更嚴重的是啟動失敗,在 SELinux 中,這會顯示為標籤衝突。裝置節點只能有一個標籤,該標籤會解析為最後套用的標籤。因此:

  • 需要存取未成功套用標籤的程序會失去資源存取權。
  • 取得檔案存取權的程序可能會中斷,因為建立的裝置節點有誤。

凡是具有 SELinux 標籤的物件 (包括屬性、服務、程序、檔案和通訊端),都可能發生平台與供應商標籤之間的衝突。為避免發生這些問題,請清楚定義這些物件的擁有權。

型別/屬性命名空間

除了標籤衝突外,SELinux 類型和屬性名稱也可能發生衝突。SELinux 不允許重複宣告相同型別和屬性。如果政策含有重複的聲明,編譯就會失敗。為避免型別和屬性名稱發生衝突,強烈建議所有供應商宣告都以 vendor_ 前置半形字元開頭。舉例來說,供應商應使用 type vendor_foo, domain;,而非 type foo, domain;

檔案擁有權

由於平台和供應商政策通常會為所有檔案系統提供標籤,因此要避免檔案發生衝突並不容易。與型別命名不同,檔案的命名空間並不實用,因為其中許多檔案都是由核心建立。為避免發生這類衝突,請按照本節的檔案系統命名指引操作。如果是 Android 8.0,這些是建議,並無技術上的強制規定。日後,供應商測試套件 (VTS) 將會強制執行這些建議。

系統 (/system)

只有系統映像檔必須透過 file_contextsservice_contexts 等為 /system 元件提供標籤。如果在供應商政策中加入 /system 元件的標籤,可能無法進行僅限架構的 OTA 更新。

供應商 (/vendor)

AOSP SELinux 政策已標記平台互動的 vendor 分區部分,因此可為平台程序編寫 SELinux 規則,以便與 vendor 分區部分通訊或存取這些部分。範例:

/vendor path 平台提供的標籤 平台程序 (視標籤而定)
/vendor(/.*)? vendor_file 架構中的所有 HAL 用戶端,例如 ueventd
/vendor/framework(/.*)? vendor_framework_file dex2oatappdomain 等。
/vendor/app(/.*)? vendor_app_file dex2oatinstalldidmap 等。
/vendor/overlay(/.*) vendor_overlay_file system_serverzygoteidmap 等。

因此,在 vendor 分區中標記其他檔案時,必須遵守特定規則 (透過 neverallows 強制執行):

  • vendor_file 必須是 vendor 分區中所有檔案的預設標籤。平台政策規定必須這樣做,才能存取直通 HAL 實作項目。
  • 透過供應商政策在 vendor 分區中新增的所有 exec_types 都必須具備 vendor_file_type 屬性。這項限制會透過 neverallow 強制執行。
  • 為避免日後與平台/架構更新發生衝突,請勿在 vendor 分區中標記 exec_types 以外的檔案。
  • 針對 AOSP 識別的相同程序 HAL,所有程式庫依附元件都必須標示為 same_process_hal_file.

Procfs (/proc)

/proc 中的檔案只能使用 genfscon 標籤標示。在 Android 7.0 中,平台供應商政策都使用 genfsconprocfs 中的檔案加上標籤。

建議:僅限平台政策標籤 /proc。 如果供應商程序需要存取 /proc 中的檔案,且這些檔案目前標示為預設標籤 (proc),供應商政策不應明確標示這些檔案,而應使用一般 proc 類型,為供應商網域新增規則。這樣一來,平台更新就能配合日後透過 procfs 公開的 Kernel 介面,並視需要明確標示。

Debugfs (/sys/kernel/debug)

Debugfs 可在 file_contextsgenfscon 中加上標籤。在 Android 7.0 至 Android 10 中,平台和供應商標籤都是 debugfs

在 Android 11 中,debugfs 無法在正式版裝置上存取或掛接。裝置製造商應移除 debugfs

Tracefs (/sys/kernel/debug/tracing)

Tracefs 可在 file_contextsgenfscon 中加上標籤。在 Android 7.0 中,只有平台標籤 tracefs

建議:只有平台可以標示 tracefs

Sysfs (/sys)

/sys 中的檔案可能會同時使用 file_contextsgenfscon 標示。在 Android 7.0 中,平台和供應商都會使用 genfsconsysfs 中的檔案加上標籤。

建議:平台可能會標示非裝置專用的 sysfs 節點。否則只有供應商可以標記檔案。

tmpfs (/dev)

/dev 中的檔案可能會在 file_contexts 中加上標籤。在 Android 7.0 中,平台和供應商標籤檔案都位於此處。

最佳化建議:供應商只能標記 /dev/vendor 中的檔案 (例如 /dev/vendor/foo/dev/vendor/socket/bar)。

Rootfs (/)

/ 中的檔案可能會在 file_contexts 中加上標籤。在 Android 7.0 中,平台和供應商標籤檔案都位於此處。

建議:只有系統可以在 / 中標示檔案。

資料 (/data)

資料標記方式是結合 file_contextsseapp_contexts

最佳化建議:禁止在外部使用供應商標籤。 /data/vendor只有平台可以標記 /data 的其他部分。

Genfs 標籤版本

2025 年 4 月的供應商 API 級別開始,使用 genfsconsystem/sepolicy/compat/plat_sepolicy_genfs_ver.cil 中指派的較新 SELinux 標籤,對於舊版 vendor 分割區為選用項目。這樣一來,舊版 vendor 分區就能保留現有的 SEPolicy 實作項目。這項設定由 Makefile 變數 BOARD_GENFS_LABELS_VERSION 控制,該變數儲存在 /vendor/etc/selinux/genfs_labels_version.txt 中。

範例:

  • 在供應商 API 級別 202404 中,/sys/class/udc 節點預設標示為 sysfs
  • 從供應商 API 級別 202504 開始,/sys/class/udc 會標示為 sysfs_udc

不過,/sys/class/udc 可能會由使用 API 層級 202404 的vendor分區使用,無論是預設的 sysfs 標籤或供應商專屬標籤都可能。無條件將 /sys/class/udc 標示為 sysfs_udc 可能會導致與這些 vendor 分區不相容。勾選 BOARD_GENFS_LABELS_VERSION 後,平台會繼續使用舊版 vendor 分區的標籤和權限。

BOARD_GENFS_LABELS_VERSION 可以大於或等於供應商 API 級別。舉例來說,使用 API 級別 202404 的 vendor 分區可以將 BOARD_GENFS_LABELS_VERSION 設為 202504,採用 202504 推出的新標籤。請參閱 202504 專屬 genfs 標籤清單。

標記 genfscon 節點時,平台必須考量舊版 vendor 分區,並視需要導入相容性備援機制。平台可以使用平台專屬程式庫查詢 genfs 標籤版本。

平台公共政策

平台 SELinux 政策分為私有和公開。平台公開政策包含的類型和屬性一律適用於供應商 API 層級,可做為平台和供應商之間的 API。這項政策會提供給供應商政策撰寫者,讓供應商建構供應商政策檔案,並與平台專屬政策合併,為裝置產生完整運作的政策。平台公開政策定義於 system/sepolicy/public

舉例來說,在供應商的環境中,代表初始化程序的 vendor_init 類型定義於 system/sepolicy/public/vendor_init.te 下方:

type vendor_init, domain;

供應商可以參考 vendor_init 型別,編寫自訂政策規則:

# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)

相容性屬性

SELinux 政策是來源和目標類型之間,針對特定物件類別和權限的互動。受 SELinux 政策影響的每個物件 (例如程序、檔案) 只能有一種型別,但該型別可能有多個屬性。

這項政策主要以現有類型撰寫,這裡的 vendor_initdebugfs 都是型別:

allow vendor_init debugfs:dir { mounton };

這是因為政策是根據所有型別編寫而成。不過,如果供應商政策和平台政策使用特定類型,且特定物件的標籤只在其中一項政策中變更,另一項政策可能包含先前獲得或失去存取權的政策。舉例來說,假設平台政策將 sysfs 節點標示為 sysfs

/sys(/.*)? u:object_r:sysfs:s0

供應商政策會授予 /sys/usb 的存取權,標示為: sysfs

allow vendor_init sysfs:chr_file rw_file_perms;

如果平台政策變更為將 /sys/usb 標示為 sysfs_usb,供應商政策會維持不變,但由於缺少新 sysfs_usb 類型的政策,vendor_init 會失去 /sys/usb 的存取權:

/sys/usb u:object_r:sysfs_usb:s0

為解決這個問題,Android 導入了版本化屬性的概念。在編譯期間,建構系統會自動將供應商政策中使用的平台公開型別,轉換為這些已加入版本的屬性。這項翻譯功能會透過對應檔案啟用,將已加上版本的屬性與平台的一或多個公開類型建立關聯。

舉例來說,假設 /sys/usb 標示為 sysfs,且 2025 年 4 月的供應商政策授予 vendor_init 存取 /sys/usb 的權限。在這種情況下:

  • 供應商政策會寫入規則 allow vendor_init sysfs:chr_file rw_file_perms;,因為 /sys/usb 在 202504 平台政策中標示為 sysfs。建構系統編譯供應商政策時,會自動將規則轉換為 allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;。屬性 vendor_init_202504sysfs_202504 分別對應至 vendor_initsysfs 類型,這些是平台定義的類型。
  • 建構系統會產生識別資訊對應檔 /system/etc/selinux/mapping/202504.cil。由於 systemvendor 分區都使用相同的 202504 版本,因此對應檔案包含從 type_202504type 的身分對應。舉例來說,vendor_init_202504 對應至 vendor_initsysfs_202504 對應至 sysfs
    (typeattributeset sysfs_202504 (sysfs))
    (typeattributeset vendor_init_202504 (vendor_init))
    ...

當版本從 202504 升級至 202604 時,系統會在 system/sepolicy/private/compat/202504/202504.cil 下建立 202504 vendor 分區的新對應檔案,並安裝至 202604 或更新版本 system 分區的 /system/etc/selinux/mapping/202504.cil。如先前所述,這個對應檔案一開始會包含身分對應。如果 202604 平台政策新增 sysfs_usb 的標籤 /sys/usb,對應檔案會更新,將 sysfs_202504 對應至 sysfs_usb

(typeattributeset sysfs_202504 (sysfs sysfs_usb))
(typeattributeset vendor_init_202504 (vendor_init))
...

這項更新可讓轉換後的供應商政策規則 allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms; 自動授予新 sysfs_usb 類型的存取權 vendor_init

為維持與舊版 vendor 分區的相容性,每當新增公開型別時,該型別必須對應至對應檔案 system/sepolicy/private/compat/ver/ver.cil 中的至少一個版本化屬性,或列於 system/sepolicy/private/compat/ver/ver.ignore.cil 下方,說明先前供應商版本中沒有相符的型別。

平台政策、供應商政策和對應檔案的組合,可讓系統在不更新供應商政策的情況下進行更新。此外,系統會自動將屬性轉換為版本化屬性,因此供應商政策不必處理版本化作業,可繼續使用公開型別。

system_ext 公開和產品公開政策

從 Android 11 開始,system_extproduct 分區可將指定公開型別匯出至 vendor 分區。與平台公開政策相同,供應商政策會使用自動轉換為版本化屬性的類型和規則,例如從 type 轉換為 type_ver,其中 vervendor 分區的供應商 API 層級。

如果 system_extproduct 分區是根據相同的平台版本 ver,建構系統會產生基本對應檔案至 system_ext/etc/selinux/mapping/ver.cilproduct/etc/selinux/mapping/ver.cil,其中包含從 typetype_ver 的身分對應。供應商政策可透過版本化屬性 type_ver 存取 type

如果只更新 system_extproduct 分區 (例如從 ver 更新至 ver+1 或更新版本),但 vendor 分區仍為 ver,供應商政策可能會失去 system_extproduct 分區的存取權。為避免中斷,system_extproduct 分區應提供從具體型別到 type_ver 屬性的對應檔案。如果合作夥伴支援 ver vendor 分區 (使用 ver+1 或更新版本 system_extproduct 分區),則須負責維護對應檔案。

如要將對應檔案安裝至 system_extproduct 分區,裝置實作人員或供應商應採取下列行動:

  1. ver system_extproduct 分區 將產生的基本對應檔案複製到來源樹狀結構
  2. 視需要修改對應檔案。
  3. 將對應檔案安裝至 ver+1 (或更新版本) 和 product 分割區。system_ext

舉例來說,假設 202504 system_ext 分區有一個名為 foo_type 的公開型別。然後,202504 system_ext 分區中的 system_ext/etc/selinux/mapping/202504.cil 會如下所示:

(typeattributeset foo_type_202504 (foo_type))
(expandtypeattribute foo_type_202504 true)
(typeattribute foo_type_202504)

如果 bar_type 已新增至 202604 system_ext,且 bar_type 應對應至 202504 foo_type 分區,則 202504.cil 可從 (typeattributeset foo_type_202504 (foo_type)) 更新至 (typeattributeset foo_type_202504 (foo_type bar_type)),然後安裝至 202604 system_ext 分區。vendor202504 vendor 分區可以繼續存取 202604 system_extfoo_typebar_type

Android 9 的屬性變更

升級至 Android 9 的裝置可以使用下列屬性,但搭載 Android 9 的裝置不得使用。

違規者屬性

Android 9 包含下列網域相關屬性:

  • data_between_core_and_vendor_violators. 所有網域的屬性,這些網域違反不得在 vendorcoredomains 之間透過路徑共用檔案的規定。平台和供應商程序不應使用磁碟上的檔案進行通訊 (ABI 不穩定)。建議:
    • 供應商代碼應使用 /data/vendor
    • 系統不應使用 /data/vendor
  • system_executes_vendor_violators所有系統網域 (initshell domains 除外) 的屬性,都違反不得執行供應商二進位檔的規定。執行供應商二進位檔時,API 不穩定。平台不應直接執行供應商二進位檔。建議:
    • 這類對供應商二進位檔的平台依附元件必須位於 HIDL HAL 後方。

    • coredomains 需要存取供應商二進位檔的 vendor 應移至 coredomain 分區,並停止成為 coredomains

不受信任的屬性

代管任意程式碼的不受信任應用程式不應存取 HwBinder 服務,但可存取被視為足夠安全,可供這類應用程式存取的服務 (請參閱下方的安全服務)。主要原因有二:

  1. HwBinder 伺服器不會執行用戶端驗證,因為 HIDL 目前不會公開呼叫端 UID 資訊。即使 HIDL 確實公開這類資料,許多 HwBinder 服務不是在應用程式層級以下運作 (例如 HAL),就是不得依據應用程式 ID 進行授權。因此,為確保安全,預設假設是每個 HwBinder 服務都會將所有用戶端視為同樣有權執行服務提供的作業。
  2. HAL 伺服器 (HwBinder 服務的子集) 包含的程式碼,安全問題發生率高於 system/core 元件,且可存取堆疊的較低層 (一路到硬體),因此增加規避 Android 安全性模型的機會。

安全服務

安全服務包括:

  • same_process_hwservice。這些服務 (依定義) 會在用戶端的程序中執行,因此與程序執行的用戶端網域具有相同的存取權。
  • coredomain_hwservice。這些服務不會造成與原因 #2 相關的風險。
  • hal_configstore_ISurfaceFlingerConfigs。這項服務專為任何網域設計。
  • hal_graphics_allocator_hwservice。這些作業也由 surfaceflinger Binder 服務提供,應用程式可存取這項服務。
  • hal_omx_hwservice。這是 mediacodec Binder 服務的 HwBinder 版本,應用程式可存取此服務。
  • hal_codec2_hwservice。這是 hal_omx_hwservice 的新版本。

可用的屬性

所有不安全的 hwservices 都具有 untrusted_app_visible_hwservice 屬性。對應的 HAL 伺服器具有 untrusted_app_visible_halserver 屬性。搭載 Android 9 的裝置「不得」使用 untrusted 屬性。

建議:

  • 不信任的應用程式應改為與系統服務通訊,再由系統服務與供應商 HIDL HAL 通訊。舉例來說,應用程式可以與 binderservicedomain 對話,然後 mediaserver (即 binderservicedomain) 會與 hal_graphics_allocator 對話。

  • 需要直接存取 vendor HAL 的應用程式應有自己的供應商定義 sepolicy 網域。

檔案屬性測試

Android 9 包含建構時間測試,可確保特定位置的所有檔案都具有適當的屬性 (例如,sysfs 中的所有檔案都具有必要的 sysfs_type 屬性)。

SELinux 內容標籤

為支援平台和供應商 sepolicy 的區別,系統會以不同方式建構 SELinux 內容檔案,確保兩者分開。

檔案內容

Android 8.0 針對 file_contexts 導入下列變更:

  • 為避免在啟動期間裝置上產生額外的編譯負擔,file_contexts 不會以二進位形式存在。而是可讀取的規則運算式文字檔,例如 {property, service}_contexts (7.0 之前的版本就是如此)。
  • file_contexts 分成兩個檔案:
    • plat_file_contexts
      • Android 平台 file_context,除了 /vendor 分區的標籤必須精確標示,確保 sepolicy 檔案正常運作外,其他部分沒有裝置專屬標籤。
      • 必須位於裝置的 system 分割區 /system/etc/selinux/plat_file_contexts,並在啟動時由 init 與供應商 file_context 一併載入。
    • vendor_file_contexts
      • 裝置專屬 file_context 是透過合併裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 file_contexts 所建構。
      • 必須安裝在 vendor 分割區的 /vendor/etc/selinux/vendor_file_contexts 中,並在啟動時由 init 與平台 file_context 一併載入。

房源背景資訊

在 Android 8.0 中,property_contexts 分成兩個檔案:

  • plat_property_contexts
    • Android 平台 property_context,沒有裝置專屬標籤。
    • 必須位於 system 分區的 /system/etc/selinux/plat_property_contexts,並在啟動時由 init 與供應商 property_contexts 一併載入。
  • vendor_property_contexts
    • 裝置專屬的 property_context 是透過合併裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 property_contexts 所建構。
    • 必須位於 vendor 分區的 /vendor/etc/selinux/vendor_property_contexts,並在啟動時由 init 與平台 property_context 一併載入

服務環境

在 Android 8.0 中,service_contexts 會拆分成下列檔案:

  • plat_service_contexts
    • Android 平台專屬 service_context,適用於 servicemanagerservice_context 沒有裝置專屬標籤。
    • 必須位於 system 分區的 /system/etc/selinux/plat_service_contexts,並在啟動時由 servicemanager 與供應商 service_contexts 一併載入。
  • vendor_service_contexts
    • 裝置專屬 service_context 是透過合併裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 service_contexts 所建構。
    • 必須位於 vendor 分區的 /vendor/etc/selinux/vendor_service_contexts,並在啟動時由 servicemanager 與平台 service_contexts 一併載入。
    • 雖然 servicemanager 會在啟動時尋找這個檔案,但如要讓 TREBLE 裝置完全符合規範,vendor_service_contexts「不得」存在。這是因為 vendorsystem 程序之間的所有互動都必須經過 hwservicemanager/hwbinder
  • plat_hwservice_contexts
    • Android 平台 hwservice_context,沒有裝置專屬標籤。hwservicemanager
    • 必須位於 system 分區的 /system/etc/selinux/plat_hwservice_contexts,並在啟動時與 vendor_hwservice_contexts 一併由 hwservicemanager 載入。
  • vendor_hwservice_contexts
    • 裝置專屬 hwservice_context 是透過合併裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 hwservice_contexts 所建構。
    • 必須位於 vendor 分區的 /vendor/etc/selinux/vendor_hwservice_contexts,並在啟動時由 hwservicemanagerplat_service_contexts 一併載入。
  • vndservice_contexts
    • 裝置專屬 service_context,是透過合併在裝置 Boardconfig.mkBOARD_SEPOLICY_DIRS 所指向目錄中找到的 vndservice_contexts 所建構。vndservicemanager
    • 這個檔案必須位於 vendor 分區的 /vendor/etc/selinux/vndservice_contexts,並在啟動時由 vndservicemanager 載入。

Seapp 內容

在 Android 8.0 中,seapp_contexts 分成兩個檔案:

  • plat_seapp_contexts
    • Android 平台 seapp_context,且沒有裝置專屬變更。
    • 必須位於 system 分區,且位於 /system/etc/selinux/plat_seapp_contexts.
  • vendor_seapp_contexts
    • 平台 seapp_context 的裝置專屬擴充功能,是透過合併裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄的 seapp_contexts 所建構。
    • 必須位於 vendor 分區的 /vendor/etc/selinux/vendor_seapp_contexts

MAC 權限

在 Android 8.0 中,mac_permissions.xml 分成兩個檔案:

  • 月台 mac_permissions.xml
    • Android 平台 mac_permissions.xml,且沒有特定裝置的變更。
    • 必須位於 system 分區,且位於 /system/etc/selinux/.
  • 非平台 mac_permissions.xml
    • 平台專屬的裝置擴充功能,由裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄的 mac_permissions.xml 建構而成。mac_permissions.xml
    • 必須位於 vendor 分區,且位於 /vendor/etc/selinux/.