自訂 SELinux

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

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

開始自訂 SELinux 時,請記得:

  • 為所有新 Daemon 編寫 SELinux 政策
  • 在適當情況下使用預先定義的網域
  • 將網域指派給任何以 init 服務衍生的程序
  • 編寫政策前,請先熟悉巨集
  • 將核心政策變更提交至 AOSP

請注意以下事項:

  • 建立不相容的政策
  • 允許自訂使用者政策
  • 允許自訂 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/null 的權限,以及讀取 /dev/zero 的權限。

# 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 只能讀取及寫入資料包通訊端和 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

更多

還有更多

neverallow 規則

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 系統映像檔的組合政策中顯示。

供應商映像檔支援功能,可與 AOSP 搭配運作

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

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

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

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

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

供應商圖片擴充功能,可提供擴充的 AOSP 元件

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

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

公開 AOSP 元件與僅限系統映像檔擴充功能的互動政策應位於 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 系統公開政策,因此不會偵測到新類型。AOSP 會透過屬性 (例如 hal_foo 屬性) 公開供應商提供的資源,以處理這項問題,但由於 system/sepolicy/public 不支援屬性合作夥伴擴充功能,因此供應商政策無法使用這項方法。存取權必須由先前建立的公開類型提供。

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

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