SELinux 即Security-Enhanced Linux,由美國國家安全局(NSA)發起,Secure Computing Corporation (SCC) 和 MITRE直接參與開發,以及很多研究機構(如猶他大學)一起參與的強制性安全審查機制,該系統最初是作爲一款通用訪問軟件,發佈於2000年12月(代碼採用 GPL 許可發佈)。並在Linux Kernel 2.6 版本後,有直接整合進入SELinux, 搭建在Linux Security Module(LSM)基礎上,目前已經成爲最受歡迎,使用最廣泛的安全方案。而SEAndroid是Google在Android 4.4上正式推出的一套以SELinux爲基礎於核心的系統安全機制。
1、背景知識
進程理論上所擁有的權限與執行它的用戶的權限相同。比如,以root用戶啓動Browser,那麼Browser就有root用戶的權限,在Linux系統上能幹任何事情。也就是像4.4以前的版本,只要我們對結點給予足夠的權限,就可以隨意的進行任意的操作。
Linux DAC有明顯的不足,其中一個重要點就是,Root權限“無法無天”,幾乎可以做任意事情,一旦入侵者拿到root權限,即已經完全掌控了系統。另外每一個進程默認都拿到對應這個用戶的所有權限,可以改動/刪除這個用戶的所有文件資源,明顯這個難以防止惡意軟件。所以在DAC之外設計了一個新的安全模型,叫MAC(Mandatory Access control),強制性訪問控制,即系統針對每一項訪問都進行嚴格的限制,具體的限制策略由開發者給出。MAC的處世哲學非常簡單:即任何進程想在SELinux系統中幹任何事情,都必須先在安全策略配置文件中賦予權限。凡是沒有出現在安全策略配置文件中的權限,進程就沒有該權限。
LinuxMAC針對DAC的不足,要求系統對每一項訪問,每訪問一個文件資源都需要進行針對性的驗證。而這個針對性的驗證是根據已經定義好了的策略進行。在Linux Kernel,所有的MAC機制都是搭建在Linux Security Modules(LSM)基礎上,包括有:SELinux、Apparmor、Smack 和TOMOYOLinux等。目前SELinux已經成了事實上的行業標準。針對Linux DAC,MAC可以明顯彌補DAC的缺陷,一方面限制Root權限,即使你有root權限,如果無法通過MAC驗證,那麼一樣的無法真正執行相關的操作。另外對每一項權限進行了更加完整的細化,可限制用戶對資源的訪問行爲。
2、SELinux and SEAndroid的發展
估計在後續版本中,Google 都會要求強制性開啓SELinux,以保證手機的安全。
SELinux 給Android 帶來下面影響:
* 嚴格限制了ROOT 權限,以往ROOT “無法無天” 的情況將得到極大的改善。* 通過SELinux 保護,降低系統關鍵進程受攻擊的風險,普通進程將沒有權限直接連接到系統關鍵進程。
* 進一步強化APP 的沙箱機制,確保APP 難以做出異常行爲或者攻擊行爲。
* 將改變APP 一旦安裝,權限就已經頂死的歷史,APP權限動態調整將成爲可能。
3、SElinux、SEAndroid基本架構與原理
SELinux是典型的MAC實現,對系統中每個對象都生成一個安全上下文(Security Context), 每一個對象訪問系統的資源都要進行安全上下文審查。審查的規則包括類型強制檢測(type enforcement),多層安全審查(Multi-LevelSecurity),及基於角色的訪問控制(RBAC: Role Based Access Control)。
SELinux的整體結構如下圖所示:SELinux 包含五個基本組成:
* 用於處理文件系統的輔助模塊,即SELinuxFS。* 集成Linux Security Modules的hooks sets。
* Security Policy Database。
* Security Label驗證模塊。
* Access Vector Cache (AVC),訪問向量緩存,以便提高驗證速度。
* 進程通過系統調用(System Call)訪問某個資源,進入Kernel後,先會做基本的檢測,如果異常則直接返回。
* Linux Kernel DAC審查,如果異常則直接返回.
* 調用Linux Kernel Modules的相關hooks,對接到SELinux的hooks,進而進行MAC驗證,如果異常則直接返回。
* 訪問真正的系統資源。
* 返回用戶態,將結構反饋。
SELinux 給Linux 的所有對象都分配一個安全上下文(Security Context), 描述成一個標準的字符串。這裏的對象分爲兩種類型,Subject主體和Object訪問對象。主體通常是以進程爲單位,通常就是進程,而客體就是進程訪問的資源,通常是以文件爲單位。
在開啓了SEAndroid安全機制的設備上執行ls –Z就可以看到一個文件的上下文。
1、 u:同樣是user之意,它代表創建這個文件的SELinux user。
2、 object_r:文件是死的東西,它沒法扮演角色,所以在SELinux中,死的東西都用object_r來表示它的role。
3、 touch_device:死的東西的Type,和進程的Domain其實是一個意思。它表示root目錄對應的Type是touch_device。
4、 s0:MLS的級別。
在來看看進程的SContext,同樣在開啓SEAndroid安全機制後,可以利用ps -Z來查看進程的上下文。
圖6:進程SContext
圖六中最左邊的那一列是進程的SContext,以進程/system/bin/af7133d的SContext爲例,其值爲u:r:af7133d:s0,其中:
1、u爲user的意思。SEAndroid中定義了一個SELinux用戶,值爲u。
2、r爲role的意思。role是角色之意,它是SELinux中一種比較高層次,更方便的權限管理思路,即Role BasedAccess Control(基於角色的訪問控制,簡稱爲RBAC)。簡單點說,一個u可以屬於多個role,不同的role具有不同的權限。
3、af7133d,代表該進程所屬的Domain爲af7133d。MAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Accesc Control(簡稱TEAC,一般用TE表示)。對進程來說,Type就是Domain。比如init這個Domain有什麼權限,都需要通過[例子1]中allow語句來說明。
4、S0和SELinux爲了滿足軍用和教育行業而設計的Multi-Level Security(MLS)機制有關。簡單點說,MLS將系統的進程和文件進行了分級,不同級別的資源需要對應級別的進程才能訪問。
在SEAndroid中,只定義了一個SELinux用戶u,因此我們通過ps -Z和ls -Z命令看到的所有的進程和文件的安全上下文中的SELinux用戶都爲u。同時,SEAndroid也只定義了一個SELinux角色r,因此,我們通過ps-Z命令看到的所有進程的安全上下文中的SELinux角色都爲r。
有時可能注意到,前面我們通過ps -Z命令看到進程init的安全上下文爲“u:r:init:s0”,按照上面的分析,這是不是一個非法的安全上下文呢?答案是否定的,因爲在另外一個文件external/sepolicy/init.te中,通過type語句聲明瞭類型init,並且將domain設置爲類型init的屬性,如下所示:
- type init, domain;
由於init具有屬性domain,因此它就可以像domain一樣,可以和SELinux用戶u和SELinux角色組合在一起形成合法的安全上下文。
SContext的標準格式如下所示:
user:role:type[:range]
1、 User: 用戶, 非Linux UID。
2、Role: 角色,一個user可以屬於多個role,不同的role具有不同的權限。它是SELinux中一種比較高層次,更方便的權限管理思路,即Role BasedAccess Control(基於角色的訪問控制,簡稱爲RBAC, SELinux 不推薦使用)。
3、Type: Subject或者Object的類型。 MAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Access Control(簡稱TEAC,一般用TE表示)。對進程來說,Type就是Domain。
Range:Multi-Level Security(MLS)的級別。MLS將系統的進程和文件進行了分級,不同級別的資源需要對應級別的進程才能訪問。上面我們分析了SEAndroid安全機制中的對象安全上下文,接下來我們就繼續分析SEAndroid安全機制中的安全策略。SEAndroid安全機制中的安全策略是在安全上下文的基礎上進行描述的,也就是說,它通過主體和客體的安全上下文,定義主體是否有權限訪問客體。
SEAndroid安全機制主要是使用對象安全上下文中的類型來定義安全策略,這種安全策略就稱TypeEnforcement,簡稱TE。在external/sepolicy目錄中,所有以.te爲後綴的文件經過編譯之後,就會生成一個sepolicy文件。這個sepolicy文件會打包在ROM中,並且保存在設備上的根目錄下,即它在設備上的路徑爲/sepolicy。
通常,TE的描述一般在device/mediatek/common/sepolicy/和external/sepolicy中,SEAndroid爲系統定義了33個te策略文件,這33個策略文件是:
adbd.te、file.te、su.te、app.te、gpsd.te、netd.te、system.te、bluetoothd.te、init.te、net.te、ueventd.te、bluetooth.te、installd.te、nfc.te、unconfined.te、cts.te、kernel.te、qemud.te、vold.te、dbusd.te、keystore.te、radio.te、wpa_supplicant.te、debuggerd.te、mediaserver.te、rild.te、zygote.te、device.te、servicemanager.te、domain.te、shell.te、drmserver.te、surfaceflinger.te。
對上述33個文件根據其策略規則針對的對象可分爲三類:針對attribute的策略制定:ttribute是多個具有共性的type的集合,有unconfined.te、domain.te、CTS.te、bluetooth.te、net.te、file.te六個文件主要是直接針對attribute制定的策略,這種針對attribute制定的策略也就是同時對多個type制定策略一樣。針對daemon domain的策略制定:分別爲adbd.te、gpsd.te、netd.te、bluetoothd.te、zygote.te、ueventd.te、installd.te、vold.te、dbusd.te、keystore.te、debuggerd.te、mediaserver.te、rild.te、drmserver.te、surfaceflinger.te、qemud.te、servicemanager.te、su.te、shell.te、wpa_supplicant.te。這些文件都是爲系統中的daemon進程進行策略的制定,它們都有着相應的daemon domain。最後的7個文件分別對系統的其他模塊進行策略制定。app.te: 在這一文件裏將安裝在系統上的第三方app分類爲受信任的app和不受信任的app,分別用不同的type表示,再分別爲這兩種app在訪問網絡,bluetooth,sdcard,數據,緩存,binder等等名感位置時設置相應權限。system.te: 這一文件主要針對的是系統app和system server進程。對系統app訪問binder、systemdata files、dalvikcatch、keystone等進行權限控制,對system server訪問網絡、bluetooth、netlink、app、binder、device、data files、socket、cache files等進行權限控制。init.te: 在這一文件中聲明瞭init擁有無限權限。nfc.te: 在這一文件中制定了nfc domain對nfc設備和相關數據文件的訪問權限。kernel.te: 在這一文件中聲明瞭kernel擁有無限權限。radio.te: 在這一文件中制定了radio domain對init、rild和相關數據文件的訪問權限。device.te: 在這一文件中定義了所有跟設備相關的type,並將這些type都歸到了dev_type屬性中。而對於安全服務,用戶空間的Security Server主要是用來保護用戶空間資源的,以及用來操作內核空間對象的安全上下文的,它由應用程序安裝服務PackageManagerService、應用程序安裝守護進程installd、應用程序進程孵化器Zygote進程以及init進程組成。其中,PackageManagerService和installd負責創建App數據目錄的安全上下文,Zygote進程負責創建App進程的安全上下文,而init進程負責控制系統屬性的安全訪問。
4、SELinux問題解決方法
- [ 215.214223]<0> (0)[307:logd.auditd]type=1400 audit(1420070451.950:8): avc: denied { write } for pid=4663 comm="om.zte.engineer" name="brightness" dev="sysfs" ino=9451 scontext=u:r:radio:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0
* [307:logd.auditd]:表示此LOG 是通過auditd 打印的;
* type=1400 : SYSCALL ;如果type=AVC 表示爲kernelevents, type=USER_AVC 表示user-space object manager events ;
* audit(1420070451.950:8):audit(time:serial_number);
* avc: denied { write }: field depend on what type of event is being audited.;
* pid=4663 comm="om.zte.engineer":如果是個進程,pid表示爲進程號,comm爲運行的進程名字;
* scontext=u:r:radio:s0:subject context爲u:r:radio:s0;
* tcontext=u:object_r:sysfs:s0:target context 爲u:object_r:sysfs:s0;
* tclass : the object class of the target class=system;
* permissive: permissive (1)or enforcing (0)。
簡化方法:
1、 提取所有的avc LOG. 如 adb shell "cat /proc/kmsg | grepavc" > avc_log.txt
2、 使用 audit2allow tool 直接生成policy. audit2allow -i avc_log.txt 即可自動輸出生成的policy
3、 將對應的policy 添加到selinux policy 規則中,對應MTK Solution, 您可以將它們添加在KK: mediatek/custom/common/sepolicy, L:device/mediatek/common/sepolicy 下面,如
allow zygoteresource_cache_data_file:dir rw_dir_perms;
allow zygote resource_cache_data_file:filecreate_file_perms;
===>mediatek/custom/common/sepolicy/zygote.te (KK)
===> device/mediatek/common/sepolicy/zygote.te (L)
這樣做就可以達到允許zygote對resource_cache_data_file進行create、r/w操作。注意audit2allow它自動機械的幫您將LOG 轉換成policy, 而無法知道你操作的真實意圖,有可能出現權限放大問題,經常出現policy 無法編譯通過的情況。
如果直接按照avc: denied 的LOG 轉換出SELinux Policy, 往往會產生權限放大問題. 比如因爲要訪問某個device, 在這個device 沒有細化SELinux Label 的情況下, 可能出現:
<7>[11281.586780] avc: denied { read write } for pid=1217comm="mediaserver" name="tfa9897" dev="tmpfs"ino=4385 scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0tclass=chr_file permissive=0
如果直接按照此LOG 轉換出SELinuxPolicy: allowmediaserver device:chr_file {read write}; 那麼就會放開mediaserver 讀寫所有device 的權限。而Google 爲了防止這樣的情況, 使用了neverallow 語句來約束, 這樣你編譯sepolicy 時就無法編譯通過。
下面主要介紹一下如何缺什麼補什麼,一步一步到沒有avc: denied問題,以上面的avc log爲例:
- [ 215.214223]<0> (0)[307:logd.auditd]type=1400 audit(1420070451.950:8): avc: denied { write } for pid=4663 comm="om.zte.engineer" name="brightness" dev="sysfs" ino=9451 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0
缺少什麼權限: { write}權限;
誰缺少權限: scontext=u:r:radio:s0;
對哪個文件缺少權限: tcontext=u:object_r:sysfs:s0
什麼類型的文件: tclass=file
所以解決方法是在:radio.te中加入
allow radio sysfs:file write;
通過上面例子,我們可以總結出一般規律:允許某個scontext對某個tcontext擁有某個權限。
所以,可以得到一個萬能套用公式:Scontext tcontext tclass avc denied權限
allow radio sysfs : file write
有時候avc denied的log不是一次性顯示所以問題,可能是要等你解決一個權限問題之後,纔會提示另外一個權限問題,所以有時我們必須一次一次的試,一次一次的加。
SEAndroid在te文件中定義了安全策略中最基本的參量type,同時將具有共性的type歸在一起構成一個稱爲attribute的集合,policy的規則執行也能以attribute作爲執行對象。SEAndroid爲所有type共定義了17個attribute:
dev_type |
這一attribute包含了所有關於設備的type |
domain |
這一attribute包含了如下所列的所有關於進程的type,通常策略中的訪問主體也就是進程所在的domain都包含在了這一attribute中 |
fs_type |
這一attribute包含了所有與文件系統相關的type。如下所列,大多是虛擬文件系統 |
file_type |
這一attribute包含了所有存在於非僞文件系統的相關文件的type |
exec_type |
這一attribute包含了所有關於domian接入點的type,多被用在domain transition中 |
data_file_type |
這一attribute包含了所有在/data目錄下的文件type |
sysfs_type |
這一attribute包含了在sysfs文件系統下的所有文件的type,在SEAndroid中只有sysfs_writable包含在這個attribute中 |
node_type |
這一attribute包含了所有與nodes/hosts有關的type,在SEAndroid中只有node包含在這個attribute中 |
netif_type |
這一attribute包含了所有與網絡接口相關的type,在SEAndroid中只有netif包含在這個attribute中 |
port_type |
這一attribute包含了所有與網絡端口相關的type,在SEAndroid中只有port包含在這個attribute中 |
mlstrustedsubject |
這一attribute包含了所有能越過MLS檢查的主體domain |
unconfineddomain |
這一attribute包含了所有擁有無限權限的type |
appdomain |
這一attribute包含了所有與app相關的type |
netdomain |
這一attribute包含了所有與需要訪問網絡的app相關的type |
bluetoothdomain |
這一attribute包含了所有與需要訪問bluetooth的app相關的type |
binderservicedomain |
這一attribute包含了所有與binder服務相關的type |
而在L 版本中,我們經常遇到下面幾種訪問對象通常與綁定的類:
1、 device
類型定義 |
external/sepolicy/device.te device/mediatek/common/sepolicy/device.te |
類型綁定 |
external/sepolicy/file_contexts device/mediatek/common/sepolicy/file_contexts |
2、 File 類型:
類型定義 |
external/sepolicy/file.te device/mediatek/common/sepolicy/file.te |
類型綁定 |
external/sepolicy/file_contexts device/mediatek/common/sepolicy/file_contexts |
3、 虛擬File類型:
類型定義 |
external/sepolicy/file.te device/mediatek/common/sepolicy/file.te |
類型綁定 |
external/sepolicy/genfs_contexts device/mediatek/common/sepolicy/genfs_contexts |
4、 Service類型
類型定義 |
external/sepolicy/service.te device/mediatek/common/sepolicy/service.te |
類型綁定 |
external/sepolicyservice_contexts device/mediatek/common/sepolicy/service_contexts |
5、 Property類型
類型定義 |
external/sepolicy/property.te device/mediatek/common/sepolicy/property.te |
類型綁定 |
external/sepolicy/property_contexts device/mediatek/common/sepolicy/property_contexts |