驗證 SELinux

Android 強烈鼓勵 OEM 徹底測試他們的 SELinux 實現。當製造商實施 SELinux 時,他們應該首先將新政策應用於設備測試池。

應用新策略後,確保了SELinux在設備上的正確的模式通過發出命令運行getenforce

這將打印全局 SELinux 模式:Enforcing 或 Permissive。為了確定每個域的SELinux的模式,你必須檢查相應的文件或運行最新版本的sepolicy-analyze與適當的( -p )標誌,存在於/platform/system/sepolicy/tools/

閱讀否認

檢查是否存在錯誤,這是路由的事件日誌dmesglogcat和是可見的本地設備上。製造商應檢查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)告訴你什麼情況下啟動的動作。在這種情況下,這是作為 shell 運行的東西。
  • tcontext (u:r:netd:s0)告訴你的行動的目標的背景下。在這種情況下,這是通過擁有的unix_stream_socket 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 writesetenforce
  • 演員-該scontext (來源上下文)項代表的演員,在這種情況下, rmt_storage守護進程。
  • 對象-的tcontext (目標上下文)項表示在被加載,在此情況下kmem的對象。
  • 結果-該tclass (目標類)項表示在被加載,在此情況下,對象的類型chr_file (字符設備)。

轉儲用戶和內核堆棧

在某些情況下,事件日誌中包含的信息不足以確定拒絕的來源。收集調用鏈(包括內核和用戶空間)通常很有用,以更好地理解拒絕發生的原因。

最新的內核定義了一個名為跟踪點avc:selinux_audited 。採用Android simpleperf啟用此跟踪點和捕捉callchain。

支持的配置

  • Linux內核> = 5.10,尤其是Android的通用內核分支主線android12-5.10支持。該android12-5.4分支也支持。您可以使用simpleperf來確定跟踪點被定義您的設備上: adb root && adb shell simpleperf list | grep avc:selinux_audited 。對於其他版本的內核,你可以挑櫻桃的提交dd8166230969bc
  • 應該可以重現您正在調試的事件。使用 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可執行命令參考

切換到寬容

可以通過 ADB 在 userdebug 或 eng 構建中禁用 SELinux 強制執行。通過運行這樣做,第一開關亞行根adb root 。然後,要禁用 SELinux 強制執行,請運行:

adb shell setenforce 0

或者在內核命令行(在早期設備啟動期間):

androidboot.selinux=permissive
androidboot.selinux=enforcing

或者通過 Android 12 中的 bootconfig:

androidboot.selinux=permissive
androidboot.selinux=enforcing

使用 audit2allow

selinux/policycoreutils/audit2allow工具把dmesg否認,並把它們轉換成相應的SELinux策略的聲明。因此,它可以大大加快 SELinux 的開發。 audit2allow發貨作為Android的源代碼樹的一部分,當您從源構建Android被自動編譯。

要使用它,請運行:

adb pull /sys/fs/selinux/policy
adb logcat -b all -d | audit2allow -p policy

然而,必須小心檢查每個潛在的添加是否超出權限。例如,飼養audit2allowrmt_storage表現在以下建議SELinux的政策聲明,先前的結果否定:

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

這將給予rmt的能力,寫內核內存,一個明顯的安全漏洞。通常情況下, audit2allow聲明僅是一個起點。使用這些語句後,您可能需要更改源域和目標的標籤,以及合併適當的宏,以達到一個好的策略。有時,被審查的否認根本不應導致任何政策變化;而是應該更改違規應用程序。