Android 強烈建議原始設備製造商徹底測試 SELinux 實作項目。製造商導入 SELinux 時,應先將新政策套用至測試裝置集。
套用新政策後,請發出 getenforce 指令,確認裝置上的 SELinux 以正確模式執行。
這會列印全域 SELinux 模式:強制執行或寬鬆。如要判斷每個網域的 SELinux 模式,您必須檢查對應的檔案,或使用適當的 (-p) 旗標執行最新版本的 sepolicy-analyze,該旗標位於
/platform/system/sepolicy/tools/。
讀取拒絕次數
檢查錯誤,這些錯誤會以事件記錄的形式傳送至 dmesg
和 logcat,並可在裝置上查看。製造商應檢查這些裝置的 SELinux 輸出內容,並在寬容模式下公開發布前調整設定,最終切換至強制模式。dmesgSELinux 記錄訊息包含 avc:,因此很容易使用 grep 找到。您可以執行 cat /proc/kmsg 擷取進行中的拒絕記錄,也可以執行 cat /sys/fs/pstore/console-ramoops 擷取先前開機的拒絕記錄。
為避免記錄過多,SELinux 錯誤訊息會在開機完成後受到速率限制。如要確保看到所有相關訊息,可以執行 adb shell auditctl -r 0 停用這項功能。
有了這項輸出內容,製造商就能輕鬆找出系統使用者或元件違反 SELinux 政策的情況。製造商隨後可以透過變更軟體、SELinux 政策或兩者,修正這項不良行為。
具體來說,這些記錄訊息會指出在強制執行模式下會失敗的程序,以及失敗原因。範例如下:
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
請按照下列方式解讀這項輸出內容:
- 上方的
{ connectto }代表正在執行的動作。 與結尾的tclass搭配使用 (unix_stream_socket),可大致瞭解對什麼項目執行了什麼操作。在本例中,有某個項目嘗試連線至 Unix 串流通訊端。 -
scontext (u:r:shell:s0)會顯示發起動作的環境。在本例中,這是以殼層形式執行的項目。 -
tcontext (u:r:netd:s0)會顯示動作目標的背景資訊。在本例中,這是netd擁有的 unix_stream_socket。 - 頂端的
comm="ping"會提供額外提示,說明產生拒絕訊息時執行的內容。在本例中,這是不錯的提示。
另一個例子:
adb shell su root dmesg | grep 'avc: '
輸出內容:
<5> type=1400 audit: avc: denied { read write } for pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file
以下是這項拒絕的關鍵要素:
- 動作 - 嘗試執行的動作會以方括號標示,例如
read write或setenforce。 - 執行者 -
scontext(來源環境) 項目代表執行者,在本例中為rmt_storage精靈。 - 物件 -
tcontext(目標內容) 項目代表要執行的物件,在本例中為 kmem。 - 結果 -
tclass(目標類別) 項目表示所操作的物件類型,在本例中為chr_file(字元裝置)。
傾印使用者和核心堆疊
在某些情況下,事件記錄檔中的資訊不足以找出拒絕要求的原因。收集呼叫鏈 (包括核心和使用者空間) 通常有助於瞭解拒絕要求的原因。
近期的核心會定義名為 avc:selinux_audited 的追蹤點。使用 Android
simpleperf 啟用這個追蹤點,並擷取呼叫鏈。
支援的設定
- 支援 Linux 核心 >= 5.10,特別是 Android Common Kernel 分支版本「mainline」和「android12-5.10」。系統也支援 android12-5.4 分支。您可以使用
simpleperf判斷裝置上是否定義了追蹤點:adb root && adb shell simpleperf list | grep avc:selinux_audited。 如為其他核心版本,您可以挑選提交內容 dd81662 和 30969bc。 - 您應該可以重現要偵錯的事件。simpleperf 不支援開機時間事件,但您或許仍可重新啟動服務來觸發事件。
擷取呼叫鏈
第一步是使用 simpleperf record 記錄事件:
adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"
接著,觸發導致拒絕的事件。之後錄音就會停止。在本範例中,使用 Ctrl-c 應已擷取樣本:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
最後,您可以使用 simpleperf report 檢查擷取的堆疊追蹤記錄。
例如:
adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children Self Command Pid Tid Shared Object Symbol
100.00% 0.00% dmesg 3318 3318 /apex/com.android.runtime/lib64/bionic/libc.so __libc_init
|
-- __libc_init
|
-- main
toybox_main
toy_exec_which
dmesg_main
klogctl
entry_SYSCALL_64_after_hwframe
do_syscall_64
__x64_sys_syslog
do_syslog
selinux_syslog
slow_avc_audit
common_lsm_audit
avc_audit_post_callback
avc_audit_post_callback
上述呼叫鏈是統一的核心和使用者空間呼叫鏈。從使用者空間開始追蹤,一路追蹤到發生拒絕的 Kernel,讓您更清楚瞭解程式碼流程。如要進一步瞭解 simpleperf,請參閱 Simpleperf 可執行檔指令參考資料
切換為寬鬆模式
在 userdebug 或 eng 建構版本中,可以使用 adb 停用 SELinux 強制執行。如要執行這項操作,請先執行 adb root,將 ADB 切換為根目錄。接著,如要停用 SELinux 強制執行模式,請執行下列指令:
adb shell setenforce 0
或是在核心指令列 (裝置啟動初期):
androidboot.selinux=permissiveandroidboot.selinux=enforcing
或透過 Android 12 中的 bootconfig:
androidboot.selinux=permissiveandroidboot.selinux=enforcing
使用 audit2allow
audit2allow 工具會接收 dmesg 拒絕,並將其轉換為對應的 SELinux 政策陳述式。因此,這項工具可大幅加快 SELinux 開發速度。
如要使用這項工具,請執行下列指令:
adb pull /sys/fs/selinux/policyadb logcat -b events -d | audit2allow -p policy
不過,您仍須仔細檢查每個潛在的附加功能,確認是否要求過多的權限。舉例來說,如果將先前顯示的 audit2allow 拒絕事項提供給 audit2allow,系統會建議下列 SELinux 政策陳述式:rmt_storage
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
這會授予 rmt 寫入核心記憶體的權限,造成明顯的安全漏洞。audit2allow 陳述式通常只是起點。採用這些陳述式後,您可能需要變更來源網域和目標標籤,並納入適當的巨集,才能制定良好的政策。有時,我們審查的拒絕原因不應導致任何政策變更,而是應變更違規應用程式。