Selinux SeAndroid理解

 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、背景知識

         SELinux出現之前,Linux上的安全模型叫DAC,全稱是Discretionary Access Control,自主訪問控制。自主訪問控制, 即系統只提供基本的驗證, 完整的訪問控制由開發者自己控制。Linux DAC採用了一種非常簡單的策略, 將資源訪問者分成三類, 分別是Owner, Group,Other;資源針對這三類訪問者設置不同的訪問權限。而訪問權限又分成read、 write、 execute。訪問者通常是進程有自己的uid/gid, 通過uid/gid和文件權限匹配, 來確定是否可以訪問。將Root權限根據不同的應用場景劃分成許多的Root Capabilities, 其中如果有CAP_DAC_OVERRIDE這項的話, 可以直接繞過Linux DAC限制。DAC的核心思想很簡單,就是:

       進程理論上所擁有的權限與執行它的用戶的權限相同。比如,以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驗證,那麼一樣的無法真正執行相關的操作。另外對每一項權限進行了更加完整的細化,可限制用戶對資源的訪問行爲。
      我們知道android是基於linux實現的,NSA爲了linux的安全性開發了一套安全機制SElinux,但由於Android系統有着獨特的用戶空間,因此SELinux不能完全適用於Android系統。爲此,NSA針對Android系統,在SElinux基礎上開發了SEAndroid。 
     SEAndroid安全機制所要保護的對象是系統中的資源,這些資源分佈在各個子系統中,例如我們經常接觸的文件就是分佈文件子系統中的。實際上,系統中需要保護的資源非常多,除了前面說的文件之外,還有進程、socket和IPC等等。對於Android系統來說,由於使用了與傳統Linux系統不一樣的用戶空間運行時,即應用程序運行時框架,因此它在用戶空間有一些特有的資源是需要特別保護的,例如系統屬性的設置等等。

2、SELinux and SEAndroid的發展

       Android是建立在標準的Linux Kernel基礎上,自然也可以開啓SELinux,通常在通用移動平臺上,很少開啓這樣的安全服務,Google爲了進一步增強Android的安全性,經過長期的準備,目前已經在Android 5.0(L)上有完整的開啓SELinux,並對SELinux進行深入整合形成了SEAndroid。
      SELinux的更新史如下圖所示:

                                                                                                                              圖一:SELinux發展圖
        上圖中有Permissive跟Enforce兩種模式,Permissive 模式,只打印audit 異常LOG,不拒絕請求, Enforce 模式,即打印audit 異常LOG, 也拒絕請求。AndroidKK版本只對netd、installd、zygote、vold四個原本具有root權限的process,以及它們fork出的子進程啓用Enforce模式。但到了L 5.0以上版本普遍性開啓SELinux Enforce mode。
    
                                                                                                                    圖2:Android 啓動模式變化
    

估計在後續版本中,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的整體結構如下圖所示:
     
圖3:SELinux整體結構體
      

SELinux 包含五個基本組成:

     * 用於處理文件系統的輔助模塊,即SELinuxFS。
     * 集成Linux Security Modules的hooks sets。
     * Security Policy Database。
     * Security Label驗證模塊。
     *  Access Vector Cache (AVC),訪問向量緩存,以便提高驗證速度。
基本的訪問流程如下圖所示:

圖4:基本訪問流程圖
  具體 流程如下:
    * 進程通過系統調用(System Call)訪問某個資源,進入Kernel後,先會做基本的檢測,如果異常則直接返回。
    * Linux Kernel DAC審查,如果異常則直接返回.
    * 調用Linux Kernel Modules的相關hooks,對接到SELinux的hooks,進而進行MAC驗證,如果異常則直接返回。
    * 訪問真正的系統資源。
    * 返回用戶態,將結構反饋。 
        SEAndroid安全機制是基於SELinux實現的,SEAndroid所要保護的對象是系統中的資源,這些資源分佈在各個子系統中,例如我們經常接觸的文件就是分佈文件子系統中的。實際上,系統中需要保護的資源非常多,除了前面說的文件之外,還有進程、socket和IPC等等。對於Android系統來說,由於使用了與傳統Linux系統不一樣的用戶空間運行時,即應用程序運行時框架,因此它在用戶空間有一些特有的資源是需要特別保護的,例如系統屬性的設置。
       SEAndroid安全機制也是分爲內核空間跟用戶空間兩部分,以SELinux文件系統接口爲邊界。內核空間的實現是基於LSM實現的,上面主要是內核空間實現。而在用戶空間,涉及到安全上下文(Security Context)、安全策略(SEAndroid Policy)和安全服務(Security Server)等模塊。下面主要分析一下這三個模塊。

      SELinux 給Linux 的所有對象都分配一個安全上下文(Security Context), 描述成一個標準的字符串。這裏的對象分爲兩種類型,Subject主體和Object訪問對象。主體通常是以進程爲單位,通常就是進程,而客體就是進程訪問的資源,通常是以文件爲單位。

       在開啓了SEAndroid安全機制的設備上執行ls –Z就可以看到一個文件的上下文。

圖5:文件SContext
  圖5中最右邊的那一列是文件的SContext,以結點touch的SContext爲例,其值爲u:object_r:touch_device:s0,其中:

     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的屬性,如下所示:

[cpp] view plain copy
  1. 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問題解決方法

      查找SELinux權限問題,一般的方法是通過查看LOG中是否有標準的SELinux Policy Exception。在Kernel Log / Main Log 中查詢關鍵字"avc:",如果出現以下log,則基本說明該問題就是SELinux權限問題引起的,在解決安全權限問題前,我們必須先讀懂log中的信息:
[cpp] view plain copy
  1. [  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  
    * [  215.214223]:kernel time ;

    * [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)。

上面語句的大概意思爲:om.zte.engineer這個process,使用radio的source context,訪問sysfs這個文件類型時,並write文件時,被SELinux拒絕訪問。
        而對於如何解決該類權限問題,一般的做法是,缺少什麼就補什麼,先介紹一下簡化方法:

簡化方法:

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爲例:

[cpp] view plain copy
  1. [  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


  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章