Android 強烈建議 OEM 徹底測試他們的 SELinux 實現。當製造商實施 SELinux 時,他們應該首先將新策略應用於設備測試池。
應用新策略後,通過發出命令getenforce確保 SELinux 在設備上以正確的模式運行。
這將打印全局 SELinux 模式:Enforcing 或 Permissive。要確定每個域的 SELinux 模式,您必須檢查相應的文件或使用/platform/system/sepolicy/tools/中的適當 ( -p ) 標誌運行最新版本的sepolicy-analyze 。
閱讀否認
檢查錯誤,這些錯誤作為事件日誌路由到dmesg和logcat ,並且可以在設備上本地查看。製造商應在這些設備上檢查 SELinux 輸出到dmesg ,並在以許可模式公開發布並最終切換到強制模式之前優化設置。 SELinux 日誌消息包含avc: ,因此可以使用grep輕鬆找到。可以通過運行cat /proc/kmsg來捕獲正在進行的拒絕日誌,或者通過運行cat /sys/fs/pstore/console-ramoops從上一次引導中捕獲拒絕日誌。
通過此輸出,製造商可以輕鬆識別系統用戶或組件何時違反 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 擁有的netd。 - 頂部的
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。 - Actor -
scontext(源上下文)條目表示參與者,在本例中為rmt_storage守護進程。 - 對象-
tcontext(目標上下文)條目表示正在操作的對象,在本例中為 kmem。 - 結果-
tclass(目標類)條目指示正在操作的對象的類型,在本例中為chr_file(字符設備)。
轉儲用戶和內核堆棧
在某些情況下,事件日誌中包含的信息不足以查明拒絕的來源。收集調用鏈(包括內核和用戶空間)通常很有用,以更好地了解拒絕發生的原因。
最近的內核定義了一個名為avc:selinux_audited的跟踪點。使用 Android simpleperf啟用此跟踪點並捕獲調用鏈。
支持的配置
- Linux 內核 >= 5.10,特別是 Android 通用內核分支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
上面的調用鍊是統一的內核和用戶空間調用鏈。通過從用戶空間開始跟踪一直到發生拒絕的內核,它可以讓您更好地了解代碼流。有關simpleperf的更多信息,請參閱Simpleperf 可執行命令參考
切換到許可
SELinux 強制可以通過 ADB 在 userdebug 或 eng 構建上禁用。為此,首先通過運行adb root 。然後,要禁用 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前面顯示的rmt_storage拒絕會導致以下建議的 SELinux 策略聲明:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
這將授予rmt寫入內核內存的能力,這是一個明顯的安全漏洞。通常, audit2allow語句只是一個起點。使用這些語句後,您可能需要更改源域和目標的標籤,以及合併適當的宏,以得出一個好的策略。有時,被審查的否認根本不應該導致任何政策變化;而是應該更改有問題的應用程序。