編寫 SELinux 策略

Android 開源項目 (AOSP) 為所有 Android 設備通用的應用程序和服務提供了堅實的基礎策略。 AOSP 的貢獻者會定期完善此政策。核心策略預計將佔最終設備策略的 90-95%,而特定於設備的定制將佔剩餘的 5-10%。本文重點介紹這些特定於設備的自定義、如何編寫特定於設備的策略以及在此過程中要避免的一些陷阱。

設備調出

在編寫特定於設備的策略時,請按照以下步驟操作。

在許可模式下運行

當設備處於許可模式時,會記錄拒絕但不強制執行。許可模式之所以重要,有兩個原因:

  • 許可模式確保策略啟動不會延遲其他早期設備啟動任務。
  • 強制拒絕可能會掩蓋其他拒絕。例如,文件訪問通常需要目錄搜索、文件打開和文件讀取。在強制模式下,只會發生目錄搜索拒絕。許可模式可確保看到所有拒絕。

將設備置於許可模式的最簡單方法是使用內核命令行。這可以添加到設備的BoardConfig.mk文件中: platform/device/<vendor>/<target>/BoardConfig.mk 。修改命令行後,執行make clean ,然後make bootimage ,刷寫新的啟動鏡像。

之後,使用以下命令確認許可模式:

adb shell getenforce

兩周是進入全局許可模式的合理時間。在解決了大多數拒絕後,回到強制模式並解決出現的錯誤。仍在產生拒絕或仍在大量開發中的服務的域可以暫時進入許可模式,但盡快將它們移回強制模式。

儘早執行

在強制模式下,拒絕記錄和強制執行。最好讓您的設備儘早進入強制模式。等待創建和執行特定於設備的策略通常會導致錯誤的產品和糟糕的用戶體驗。儘早開始參與dogfooding並確保在實際使用中對功能進行全面測試。儘早開始可確保安全問題為設計決策提供信息。相反,僅基於觀察到的拒絕授予權限是一種不安全的方法。利用這段時間對設備進行安全審核,並針對不應允許的行為提交錯誤。

移除或刪除現有政策

在新設備上從頭開始創建特定於設備的策略有很多充分的理由,其中包括:

解決拒絕核心服務的問題

核心服務產生的拒絕通常通過文件標記來解決。例如:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

通過正確標記/dev/kgsl-3d0可以完全解決。在此示例中, tcontextdevice 。這表示默認上下文,其中/dev中的所有內容都接收“設備”標籤,除非分配了更具體的標籤。在這裡簡單地接受audit2allow的輸出會導致不正確且過於寬鬆的規則。

要解決此類問題,請給文件一個更具體的標籤,在本例中為gpu_device 。不需要進一步的權限,因為媒體服務器已經在核心策略中擁有訪問 gpu_device 的必要權限

應使用核心策略中預定義的類型標記的其他特定於設備的文件:

通常,授予默認標籤權限是錯誤的。 neverallow規則不允許其中許多權限,但即使沒有明確禁止,最佳做法是提供特定標籤。

標記新服務並解決拒絕問題

初始化啟動的服務需要在它們自己的 SELinux 域中運行。以下示例將服務“foo”放入其自己的 SELinux 域並授予其權限。

該服務在我們設備的init. device .rc文件為:

service foo /system/bin/foo
    class core
  1. 創建一個新域“foo”

    使用以下內容創建文件device/ manufacturer / device-name /sepolicy/foo.te

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    這是 foo SELinux 域的初始模板,您可以根據該可執行文件執行的特定操作向其中添加規則。

  2. 標籤/system/bin/foo

    將以下內容添加到device/ manufacturer / device-name /sepolicy/file_contexts

    /system/bin/foo   u:object_r:foo_exec:s0
    

    這確保可執行文件被正確標記,以便 SELinux 在正確的域中運行服務。

  3. 構建並刷新引導和系統映像。
  4. 優化域的 SELinux 規則。

    使用拒絕來確定所需的權限。 audit2allow工具提供了很好的指導,但僅用於為策略編寫提供信息。不要只複製輸出。

切換回強制模式

在許可模式下進行故障排除很好,但儘早切換回強制模式並嘗試保持在那裡。

常見錯誤

以下是編寫特定設備策略時發生的常見錯誤的一些解決方案。

過度使用否定

以下示例規則就像鎖上前門但讓窗戶保持打開狀態:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

意圖很明確:除了第三方應用程序之外的每個人都可以訪問調試設備。

該規則在幾個方面存在缺陷。排除untrusted_app很容易解決,因為所有應用程序都可以選擇在isolated_app域中運行服務。同樣,如果將第三方應用程序的新域添加到 AOSP,它們也將可以訪問scary_debug_device的調試設備。該規則過於寬鬆。大多數域都不會從訪問此調試工具中受益。應該編寫規則以僅允許需要訪問的域。

生產中的調試功能

調試功能不應該出現在生產版本中,它們的策略也不應該出現。

最簡單的替代方法是僅在 eng/userdebug 構建上禁用 SELinux 時才允許調試功能,例如adb rootadb shell setenforce 0

另一種安全的替代方法是將調試權限包含在userdebug_or_eng語句中。

政策規模爆炸

在野外表徵 SEAndroid 策略描述了設備策略定制增長的一個令人擔憂的趨勢。特定於設備的策略應佔設備上運行的整體策略的 5-10%。 20%+ 範圍內的自定義幾乎可以肯定包含超過特權域和無效策略。

不必要的大政策:

  • 由於策略位於 ramdisk 中並且也加載到內核內存中,因此會對內存造成雙重打擊。
  • 需要更大的引導映像會浪費磁盤空間。
  • 影響運行時策略查找時間。

以下示例顯示了兩個設備,其中製造商特定的策略包括 50% 和 40% 的設備上策略。策略的重寫產生了實質性的安全改進,而功能沒有損失,如下所示。 (包括 AOSP 設備 Shamu 和 Flounder 以進行比較。)

圖 1:安全審計後設備特定策略大小的比較。

圖 1 。安全審計後設備特定策略大小的比較。

在這兩種情況下,策略的大小和權限數量都大大減少。策略大小的減少幾乎完全是由於刪除了不必要的權限,其中許多可能是由audit2allow生成的規則,被不加選擇地添加到策略中。死域也是這兩種設備的問題。

授予 dac_override 能力

dac_override拒絕意味著違規進程正在嘗試使用不正確的 unix 用戶/組/世界權限訪問文件。正確的解決方案是幾乎從不授予dac_override權限。而是更改文件或進程的 unix 權限。一些域,如initvoldinstalld確實需要能夠覆蓋 unix 文件權限才能訪問其他進程的文件。有關更深入的解釋,請參閱Dan Walsh 的博客