selinux-編寫策略

編寫 SELinux 政策

Android 開放源代碼項目 (AOSP) 針對所有 Android 設備中常用的應用和服務提供了一個可靠實用的基本政策。AOSP 的貢獻者會定期完善該政策。該核心政策應占設備上最終政策的 90-95%,而剩下的 5-10% 則爲設備專用自定義政策。本文重點介紹了這些設備專用自定義政策、如何編寫設備專用政策,以及在編寫此類政策時要避免的一些陷阱。

設備啓動

在編寫設備專用政策時,請按順序執行以下步驟。

在寬容模式下運行

當設備處於寬容模式時,拒絕事件會被記錄下來,但不會被強制執行。寬容模式非常重要,原因有以下兩個:

  1. 寬容模式可確保政策啓用不會延誤其他早期設備啓動任務。
  2. 被強制執行的拒絕事件可能會掩蓋其他拒絕事件。例如,文件訪問通常會涉及目錄搜索、文件打開和文件讀取操作。在強制模式下,只會發生目錄搜索拒絕事件。寬容模式可確保所有拒絕事件都會顯示出來。

要使設備進入寬容模式,最簡單的方法是通過內核命令行來實現。相應命令可以添加到設備的 BoardConfig.mk 文件中:platform/device/<vendor>/<target>/BoardConfig.mk。修改命令行之後,執行 make clean,接着執行 make bootimage,然後刷寫新的啓動映像。

在此之後,通過以下命令確認寬容模式:

adb 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 添加適當的標籤來解決的。在此示例中,tcontext 是 device。這表示默認環境,在該環境中,/dev 內的所有文件都會獲得“device”標籤,除非被分配了更具體的標籤。直接在此處接受來自 audit2allow 的輸出會導致不正確且過度寬容的規則。

要解決這種問題,可以爲文件添加更具體的標籤,在此示例中爲 gpu_device。由於 mediaserver 在覈心政策中已有訪問 gpu_device 所需的必要權限,因此不再需要更多權限。

其他需要以核心政策中預定義的類型作爲標籤的設備專用文件:

  1. 塊設備
  2. 音頻設備
  3. 視頻設備
  4. 傳感器
  5. nfc
  6. gps_device
  7. /sys 中的文件
  8. /proc 中的文件

一般情況下,向默認標籤授予權限的做法是錯誤的。其中許多權限都是 neverallow 規則所不允許的,但即使該規則並未明確禁止這些權限,也最好是提供具體標籤。

爲新服務添加標籤並解決拒絕事件

通過 init 啓動的服務需要在各自的 SELinux 域中運行。以下示例會將服務“foo”放入它自己的 SELinux 域中併爲其授予權限。

該服務是在設備的 init.<target>.rc 文件中啓動的,如下所示:

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

    創建包含以下內容的文件 device/<oem>/<target>/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/<oem>/<target>/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 root 和 adb setenforce 0

另一種安全的替代方案是在 userdebug_or_eng 聲明中包含調試權限。

政策規模擴張

在 Wild 中描述 SEAndroid 政策中介紹了一個令人關注的設備政策自定義發展趨勢。設備專用政策應占設備上運行的總體政策的 5-10%。如果自定義政策所佔的比例超過 20%,則幾乎肯定會包含超特權域和 Dead 政策。

過大的政策:

  • 由於此類政策位於 ramdisk 中,並且還會加載到內核內存中,因此會佔據兩倍的內存。
  • 需要較大的啓動映像,浪費磁盤空間。
  • 影響運行時政策查詢次數。

以下示例顯示了製造商專用政策分別佔設備上政策 50% 和 40% 的兩種設備。重寫政策大幅提高了安全性,而且功能方面沒有任何損失,如下所示。(AOSP 設備 Shamu 和 Flounder 也包含在了該示例中,以便進行比較。)

圖 1:安全審覈後的設備專用政策規模對比。

圖 1. 安全審覈後的設備專用政策規模對比。

在兩種設備中,政策的規模和權限數量都大大減小了。政策規模的減小幾乎完全是因爲移除了不必要的權限,其中許多權限可能是由 audit2allow 生成且被隨意添加到政策中的規則。對於這兩種設備來說,Dead 域也是一個問題。

授予 dac_override 權限

dac_override 拒絕事件意味着違規進程正在嘗試使用錯誤的 unix user/group/world 權限訪問某個文件。正確的解決方案几乎從不授予 dac_override 權限,而是更改相應文件或進程的 unix 權限。有些域(例如 init、vold 和 installd)確實需要能夠替換 unix 文件權限才能訪問其他進程的文件。要查看更深入的講解,請訪問 Dan Walsh 的博客

其他資源

如果要提問或提出代碼審覈請求,SEAndroid 論壇是一個的絕佳場所。

AOSP 提供了關於 Android 上的 SELinux 的簡要介紹。

如需更深入的說明,請點擊此處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章