1. 概述
SELinux是Google從android 5.0開始,強制引入的一套很是嚴格的權限管理機制,主要用於加強系統的安全性。android
然而,在開發中,咱們常常會遇到因爲SELinux形成的各類權限不足,即便擁有「萬能的root權限」,也不能獲取所有的權限。本文旨在結合具體案例,講解如何根據log來快速解決90%的SELinux權限問題。shell
2. 調試確認SELinux問題
爲了澄清是否由於SELinux致使的問題,可先執行:安全
setenforce 0 (臨時禁用掉SELinux)app
getenforce (獲得結果爲Permissive)dom
若是問題消失了,基本能夠確認是SELinux形成的權限問題,須要經過正規的方式來解決權限問題。ide
遇到權限問題,在logcat或者kernel的log中必定會打印avc denied提示缺乏什麼權限,能夠經過命令過濾出全部的avc denied,再根據這些log各個擊破:測試
cat /proc/kmsg | grep avc ui
或調試
dmesg | grep avcorm
例如:
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
能夠看到有avc denied,且最後有permissive=0,表示不容許。
3. 具體案例分析
解決原則是:缺什麼權限補什麼,一步一步補到沒有avc denied爲止。
解決權限問題須要修改的權限文件以下位置,以.te結尾
A:Android/devicesoftwinner/astar-common/sepolicy/*.te
B:Android/external/sepolicy/*.te
其中,A是對B的overlay(覆蓋),能在A修改的儘可能在A修改,儘可能避免修改B,修改B可能會致使CTS fail問題,修改A不會影響CTS測試。
(若是不須要深刻了解,請直接跳到萬能公式這一章閱讀更簡潔)
下面給出四個案例:
案例1
audit(0.0:67): avc: denied { write } for path="/dev/block/vold/93:96" dev="tmpfs" ino=/1263 scontext=u:r:kernel:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0
分析過程:
缺乏什麼權限: { write }權限,
誰缺乏權限: scontext=u:r:kernel:s0
對哪一個文件缺乏權限:tcontext=u:object_r:block_device
什麼類型的文件: tclass=blk_file
完整的意思: kernel進程對block_device類型的blk_file缺乏write權限。
解決方法:在上文A位置,找到kernel.te這個文件,加入如下內容:
allow kernel block_device:blk_file write;
make installclean後從新編譯,刷boot.img纔會生效。
案例2
audit(0.0:53): avc: denied { execute } for path="/data/data/com.mofing/qt-reserved-files/plugins/platforms/libgnustl_shared.so" dev="nandl" ino=115502 scontext=u:r:platform_app:s0 tcontext=u:object_r:app_data_file:s0 tclass=file permissive=0
分析過程:
缺乏什麼權限: { execute}權限,
誰缺乏權限: scontext = u:r:platform_app:s0
對哪一個文件缺乏權限:tcontext = u:object_r:app_data_file
什麼類型的文件: tclass= file
完整的意思: platform_app進程對app_data_file類型的file缺乏execute權限。
解決方法:在上文A位置,找到platform_app.te這個文件,加入如下內容:
allow platform_app app_data_file:file execute;
make installclean後從新編譯,刷boot.img纔會生效。
案例3
audit(1444651438.800:8): avc: denied { search } for pid=158 comm="setmacaddr" name="/" dev="nandi" ino=1 scontext=u:r:engsetmacaddr:s0 tcontext=u:object_r:vfat:s0 tclass=dir permissive=0
解決方法 :engsetmacaddr.te
allow engsetmacaddr vfat:dir { search write add_name create }; 或者
allow engsetmacaddr vfat:dir create_dir_perms;
(create_dir_perms包含search write add_name create可參考external/sepolicy/global_macros的定義聲明)
案例4
audit(1441759284.810:5): avc: denied { read } for pid=1494 comm="sdcard" name="0" dev="nandk" ino=245281 scontext=u:r:sdcardd:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0
解決方法 :sdcardd.te
allow sdcardd system_data_file:dir read; 或者
allow sdcardd system_data_file:dir rw_dir_perms;
(rw_dir_perms包含read write,可參考external/sepolicy/global_macros的定義聲明)
4. 萬能公式
經過這四個案例,咱們能夠總結出通常規律,
以第案例4爲例:
audit(1441759284.810:5): avc: denied { read } for pid=1494 comm="sdcard" name="0" dev="nandk" ino=245281 scontext=u:r:sdcardd:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0
某個scontext對某個tclass類型的tcontext缺少某個權限,咱們須要容許這個權限:
咱們的log從新排列一下,
scontext = u:r:sdcardd
tcontex t= u:object_r:system_data_file:s0
tclass = dir
avc: denied { read }
獲得萬能套用公式以下:
在scontext所指的.te文件(例如sdcardd.te)中加入相似以下allowe內容:
5. TIPS
1. 以上以.te爲後綴的文件都在如下位置:
A:Android/devicesoftwinner/astar-common/sepolicy/*.te
B:Android/external/sepolicy/*.te
其中,A是對B的overlay(覆蓋),能在A修改的儘可能在A修改,修改B可能會致使CTS fail問題,修改A不會影響CTS測試。修改以後,爲了節約驗證時間,只重刷boot.img便可看效果;
2. 有時候avc denied的log不是一次性暴露全部權限問題,要等解決一個權限問題以後,纔會暴露另一個權限問題。好比提示缺乏某個目錄的read權限,加入read以後,才顯示缺乏write權限,要一次次一次試,一次一次加,時間成本極大。
針對dir缺乏的任何權限,建議賦予create_dir_perms,基本涵蓋對dir的全部權限,好比:
{ open search write read rename create rmdir getattr }等等。
針對file缺乏的任何權限,建議賦予rwx_file_perms,基本涵蓋對file的全部權限,好比:
包含{ open read write open execute getattr create ioctl }等等。
更多內容請參考external/sepolicy/global_macros來了解更多權限聲明。
3. 要加入的權限不少時,能夠用中括號,好比:
allow engsetmacaddr vfat:dir { search write add_name create};
4. 修改A位置的.te文件遇到編譯錯誤怎麼辦?
(首先請排除拼寫錯誤)說明此項權限是SELinux明確禁止的,也是Google CTS禁止的,若是產品不須要過CTS,能夠修改。通常來講,編譯出錯的log會提示相關哪一個文件哪一行出錯,文件位置必定會在B裏的.te文件。好比B規定了如下neverallow,
neverallow system_server sdcard_type:dir { open read write };
那麼system_server是不能擁有這些權限的,若是賦予這些權限就編譯報錯,解決方法是根據編譯錯誤提示的行號,把這一句註釋掉便可。
6. 高級進階
6.1. 新建.te安全策略文件方法
以上基本是對已經存在的進程增長權限,但對第三方進程改如何新增一個全新的te文件並賦予權限呢?
以寫mac地址的setmacaddr執行文件爲例(這個執行檔android原生不存在,自行添加的):
在init.xxx.rc中以下服務:
service engsetmacaddr /system/bin/setmacaddr /data/misc/wifi/wifimac.txt
class main
disabled
oneshot
1. 在device/softwinner/astar-common/sepolicy/file_contexts中,參考其餘進程聲明一個scontext:
……
/system/bin/install-recovery.sh u:object_r:install_recovery_exec:s0
/system/bin/dex2oat u:object_r:dex2oat_exec:s0
/system/bin/patchoat u:object_r:dex2oat_exec:s0
/system/bin/setmacaddr u:object_r:engsetmacaddr_exec:s0
指定setmacaddr的路徑,並指定一個名字,必定要以service名+_exec結尾
2.參考其.te文件在device/softwinner/astar-common/sepolicy/file_contexts 建立engsetmacaddr.te文件,內容以下:
type engsetmacaddr, domain;
type engsetmacaddr_exec, exec_type, file_type;
init_daemon_domain(engsetmacaddr)
allow engsetmacaddr vfat:dir { search write add_name create};
allow engsetmacaddr vfat:file { create read write open };
allow engsetmacaddr engsetmacaddr:capability dac_override;
allow engsetmacaddr shell_exec:file { execute read open execute_no_trans};
allow engsetmacaddr system_data_file:dir { write add_name remove_name };
allow engsetmacaddr system_data_file:file { create execute_no_trans write open setattr};
allow engsetmacaddr system_file:file { execute_no_trans};
以上賦予的權限所有是根據avc denied的log缺什麼一步一步補什麼來的。
6.2. 新設備節點增長訪問權限
驅動建立了一個新的設備節點,即便權限是777,android層也是沒有訪問權限的。
下面以一個/dev/wifi_bt節點爲示範,讓此節點被用戶空間的system_server進程訪問。
1. 編輯devicesoftwinner/astar-common/sepolicy/device.te,仿照這個文件裏的寫法,定義一個dev_type類型的wifi_bt_device設備:
type misc_block_device, dev_type;
type private_block_device, dev_type;
……
type wf_bt_device, dev_type;
2. 編輯file_contexts.te,將/dev/wf_bt節點聲明爲第1步定義的wf_bt_device:
/dev/block/by-name/misc u:object_r:misc_block_device:s0
/dev/block/by-name/alog u:object_r:log_block_device:s0
/dev/block/by-name/private u:object_r:private_block_device:s0
# We add here
/dev/wf_bt u:object_r:wf_bt_device:s0
3. 在system_server.te,根據dmesg | grep avc容許system_server對wf_bt_device這個節點可讀可寫:
# Read/Write to /proc/net/xt_qtaguid/ctrl and and /dev/xt_qtaguid.
allow system_server qtaguid_proc:file rw_file_perms;
allow system_server qtaguid_device:chr_file rw_file_perms;
……
allow system_server wf_bt_device:chr_file rw_file_perms;
其餘進程如需訪問/dev/wf_bt節點,依樣畫葫蘆,增長對wf_bt_device的權限便可。