自訂 SELinux

整合基本層級的 SELinux 功能並徹底分析結果後,您可以新增自己的政策設定,涵蓋對 Android 作業系統的客製化設定。這些政策仍必須符合 Android 相容性計畫規定,且不得移除預設的 SELinux 設定。

製造商不應移除現有的 SELinux 政策。否則,可能會導致 Android SELinux 實作項目和受控的應用程式發生錯誤。這包括可能需要改善以符合規定並運作的第三方應用程式。應用程式無須修改,就能繼續在支援 SELinux 的裝置上運作。

自訂 SELinux 時,請記得以下操作:

  • 為所有新 Daemon 編寫 SELinux 政策
  • 在適當情況下使用預先定義的網域
  • 將網域指派給以 init 服務形式產生的任何程序
  • 編寫政策前,請先熟悉巨集
  • 將核心政策異動提交至 Android 開放原始碼計畫

請注意以下事項:

  • 建立不相容的政策
  • 允許自訂使用者政策
  • 允許自訂 MDM 政策
  • 嚇阻違反政策的使用者
  • 新增後門程式

如需瞭解具體需求,請參閱 Android 相容性定義說明文件的「Kernel Security Features」一節。

SELinux 採用白名單的做法,代表必須在政策中明確允許所有存取行為才能獲得允許。由於 Android 的預設 SELinux 政策已支援 Android 開放原始碼專案,因此您不需要以任何方式修改 SELinux 設定。如果您要自訂 SELinux 設定,請務必小心,不要破壞現有應用程式。做法如下:

  1. 使用最新的 Android 核心
  2. 採用最低權限原則
  3. 只新增您自行在 Android 裝置上新增的項目。預設政策會自動適用於 Android 開放原始碼計畫程式碼集。
  4. 將軟體元件分隔為執行單一工作模組。
  5. 建立 SELinux 政策,將這些工作與不相關的函式隔離。
  6. 將這些政策放入 /device/manufacturer/device-name/sepolicy 目錄中的 *.te 檔案 (SELinux 政策來源檔案的副檔名),然後使用 BOARD_SEPOLICY 變數將這些政策納入建構作業。
  7. 一開始最好使用允許的新網域。方法是在網域的 .te 檔案中使用許可宣告。
  8. 分析結果並調整網域定義。
  9. 如果在 userdebug 版本中沒有出現其他拒絕,請移除寬鬆宣告。

整合 SELinux 政策變更後,請在開發工作流程中新增一個步驟,確保日後 SELinux 的相容性。在理想的軟體開發程序中,只有在軟體模型變更時,SELinux 政策才會變更,而非實際實作。

開始自訂 SELinux 時,請先稽核您向 Android 新增的內容。如果您已新增執行新函式的元件,請先確認元件符合 Android 的安全政策,以及 OEM 制定的任何相關政策,再開啟強制模式。

為避免不必要的問題,建議您採用較廣泛且相容性較高的設定,而非過於嚴格且不相容的設定,因為前者不會導致裝置功能失效。反之,如果您的變更將受益於其他人,則應以修補程式形式提交對預設 SELinux 政策的修改。如果修補程式套用至預設安全性政策,您就不需要在每次推出新版 Android 時進行這項變更。

政策聲明範例

SELinux 是以 M4 電腦語言為基礎,因此支援各種巨集,可節省時間。

在以下範例中,所有網域都會獲得從 /dev/zero 讀取或寫入 /dev/null 的權限。

# Allow read / write access to /dev/null
allow domain null_device:chr_file { getattr open read ioctl lock append write};

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file { getattr open read ioctl lock };

您也可以使用 SELinux *_file_perms 巨集 (簡寫) 編寫相同的陳述式:

# Allow read / write access to /dev/null
allow domain null_device:chr_file rw_file_perms;

# Allow read-only access to /dev/zero
allow domain zero_device:chr_file r_file_perms;

政策範例

以下是 DHCP 政策的完整範例,我們會在下方進行檢查:

type dhcp, domain;
permissive dhcp;
type dhcp_exec, exec_type, file_type;
type dhcp_data_file, file_type, data_file_type;

init_daemon_domain(dhcp)
net_domain(dhcp)

allow dhcp self:capability { setgid setuid net_admin net_raw net_bind_service
};
allow dhcp self:packet_socket create_socket_perms;
allow dhcp self:netlink_route_socket { create_socket_perms nlmsg_write };
allow dhcp shell_exec:file rx_file_perms;
allow dhcp system_file:file rx_file_perms;
# For /proc/sys/net/ipv4/conf/*/promote_secondaries
allow dhcp proc_net:file write;
allow dhcp system_prop:property_service set ;
unix_socket_connect(dhcp, property, init)

type_transition dhcp system_data_file:{ dir file } dhcp_data_file;
allow dhcp dhcp_data_file:dir create_dir_perms;
allow dhcp dhcp_data_file:file create_file_perms;

allow dhcp netd:fd use;
allow dhcp netd:fifo_file rw_file_perms;
allow dhcp netd:{ dgram_socket_class_set unix_stream_socket } { read write };
allow dhcp netd:{ netlink_kobject_uevent_socket netlink_route_socket
netlink_nflog_socket } { read write };

我們來分析這個例子:

在第一行類型宣告中,DHCP 守護程序會從基礎安全性政策 (domain) 繼承。根據前述陳述式範例,DHCP 可以讀取 /dev/null 並寫入 /dev/null

系統會在第二行將 DHCP 識別為許可網域。

init_daemon_domain(dhcp) 行中,政策狀態表示 DHCP 是從 init 產生,可以與其通訊。

net_domain(dhcp) 行中,政策允許 DHCP 使用 net 網域的一般網路功能,例如讀取和寫入 TCP 封包、透過通訊 socket 進行通訊,以及執行 DNS 要求。

allow dhcp proc_net:file write; 行中,政策指出 DHCP 可寫入 /proc 中的特定檔案。這行程式碼示範了 SELinux 的精細檔案標示。它使用 proc_net 標籤,將寫入權限限制為僅限 /proc/sys/net 底下的檔案。

範例的最後一個區塊以 allow dhcp netd:fd use; 開頭,說明應用程式如何允許彼此互動。這項政策指出,DHCP 和 netd 可能會透過檔案描述符、FIFO 檔案、資料包通訊端和 UNIX 串流通訊端互相通訊。DHCP 只能從 Datagram 通訊端和 UNIX 串流通訊端讀取和寫入,但無法建立或開啟它們。

可用的控制選項

類別 權限
檔案
ioctl read write create getattr setattr lock relabelfrom relabelto append
unlink link rename execute swapon quotaon mounton
目錄
add_name remove_name reparent search rmdir open audit_access execmod
通訊端
ioctl read write create getattr setattr lock relabelfrom relabelto append bind
connect listen accept getopt setopt shutdown recvfrom sendto recv_msg send_msg
name_bind
檔案系統
mount remount unmount getattr relabelfrom relabelto transition associate
quotamod quotaget
程序
fork transition sigchld sigkill sigstop signull signal ptrace getsched setsched
getsession getpgid setpgid getcap setcap share getattr setexec setfscreate
noatsecure siginh setrlimit rlimitinh dyntransition setcurrent execmem
execstack execheap setkeycreate setsockcreate
安全性
compute_av compute_create compute_member check_context load_policy
compute_relabel compute_user setenforce setbool setsecparam setcheckreqprot
read_policy
能力
chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap
linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock
ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin
sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write
audit_control setfcap

更多

及其他商家

永不允許規則

SELinux neverallow 規則會禁止不應發生的行為。透過相容性測試,現在可在所有裝置上強制執行 SELinux neverallow 規則。

以下指南可協助製造商避免在自訂過程中發生 neverallow 規則相關錯誤。此處使用的規則編號對應至 Android 5.1,且可能因版本而異。

規則 48:neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
請參閱 ptrace 的手冊頁面。sys_ptrace 功能可授予 ptrace 任何程序的功能,這能讓您充分控管其他程序,而且只能屬於規則所述的指定系統元件。這項功能的需求通常表示存在不需要提供給使用者的建構或功能不需要的功能。移除不必要的元件。

規則 76:neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;
這項規則旨在防止系統執行任意程式碼。具體來說,它會斷言只執行 /system 上的程式碼,這可透過驗證開機等機制提供安全保證。遇到此 neverallow 規則的問題時,通常最佳解決方法是將有問題的程式碼移至 /system 區隔。

在 Android 8.0 以上版本中自訂 SEPolicy

本節提供 Android 8.0 以上版本的廠商 SELinux 政策指南,包括 Android 開放原始碼計畫 (AOSP) SEPolicy 和 SEPolicy 擴充功能。如要進一步瞭解如何讓 SELinux 政策在不同分區和 Android 版本之間保持相容性,請參閱「相容性」。

政策擺放位置

在 Android 7.0 以下版本中,裝置製造商可以將政策新增至 BOARD_SEPOLICY_DIRS,包括在不同裝置類型中擴充 AOSP 政策的政策。在 Android 8.0 以上版本中,將政策新增至 BOARD_SEPOLICY_DIRS 只會將政策置於供應商映像檔中。

在 Android 8.0 以上版本中,政策位於 AOSP 的以下位置:

  • system/sepolicy/public. 包含匯出至供應商專屬政策的政策。所有內容都會納入 Android 8.0 相容性基礎架構。公開政策適用於所有版本,因此您可以在自訂政策中加入任何 /public。因此,可放入 /public 的政策類型會受到更多限制。請將此視為平台匯出的政策 API:任何與 /system/vendor 之間的介面相關的內容都屬於此類。
  • system/sepolicy/private. 包含系統映像檔運作所需的政策,但不包含供應商映像檔政策。
  • system/sepolicy/vendor包含 /vendor 中,但存在於核心平台樹狀結構 (而非裝置專屬目錄) 中的元件政策。這是版本系統對裝置和全域元件做出區別的產物;從概念上來說,這是下文所述裝置專屬政策的一部分。
  • device/manufacturer/device-name/sepolicy。 包括裝置專屬政策。還提供裝置自訂設定,Android 8.0 以上版本可對應至供應商映像檔元件政策。

在 Android 11 以上版本中,system_ext 和產品分區也可以包含分區專屬政策。system_ext 和產品政策也分為公開和私人,供應商可以使用 system_ext 和產品的公開政策,例如系統政策。

  • SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS:包含匯出至供應商專屬政策的政策。安裝至 system_ext 分區。
  • SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS:包含系統_ext 映像檔運作所需的必要政策,但供應商映像檔政策不應知曉這些政策。安裝至 system_ext 分區。
  • PRODUCT_PUBLIC_SEPOLICY_DIRS。包含匯出至供應商專屬政策中使用的政策。已安裝至產品分區。
  • PRODUCT_PRIVATE_SEPOLICY_DIRS:包含產品圖片運作所需的政策,但供應商圖片政策不應知曉。已安裝至產品分區。
注意:使用 GSI 時,系統不會掛載 OEM 的 system_ext 和產品分區。由於缺少 OEM 專屬類型定義,因此使用 OEM 的 system_ext 和產品公開政策的供應商 sepolicy 中的規則會變成 NOP。
注意:使用 system_ext 和產品公開政策時,請格外小心。公用政策會做為 system_ext/product 和供應商之間的匯出 API。合作夥伴應自行管理相容性問題。

支援的政策情境

在搭載 Android 8.0 以上版本的裝置上,供應商映像檔必須與 Google 提供的原始設備製造商 (OEM) 系統映像檔和參考 AOSP 系統映像檔相容,並通過此參考映像檔的 CTS。這些規定可確保架構和供應商程式碼之間的明確區隔。這類裝置支援下列情境。

僅限供應商圖片的額外資訊

範例:從供應商映像檔新增服務至 vndservicemanager,該映像檔支援供應商映像檔的程序。

如同使用先前 Android 版本推出的裝置,請在 device/manufacturer/device-name/sepolicy 中新增裝置專屬的客製化設定。新政策將規範供應商元件與其他供應商元件互動的情形,應只涉及 device/manufacturer/device-name/sepolicy 中存在的類型。在此編寫的政策可讓供應商的程式碼正常運作,不會在僅限架構的 OTA 中更新,並在裝置上與參考 AOSP 系統映像檔的組合政策中顯示。

供應商映像檔支援,以便處理 Android 開放原始碼計畫

範例:新增實作 AOSP 定義的 HAL 的新程序 (透過供應商映像檔的 hwservicemanager 註冊)。

和搭載舊版 Android 的裝置一樣,請在 device/manufacturer/device-name/sepolicy 中執行裝置專屬的自訂設定。匯出為 system/sepolicy/public/ 一部分的政策可供使用,並會隨供應商政策一併發布。您可以在新規則中使用公開政策中的類型和屬性,以便與新的供應商專屬位元互動,但須遵守提供的 neverallow 限制。與僅限供應商的情況相同,這裡的新政策不會在僅限架構的 OTA 中更新,而是會在裝置上與參考 AOSP 系統映像檔的組合政策中顯示。

僅限系統映像檔的擴充功能

範例:新增服務 (已向 ServiceManager 註冊),且只有系統映像檔中的其他程序可存取。

將這項政策新增至 system/sepolicy/private。您可以新增額外程序或物件,在合作夥伴系統映像檔中啟用功能,但前提是這些新位元不需要與供應商映像檔中的新元件互動 (具體來說,這些程序或物件必須在沒有供應商映像檔政策的情況下完全運作)。system/sepolicy/public 匯出的政策可用於這裡,就像是僅限供應商圖片的擴充功能一樣。這項政策是系統映像檔的一部分,可以在僅限架構的 OTA 中更新,但使用參考 AOSP 系統映像檔時,這項政策不會出現。

提供擴充 Android 開放原始碼計畫元件的廠商圖片擴充功能

範例:新的非 AOSP HAL,供 AOSP 系統映像檔中也存在的擴充用戶端使用 (例如擴充的 system_server)。

系統與供應商之間的互動政策必須納入於供應商分區的 device/manufacturer/device-name/sepolicy 目錄中。這與上述新增供應商映像檔支援以搭配參考 AOSP 映像檔運作的情況類似,但修改過的 AOSP 元件可能也需要額外政策,才能與系統分區的其他部分正常運作 (只要仍有公開的 AOSP 類型標籤即可)。

如需搭配系統映像檔擴充功能的公開 Android 開放原始碼計畫元件互動政策,應位於 system/sepolicy/private

僅存取 Android 開放原始碼計畫介面的系統映像檔擴充功能

範例:新的非 Android 開放原始碼計畫系統程序必須存取 Android 開放原始碼計畫所依賴的 HAL。

這與僅限系統映像檔的擴充功能範例類似,但新的系統元件或許可以在 system/vendor 介面上互動。新系統元件的政策必須放入 system/sepolicy/private,如果是透過 AOSP 在 system/sepolicy/public 中建立的介面,則可接受 (也就是說,功能所需的類型和屬性都在其中)。儘管政策可納入裝置專屬政策,卻因只有架構更新而無法使用其他 system/sepolicy/private 類型或變更 (任何影響政策的方式)。這項政策可能會在僅限架構的 OTA 中變更,但使用 AOSP 系統映像檔時不會顯示 (也不會有新的系統元件)。

提供新系統元件的廠商圖片擴充功能

範例:新增非 AOSP HAL,供用戶端程序使用,但沒有 AOSP 類似項目 (因此需要專屬網域)。

AOSP 擴充功能範例類似,系統與供應商之間的互動政策必須放在供應商分區中提供的 device/manufacturer/device-name/sepolicy 目錄中 (以確保系統政策不會知道供應商特定詳細資料)。您可以新增可在 system/sepolicy/public 中擴充政策的新公開類型;這項操作應只在現有 AOSP 政策之外進行,也就是不要移除 AOSP 公開政策。接著,您就可以在 system/sepolicy/privatedevice/manufacturer/device-name/sepolicy 中,為政策使用新的公開類型。

請注意,每新增一個 system/sepolicy/public 都會增加複雜度,因為這會公開新的相容性保證,而這項保證必須在對應檔案中追蹤,並受其他限制。您只能在 system/sepolicy/public 中新增類型與對應的允許規則;不支援屬性和其他政策陳述式。此外,新的公開類型無法用於直接標記 /vendor 政策中的物件。

不支援的政策情境

搭載 Android 8.0 以上版本的裝置不支援下列政策情境和範例。

在僅限架構 OTA 後,系統映像檔需要取得新供應商映像檔元件的權限的額外擴充功能

範例:在下一個 Android 版本中新增了需要專屬網域的非 AOSP 系統程序,且需要存取新的非 AOSP HAL。

新 (非 AOSP) 系統和供應商元件互動類似,只是新系統類型是在僅限架構的 OTA 中引入。雖然新類型可新增至 system/sepolicy/public 中的政策,但現有的供應商政策只追蹤 Android 8.0 系統公開政策,因此不會偵測到新類型。Android 開放原始碼計畫會透過屬性 (例如 hal_foo 屬性) 公開供應商提供的資源,藉此處理這個問題,但 system/sepolicy/public 不支援屬性合作夥伴擴充功能,因此無法使用這個方法。存取權必須由先前建立的公開類型提供。

範例:系統程序 (AOSP 或非 AOSP) 的變更必須變更與新非 AOSP 供應商元件的互動方式。

系統映像檔的政策必須在未知特定供應商自訂設定的情況下編寫。與 Android 開放原始碼計畫中特定介面相關的政策會透過 system/sepolicy/public 中的屬性來公開,讓供應商政策能選擇日後採用使用這些屬性的系統政策。不過,system/sepolicy/public 不支援屬性擴充功能,因此所有政策都必須位於 device/manufacturer/device-name/sepolicy 中,才能指示系統元件與新供應商元件如何互動 (且不會由 AOSP system/sepolicy/public 中現有的屬性處理)。這表示系統類型無法透過架構專用的 OTA 變更允許供應商類型的存取權。