政策相容性

本文將說明 Android 如何處理政策相容性問題,以及平台 OTA 與新平台 SELinux 設定與舊版供應商 SELinux 設定的差異。

以 Treble 為基礎的 SELinux 政策設計會將「平台」和「供應商」政策區分開來考量;如果供應商分區產生依附元件 (例如 platform < vendor < oem),則這項設計就會變得更複雜。

在 Android 8.0 以上版本中,SELinux 全域政策會分為私人和公開元件。公開元件包含政策和相關基礎架構,保證可供平台版本使用。這項政策會提供給供應商政策編寫者,讓供應商建構供應商政策檔案,並與平台提供的政策結合,為裝置提供完整功能的政策。

  • 針對版本控制,匯出的平台公開政策會以屬性的形式寫入。
  • 為方便編寫政策,系統會在政策建構程序中,將匯出的類型轉換為版本化屬性。公開類型也可以直接用於供應商情境檔案提供的標示決策。

Android 會在平台政策中,為匯出的具體類型與每個平台版本的相應版本屬性之間維護對應關係。這可確保物件以類型標示時,不會違反先前版本中平台公開政策保證的行為。 每個平台版本的對應檔案都會保持最新狀態,以便維護這項對應,並保留公用政策中匯出的每個類型的屬性成員資格資訊。

物件擁有權和標示

在 Android 8.0 以上版本中自訂政策時,必須明確定義每個物件的擁有權,才能將平台和供應商政策分開。舉例來說,如果供應商標示 /dev/foo,而平台則在後續 OTA 中標示 /dev/foo,就會出現未定義的行為。對於 SELinux 而言,這會導致標記衝突。裝置節點只能有一個標籤,並將其解析為最後套用的標籤。因此:

  • 需要存取已套用標記失敗的程序,將無法存取該資源。
  • 建立錯誤的裝置節點,可能會導致取得檔案存取權的程序中斷。

系統屬性也可能會發生命名衝突,導致系統 (以及 SELinux 標記) 出現未定義的行為。任何具有 SELinux 標籤的物件 (包括屬性、服務、程序、檔案和 Socket) 都可能發生平台和供應商標籤之間的衝突。為避免這些問題,請明確定義這些物件的擁有權。

除了標籤衝突之外,SELinux 類型/屬性名稱也可能發生衝突。類型/屬性名稱衝突一律會導致政策編譯器錯誤。

類型/屬性命名空間

SELinux 不允許宣告相同類型/屬性。含有重複宣告的政策無法編譯。為避免類型和屬性名稱衝突,所有供應商宣告都應使用以 vendor_ 開頭的命名空間。

type foo, domain;  type vendor_foo, domain;

系統屬性和程序標示擁有權

避免標記衝突的最佳解決方法是使用屬性命名空間。為方便識別平台屬性,並在重新命名或新增匯出的平台屬性時避免名稱衝突,請確保所有供應商屬性都有各自的前置字串:

資源類型 可接受的前置字串
控制項屬性 ctl.vendor.
ctl.start$vendor.
ctl.stop$vendor.
init.svc.vendor.
可讀寫 vendor.
唯讀 ro.vendor.
ro.boot.
ro.hardware.
持續 persist.vendor.

供應商可以繼續使用 ro.boot.* (來自核心 cmdline) 和 ro.hardware.* (明顯的硬體相關屬性)。

在非系統分區的 init.rc 檔案中,所有供應商服務都應包含 vendor. 服務。類似的規則也適用於供應商屬性的 SELinux 標籤 (供應商屬性的 vendor_)。

檔案擁有權

預防檔案衝突的難度很高,因為平台和供應商政策通常會為所有檔案系統提供標籤。與類型命名不同,檔案的命名空間並不實用,因為其中許多檔案都是由核心建立。為避免發生衝突,請按照本節中所述的命名規則建立檔案系統。對於 Android 8.0,這些是建議,並未強制執行。日後,這些最佳化建議將由供應商測試套件 (VTS) 強制執行。

系統 (/system)

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

供應商 (/vendor)

AOSP SELinux 政策已為平台互動的 vendor 分區部分加上標記,讓您為平台程序編寫 SELinux 規則,以便與 vendor 分區的部分進行通訊和/或存取。範例:

/vendor路徑 平台提供的標籤 平台處理程序 (視標籤而定)
/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 實作的內容。
  • 透過供應商 SEPolicy 在 vendor 分區中新增的所有新 exec_types 都必須具有 vendor_file_type 屬性。這項規定是透過 neverallows 強制執行。
  • 為避免與日後的平台/架構更新發生衝突,請勿在 vendor 分割區中標記 exec_types 以外的檔案。
  • AOSP 所識別的相同程序 HAL 的所有程式庫依附元件,都必須標示為 same_process_hal_file.

Procfs (/proc)

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

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

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 標籤版本

供應商 API 級別 202504 起,對於較舊的供應商分區,可選擇使用在 system/sepolicy/compat/plat_sepolicy_genfs_{ver}.cil 中以 genfscon 指派的較新 SELinux 標籤。這樣一來,較舊的供應商分區就能保留現有的 SEPolicy 實作。這項功能由儲存在 /vendor/etc/selinux/genfs_labels_version.txt 中的 Makefile 變數 BOARD_GENFS_LABELS_VERSION 控制。

範例:

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

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

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

標示 genfscon 節點時,平台必須考量舊版供應商分區,並視需要實作備用機制以確保相容性。平台可以使用平台專屬程式庫來查詢 genfs 標籤版本。

相容性屬性

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

政策大多是使用現有類型編寫:

allow source_type target_type:target_class permission(s);

這是因為政策是根據所有類型的知識編寫而成。不過,如果供應商政策和平台政策使用特定類型,且特定物件的標籤只在其中一個政策中變更,另一個政策可能就會包含先前依賴的取得或失去存取權的政策。例如:

File_contexts:
/sys/A   u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;

可改為:

File_contexts:
/sys/A   u:object_r:sysfs_A:s0

雖然供應商政策會維持不變,但由於新 sysfs_A 類型沒有政策,v_domain 會失去存取權。

透過以屬性定義政策,我們可以為基礎物件提供類型,該類型具有與平台和供應商程式碼政策相對應的屬性。您可以對所有類型執行這項操作,有效建立屬性-政策,其中永遠不會使用具體類型。實際上,只有平台和供應商之間重疊的政策部分才需要這項功能,這些部分會定義並提供為平台公開政策,並在供應商政策中建構。

將公開政策定義為版本化屬性,可滿足兩個政策相容性目標:

  • 確保供應商程式碼在平台更新後仍能正常運作。 方法是在具體類型中為相應的物件新增屬性,以便保留存取權,並與供應商程式碼所依賴的物件相符。
  • 能夠淘汰政策。方法是將政策集明確劃分為屬性,並在對應版本不再受支援時立即移除。開發人員可以繼續在平台上進行開發,因為供應商政策中仍會保留舊政策,並會在升級時自動移除。

政策可寫入性

為了達成不必瞭解政策開發作業的特定版本變更內容,Android 8.0 會將平台公開政策類型與其屬性進行對應。類型 foo 會對應至屬性 foo_vN,其中 N 是指定的版本。vN 對應至 PLATFORM_SEPOLICY_VERSION 建構變數,格式為 MM.NN,其中 MM 對應至平台 SDK 編號,而 NN 則是平台安全政策專屬版本。

公開政策中的屬性並未分版本,而是以 API 的形式存在,平台和供應商政策可在該 API 上建構,以便維持兩個區隔之間的介面穩定性。平台和供應商政策編寫者可以繼續按照現行方式編寫政策。

allow source_foo target_bar:class perm; 格式匯出的平台公開政策會納入供應商政策。在編譯 (包括對應版本) 期間,會將其轉換為政策,並傳送至裝置的供應商部分 (顯示在轉換後的通用中介語言 (CIL) 中):

 (allow source_foo_vN target_bar_vN (class (perm)))

由於供應商政策不會超前平台,因此不必擔心舊版。不過,平台政策需要瞭解供應商政策的回溯時間長度,並納入其類型的屬性,以及設定與版本屬性相對應的政策。

政策差異

在每個類型的結尾加上 _vN,系統就會自動建立屬性,但如果沒有在版本差異中將屬性對應至類型,系統就不會執行任何操作。Android 會在屬性版本與類型與這些屬性之間維持對應關係。這項操作會在上述對應檔案中使用陳述式完成,例如 (CIL):

(typeattributeset foo_vN (foo))

平台升級

以下章節將詳細說明平台升級的情況。

相同類型

當物件未在政策版本中變更標籤時,就會發生這種情況。來源和目標類型皆相同,可透過 /dev/binder 查看,且在所有版本中都標示為 binder_device。在轉換後的政策中,這會以以下方式表示:

binder_device_v1 … binder_device_vN

v1 升級至 v2 時,平台政策必須包含下列項目:

type binder_device; -> (type binder_device) (in CIL)

在 v1 對應檔案 (CIL) 中:

(typeattributeset binder_device_v1 (binder_device))

在 v2 對應檔案 (CIL) 中:

(typeattributeset binder_device_v2 (binder_device))

在 v1 供應商政策 (CIL) 中:

(typeattribute binder_device_v1)
(allow binder_device_v1 )

在 v2 供應商政策 (CIL) 中:

(typeattribute binder_device_v2)
(allow binder_device_v2 )
新類型

這種情況會在平台新增新類型時發生,例如新增新功能或在強化政策時。

  • 新功能。如果類型標示先前不存在的物件 (例如新服務程序),供應商程式碼先前並未直接與該物件互動,因此不會有對應的政策。對應至該類型的新屬性在先前版本中沒有屬性,因此在針對該版本的對應檔案中不需要項目。
  • 政策強化:如果類型代表政策強化,新的類型屬性必須連結至與先前相應的屬性鏈結 (類似於先前範例將 /sys/Asysfs 變更為 sysfs_A)。供應商程式碼會依賴規則來啟用對 sysfs 的存取權,並需要將該規則納入新類型的屬性。

v1 升級至 v2 時,平台政策必須包含下列項目:

type sysfs_A; -> (type sysfs_A) (in CIL)
type sysfs; (type sysfs) (in CIL)

在 v1 對應檔案 (CIL) 中:

(typeattributeset sysfs_v1 (sysfs sysfs_A))

在 v2 對應檔案 (CIL) 中:

(typeattributeset sysfs_v2 (sysfs))
(typeattributeset sysfs_A_v2 (sysfs_A))

在 v1 供應商政策 (CIL) 中:

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

在 v2 供應商政策 (CIL) 中:

(typeattribute sysfs_A_v2)
(allow  sysfs_A_v2 )
(typeattribute sysfs_v2)
(allow  sysfs_v2 )
已移除的類型

這種情況 (很少發生) 會在移除類型時發生,而這可能發生在基礎物件:

  • 會保留,但會取得不同的標籤。
  • 已遭平台移除。

在放寬政策期間,系統會移除某個類型,並為標示為該類型的物件提供不同的現有標籤。這代表屬性對應項目已合併:供應商程式碼仍必須能透過所擁有的屬性存取基礎物件,但系統的其他部分現在必須能透過新的屬性存取該物件。

如果所切換的屬性是新屬性,重新標記的做法與新類型相同,但使用現有標籤時,新增舊屬性新類型會導致其他物件也以此類型標記,並且可供新存取。這基本上是平台所做的事,且被視為維持相容性的可接受妥協。

(typeattribute sysfs_v1)
(allow  sysfs_v1 )

範例 1:收合類型 (移除 sysfs_A)

v1 升級至 v2 時,平台政策必須包含下列項目:

type sysfs; (type sysfs) (in CIL)

在 v1 對應檔案 (CIL) 中:

(typeattributeset sysfs_v1 (sysfs))
(type sysfs_A) # in case vendors used the sysfs_A label on objects
(typeattributeset sysfs_A_v1 (sysfs sysfs_A))

在 v2 對應檔案 (CIL) 中:

(typeattributeset sysfs_v2 (sysfs))

在 v1 供應商政策 (CIL) 中:

(typeattribute sysfs_A_v1)
(allow  sysfs_A_v1 )
(typeattribute sysfs_v1)
(allow  sysfs_v1 )

在 v2 供應商政策 (CIL) 中:

(typeattribute sysfs_v2)
(allow  sysfs_v2 )

範例 2:完全移除 (foo 類型)

v1 升級至 v2 時,平台政策必須包含下列項目:

# nothing - we got rid of the type

在 v1 對應檔案 (CIL) 中:

(type foo) #needed in case vendors used the foo label on objects
(typeattributeset foo_v1 (foo))

在 v2 對應檔案 (CIL) 中:

# nothing - get rid of it

在 v1 供應商政策 (CIL) 中:

(typeattribute foo_v1)
(allow foo )
(typeattribute sysfs_v1)
(allow sysfs_v1 )

在 v2 供應商政策 (CIL) 中:

(typeattribute sysfs_v2)
(allow sysfs_v2 )
新類別/權限

這種情況會在平台升級時引入先前版本不存在的新政策元件時發生。舉例來說,當 Android 新增建立新增、查找和列出權限的 servicemanager 物件管理員時,供應商 Daemon 若想註冊 servicemanager,就需要使用無法使用的權限。在 Android 8.0 中,只有平台政策可以新增類別和權限。

如要讓供應商政策建立或擴充的所有網域都能順利使用新類別,平台政策必須納入類似以下的規則:

allow {domain -coredomain} *:new_class perm;

這可能還需要政策允許所有介面 (公開政策) 類型的存取權,確保供應商圖片能取得存取權。如果這會導致無法接受的安全政策 (因為服務管理員可能會變更),可能會強制供應商升級。

已移除的類別/權限

這種情況會發生在移除物件管理員 (例如 ZygoteConnection 物件管理員) 時,但不應導致問題。物件管理員類別和權限可在政策中保留定義,直到供應商版本不再使用為止。方法是將定義新增至對應的對應檔案。

新類型/重新命名類型的供應商自訂

新的供應商類型是供應商政策開發的核心,因為供應商需要描述新的程序、二進位檔、裝置、子系統和儲存資料。因此,您必須允許建立供應商定義的類型。

由於供應商政策一向是裝置上最舊的政策,因此您不需要自動將所有供應商類型轉換為政策中的屬性。平台不會依賴供應商政策中標示的任何項目,因為平台不瞭解這些項目;不過,平台會提供用於與標示為這些類型的物件互動的屬性和公開類型 (例如 domainsysfs_type 等)。為了讓平台能夠繼續正確與這些物件互動,必須適當套用屬性和類型,並可能需要在可自訂的網域 (例如 init) 中新增特定規則。

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 應移至供應商分割區,因此不再是 coredomain

不信任的屬性

代管任意程式的不受信任應用程式不應具備 HwBinder 服務存取權,除非這些服務已被視為可供這類應用程式存取的安全服務 (請參閱下方的安全服務)。主要原因有兩個:

  1. HwBinder 伺服器不會執行用戶端驗證,因為 HIDL 目前不會公開呼叫端 UID 資訊。即使 HIDL 公開了這類資料,許多 HwBinder 服務都會在低於應用程式的層級運作 (例如 HAL),或者不必仰賴應用程式身分進行授權。因此,為了安全起見,預設假設是,每個 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 屬性)。

平台公共政策

平台公開政策是符合 Android 8.0 架構模型的核心,不必單純維護 v1 和 v2 的平台政策組合。供應商會看到部分平台政策,其中包含可用類型和屬性,以及這些類型和屬性的規則,這些規則會成為供應商政策的一部分 (即 vendor_sepolicy.cil)。

類型和規則會在供應商產生的政策中自動轉譯為 attribute_vN,因此所有平台提供的類型都是版本化的屬性 (但屬性不會版本化)。平台負責將提供的具體類型對應至適當的屬性,確保供應商政策持續運作,並納入為特定版本提供的規則。平台公開政策和供應商政策的組合,可滿足 Android 8.0 架構模型的目標,也就是允許獨立平台和供應商版本。

對應至屬性鏈結

使用屬性對應至政策版本時,類型會對應至屬性或多個屬性,確保標示為該類型的物件可透過與先前類型相對應的屬性存取。

為了達到隱藏政策編寫工具的版本資訊,您必須自動產生版本化屬性,並將這些屬性指派給適當的類型。在靜態類型的常見情況下,這很簡單:type_foo 會對應至 type_foo_v1

對於物件標籤變更 (例如 sysfssysfs_Amediaserveraudioserver),建立這類對應關係並非易事 (如上述範例所述)。平台政策維護者必須決定如何在物件的轉換點建立對應項目,這需要瞭解物件與其指派的標籤之間的關係,並決定何時發生這種情況。為維持回溯相容性,這項複雜性需要在平台端管理,這是唯一可能更新的區隔。

版本升級

為了簡化程序,Android 平台會在新的發布分支版本推出時,發布 sepolicy 版本。如上所述,版本號碼包含在 PLATFORM_SEPOLICY_VERSION 中,格式為 MM.nn,其中 MM 對應 SDK 值,而 nn 則是 /platform/system/sepolicy. 中維護的私人值。舉例來說,19.0 代表 Kitkat、21.0 代表 Lollipop、22.0 代表 Lollipop-MR1、23.0 代表 Marshmallow、24.0 代表 Nougat、25.0 代表 Nougat-MR1、26.0 代表 Oreo、27.0 代表 Oreo-MR1,而 28.0 代表 Android 9。Uprev 不一定是整數。舉例來說,如果版本的 MR 升級需要 system/sepolicy/public 中不相容的變更,但不需要 API 升級,則該 sepolicy 版本可能為:vN.1。開發分支中顯示的版本是永遠不會用於出貨裝置的 10000.0

Android 可能會在升級時淘汰最舊的版本。如要提供何時淘汰版本的意見回饋,Android 可能會收集執行該 Android 版本且仍可接收主要平台更新的供應商政策裝置數量。如果數字低於特定門檻,該版本就會淘汰。

多個屬性對成效的影響

https://github.com/SELinuxProject/cil/issues/9 所述,將大量屬性指派給某類型,會在政策快取遺漏時導致效能問題。

這已確認是 Android 的問題,因此我們對 Android 8.0 進行了變更,以移除政策編譯器新增至政策的屬性,並移除未使用的屬性。這些變更解決了效能回歸問題。

system_ext 公開政策和產品公開政策

自 Android 11 起,system_extproduct 分區可將指定的公開類型匯出至供應商分區。就像平台公開政策一樣,供應商會使用類型和規則,自動轉換為版本化屬性,例如從 type 轉換為 type_N,其中 N 是供應商分區所依據的平台版本。

如果 system_extproduct 分割區皆以相同的平台版本 N 為基礎,建構系統會產生基本對應檔案至 system_ext/etc/selinux/mapping/N.cilproduct/etc/selinux/mapping/N.cil,其中包含從 typetype_N 的 ID 對應。供應商可以使用版本屬性 type_N 存取 type

如果只有 system_extproduct 分區更新 (例如從 N 更新至 N+1 (或更高版本),而供應商仍停留在 N),供應商可能會失去 system_extproduct 分區類型的存取權。為避免發生中斷情形,system_extproduct 區隔應提供從具體類型對應至 type_N 屬性的對應檔案。如果合作夥伴要支援使用 N+1 (或更新版本) system_extproduct 分區的 N 供應商,則必須負責維護對應檔案。

為此,合作夥伴應:

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

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

(typeattributeset foo_type_N (foo_type))
(expandtypeattribute foo_type_N true)
(typeattribute foo_type_N)

如果 bar_type 已新增至 N+1 system_ext,且 bar_type 應對應至 N 供應商的 foo_type,則可透過N.cil

(typeattributeset foo_type_N (foo_type))

(typeattributeset foo_type_N (foo_type bar_type))

然後安裝至 N+1 system_ext 的磁碟分割區。N 供應商可以繼續存取 N+1 system_ext 的 foo_typebar_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/etc/selinux/plat_file_contextssystem 分區,並在 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/etc/selinux/plat_property_contextssystem 分割區,並在 init 一開始載入時,與供應商 property_contexts 一併載入。
  • vendor_property_contexts
    • 裝置專屬 property_context,透過結合裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 property_contexts 所建構。
    • 必須位於 /vendor/etc/selinux/vendor_property_contextsvendor 分區,並在 init 開始時與平台 property_context 一併載入

服務內容

在 Android 8.0 中,service_contexts 會在下列檔案之間分割:

  • plat_service_contexts
    • servicemanager 的 Android 平台專屬 service_contextservice_context 沒有裝置專屬標籤。
    • 必須位於 /system/etc/selinux/plat_service_contextssystem 分割區,並在 servicemanager 一開始時載入,同時載入供應商 service_contexts
  • vendor_service_contexts
    • 裝置專屬 service_context,透過結合裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 service_contexts 所建構。
    • 必須位於 /vendor/etc/selinux/vendor_service_contextsvendor 分割區,並在 servicemanager 一開始載入時,與平台 service_contexts 一併載入。
    • 雖然 servicemanager 會在啟動時尋找這個檔案,但對於完全相容的 TREBLE 裝置,vendor_service_contexts 一律不得存在。這是因為 vendorsystem 程序之間的所有互動都必須經過 hwservicemanager/hwbinder
  • plat_hwservice_contexts
    • hwservicemanager 的 Android 平台 hwservice_context,沒有裝置專屬標籤。
    • 必須位於 /system/etc/selinux/plat_hwservice_contextssystem 分割區,並在 hwservicemanager 一開始時與 vendor_hwservice_contexts 一併載入。
  • vendor_hwservice_contexts
    • 裝置專屬 hwservice_context,透過結合裝置 Boardconfig.mk 檔案中 BOARD_SEPOLICY_DIRS 所指向目錄中的 hwservice_contexts 所建構。
    • 必須位於 /vendor/etc/selinux/vendor_hwservice_contextsvendor 分割區,並在 hwservicemanager 一開始載入時,與 plat_service_contexts 一併載入。
  • vndservice_contexts
    • 針對 vndservicemanager 的裝置專屬 service_context,透過結合裝置 Boardconfig.mkBOARD_SEPOLICY_DIRS 所指向目錄中的 vndservice_contexts 所建構。
    • 這個檔案必須位於 /vendor/etc/selinux/vndservice_contextsvendor 分割區,並在啟動時由 vndservicemanager 載入。

Seapp 背景資訊

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

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

MAC 權限

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

  • 平台 mac_permissions.xml
    • 沒有裝置專屬變更的 Android 平台 mac_permissions.xml
    • 必須位於 /system/etc/selinux/.system 分區
  • 非平台 mac_permissions.xml
    • 針對裝置專屬的擴充功能,可從 mac_permissions.xml 建構,並在裝置 Boardconfig.mk 檔案中由 BOARD_SEPOLICY_DIRS 指向的目錄中找到 mac_permissions.xml
    • 必須位於 /vendor/etc/selinux/.vendor 分區