Android 開放源代碼項目 (AOSP) 針對所有 Android 設(shè)備中常用的應(yīng)用和服務(wù)提供了一個可靠實用的基本政策幌甘。AOSP 的貢獻者會定期完善該政策。核心政策應(yīng)占設(shè)備上最終政策的 90-95%袖瞻,而剩下的 5-10% 則為設(shè)備專用自定義政策辙诞。本文重點介紹這些設(shè)備專用自定義政策褪子、編寫設(shè)備專用政策的方法量淌,以及在編寫此類政策時要避免的一些陷阱。
<devsite-heading text="設(shè)備啟動" for="device_bringup" level="h2" link="" toc="" class="" back-to-top="">## 設(shè)備啟動</devsite-heading> <devsite-heading text="設(shè)備啟動" for="device_bringup" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>
在編寫設(shè)備專用政策時嫌褪,請按照下列步驟操作呀枢。
<devsite-heading text="在寬容模式下運行" for="run_in_permissive_mode" level="h3" link="" toc="" class="">### 在寬容模式下運行</devsite-heading>
當設(shè)備處于寬容模式時,拒絕事件會被記錄下來笼痛,但不會被強制執(zhí)行裙秋。寬容模式非常重要琅拌,原因有以下兩點:
- 寬容模式可確保政策啟用不會延誤其他早期設(shè)備啟動任務(wù)。
- 被強制執(zhí)行的拒絕事件可能會掩蓋其他拒絕事件摘刑。例如进宝,文件訪問通常會涉及目錄搜索、文件打開和文件讀取操作枷恕。在強制模式下党晋,只會發(fā)生目錄搜索拒絕事件。寬容模式可確保所有拒絕事件都會顯示出來徐块。
要使設(shè)備進入寬容模式未玻,最簡單的方法是使用內(nèi)核命令行來實現(xiàn)。相應(yīng)命令可以添加到設(shè)備的 BoardConfig.mk
文件中:platform/device/<vendor>/<target>/BoardConfig.mk
胡控。修改命令行之后扳剿,執(zhí)行 make clean
,接著執(zhí)行 make bootimage
昼激,然后刷寫新的啟動映像舞终。
在此之后,通過以下命令確認寬容模式:
<devsite-code><pre class="devsite-terminal" is-upgraded="">adb shell getenforce
</pre></devsite-code>
將處于全局寬容模式的時間設(shè)為兩周比較合理癣猾。在解決大多數(shù)拒絕事件之后,返回到強制模式余爆,并在出現(xiàn)錯誤時加以解決纷宇。對于仍然不斷出現(xiàn)拒絕事件的域或仍處于密集開發(fā)階段的服務(wù),可以暫時使其進入寬容模式蛾方,但要盡快使其返回到強制模式像捶。
<devsite-heading text="提早采用強制模式" for="enforce_early" level="h3" link="" toc="" class="">### 提早采用強制模式</devsite-heading>
在強制模式下,拒絕事件會被記錄下來桩砰,并且會被強制執(zhí)行拓春。最佳做法是盡早使您的設(shè)備進入強制模式。如果花時間等待創(chuàng)建和強制執(zhí)行設(shè)備專用政策亚隅,通常會導(dǎo)致有問題的產(chǎn)品和糟糕的用戶體驗硼莽。要提前足夠長的時間開始參與 dogfooding,確保對實際使用中涉及的功能進行全面測試煮纵。提早開始有助于確保安全問題能夠在相關(guān)人員做出設(shè)計決策時被考慮在內(nèi)懂鸵。相反,僅根據(jù)觀察到的拒絕事件來授予權(quán)限是一種不安全的做法行疏〈夜猓可以利用這段時間對設(shè)備進行安全審核,并針對不應(yīng)被允許的行為提出錯誤酿联。
<devsite-heading text="移除或刪除現(xiàn)有政策" for="remove_or_delete_existing_policy" level="h3" link="" toc="" class="">### 移除或刪除現(xiàn)有政策</devsite-heading>
之所以要在新設(shè)備上從頭開始創(chuàng)建設(shè)備專用政策终息,有很多合理的理由夺巩,其中包括:
- 安全審核
- 過度寬容的政策
- 政策規(guī)模縮小
- Dead 政策
<devsite-heading text="解決核心服務(wù)生成的拒絕事件" for="address_denials_of_core_services" level="h3" link="" toc="" class="">### 解決核心服務(wù)生成的拒絕事件</devsite-heading>
核心服務(wù)生成的拒絕事件通常是通過為文件添加標簽來解決的周崭。例如:
<devsite-code><pre is-upgraded="">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
</pre></devsite-code>
是完全通過為 /dev/kgsl-3d0
添加適當?shù)臉撕瀬斫鉀Q的柳譬。在此示例中,tcontext
是 device
休傍。這表示默認環(huán)境征绎,在該環(huán)境中,/dev
中的內(nèi)容都會獲得 device 標簽(被分配了更具體的標簽的內(nèi)容除外)磨取。直接在此處接受來自 audit2allow 的輸出會導(dǎo)致不正確且過度寬容的規(guī)則人柿。
要解決這種問題,可以為文件添加更具體的標簽忙厌,在此示例中為 gpu_device凫岖。由于 mediaserver 在核心政策中已有訪問 gpu_device 所需的必要權(quán)限,因此不再需要更多權(quán)限逢净。
其他需要以核心政策中預(yù)定義的類型作為標簽的設(shè)備專用文件:
一般情況下哥放,向默認標簽授予權(quán)限的做法是錯誤的。其中許多權(quán)限都是 neverallow 規(guī)則所不允許的爹土,但即使該規(guī)則并未明確禁止這些權(quán)限甥雕,也最好是提供具體標簽。
<devsite-heading text="為新服務(wù)添加標簽并解決拒絕事件" for="label_new_services_and_address_denials" level="h3" link="" toc="" class="">### 為新服務(wù)添加標簽并解決拒絕事件</devsite-heading>
通過 init 啟動的服務(wù)需要在各自的 SELinux 域中運行胀茵。以下示例會將服務(wù)“foo”放入它自己的 SELinux 域中并為其授予權(quán)限社露。
該服務(wù)是在設(shè)備的 init.<var>device</var>.rc
文件中啟動的,如下所示:
<devsite-code><pre class="" is-upgraded="">service foo /system/bin/foo
class core
</pre></devsite-code>
-
創(chuàng)建一個新域“foo”
創(chuàng)建包含以下內(nèi)容的文件
device/<var>manufacturer</var>/<var>device-name</var>/sepolicy/foo.te
:<devsite-code><pre class="" is-upgraded=""># foo service
type foo, domain;
type foo_exec, exec_type, file_type;init_daemon_domain(foo)
</pre></devsite-code>
-
這是 foo SELinux 域的初始模板琼娘,您可以根據(jù)該可執(zhí)行文件執(zhí)行的具體操作為該模板添加規(guī)則峭弟。
- 為
/system/bin/foo
添加標簽
將以下內(nèi)容添加到
device/<var>manufacturer</var>/<var>device-name</var>/sepolicy/file_contexts
:<devsite-code><pre class="" is-upgraded="">/system/bin/foo u:object_r:foo_exec:s0
</pre></devsite-code> - 為
這可確保為該可執(zhí)行文件添加適當?shù)臉撕灒员?SELinux 在適當?shù)挠蛑羞\行相應(yīng)服務(wù)脱拼。
編譯并刷寫啟動映像和系統(tǒng)映像瞒瘸。
-
優(yōu)化相應(yīng)域的 SELinux 規(guī)則。
根據(jù)拒絕事件確定所需的權(quán)限熄浓。audit2allow 工具提供了一些實用的指南情臭,但該工具僅適用于提供編寫政策時所需的信息。切勿只是復(fù)制輸出內(nèi)容赌蔑。
<devsite-heading text="切換回強制模式" for="enforcing_mode" level="h3" link="" toc="" class="">### 切換回強制模式</devsite-heading>
可以在寬容模式下進行問題排查谎柄,但要盡早切換回強制模式,并盡量保持該模式惯雳。
<devsite-heading text="常見錯誤" for="common_mistakes" level="h2" link="" toc="" class="" back-to-top="">## 常見錯誤</devsite-heading> <devsite-heading text="常見錯誤" for="common_mistakes" level="h2" link="" toc="" class="" back-to-top=""></devsite-heading>
下面介紹了在編寫設(shè)備專用政策時發(fā)生的常見錯誤的一些解決方法朝巫。
<devsite-heading text="過度使用否定" for="overuse_of_negation" level="h3" link="" toc="" class="">### 過度使用否定</devsite-heading>
以下示例規(guī)則類似于鎖著前門,但開著窗戶:
<devsite-code><pre is-upgraded="">allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms</pre></devsite-code>
該規(guī)則的意圖很明確:除了第三方應(yīng)用之外石景,其他所有應(yīng)用都可以訪問調(diào)試設(shè)備劈猿。
該規(guī)則存在幾個方面的缺陷拙吉。排除 untrusted_app
所起到的效果微不足道,因為所有應(yīng)用都可以選擇在 isolated_app
網(wǎng)域中運行服務(wù)揪荣。同樣筷黔,如果第三方應(yīng)用的新域被添加到了 AOSP,它們也可以訪問 scary_debug_device
仗颈。該規(guī)則過于寬容佛舱。對于大多數(shù)域來說,能夠訪問該調(diào)試工具并不能使它們獲益挨决。該規(guī)則應(yīng)編寫為僅允許需要訪問該調(diào)試工具的域请祖。
<devsite-heading text="正式版中的調(diào)試功能" for="debugging_features_in_production" level="h3" link="" toc="" class="">### 正式版中的調(diào)試功能</devsite-heading>
調(diào)試功能及其政策不應(yīng)存在于正式版中。
最簡單的替代方案是脖祈,僅當 eng/userdebug 版本中停用了 SELinux 時肆捕,才允許使用調(diào)試功能,例如 adb root
和 adb shell setenforce 0
盖高。
另一種安全的替代方案是在 userdebug_or_eng 聲明中包含調(diào)試權(quán)限慎陵。
<devsite-heading text="政策規(guī)模擴張" for="policy_size_explosion" level="h3" link="" toc="" class="">### 政策規(guī)模擴張</devsite-heading>
在 Wild 中描述 SEAndroid 政策中介紹了一個令人關(guān)注的設(shè)備政策自定義發(fā)展趨勢。設(shè)備專用政策應(yīng)占設(shè)備上運行的所有政策的 5-10%喻奥。如果自定義政策所占的比例超過 20%席纽,則幾乎肯定會包含超特權(quán)域和 Dead 政策。
過大的政策:
- 由于此類政策位于 ramdisk 中撞蚕,并且還會加載到內(nèi)核內(nèi)存中胆筒,因此會占據(jù)兩倍的內(nèi)存。
- 需要較大的啟動映像诈豌,浪費磁盤空間。
- 影響運行時政策查詢次數(shù)抒和。
以下示例顯示了制造商專用政策分別占設(shè)備上政策 50% 和 40% 的兩種設(shè)備矫渔。重寫政策大幅提高了安全性,而且功能方面沒有任何損失摧莽,如下所示庙洼。(AOSP 設(shè)備 Shamu 和 Flounder 也包含在了該示例中,以便進行比較镊辕。)
在兩種設(shè)備中油够,政策的規(guī)模和權(quán)限數(shù)量都大大減小了。政策規(guī)模的減小幾乎完全是因為移除了不必要的權(quán)限征懈,其中許多權(quán)限可能是由 audit2allow
生成且被隨意添加到政策中的規(guī)則石咬。對于這兩種設(shè)備來說,Dead 域也是一個問題卖哎。
<devsite-heading text="授予 dac_override 權(quán)限" for="granting_the_dac_override_capability" level="h3" link="" toc="" class="">### 授予 dac_override 權(quán)限</devsite-heading>
dac_override
拒絕事件意味著違規(guī)進程正在嘗試使用錯誤的 unix user/group/world 權(quán)限訪問某個文件鬼悠。正確的解決方案幾乎從不授予 dac_override
權(quán)限删性,而是更改相應(yīng)文件或進程的 unix 權(quán)限。有些域(例如 init
焕窝、vold
和 installd
)確實需要能夠替換 unix 文件權(quán)限才能訪問其他進程的文件蹬挺。要查看更深入的講解,請訪問 Dan Walsh 的博客它掂。