深刻理解SELinux SEAndroid

按哥的習慣,應該是所有洗剪吹完後再發,不過今年是馬年,什麼都強調 立刻。因此 如今就先奉獻 立刻有第一部分  祝各位同仁,朋友 馬年快樂。html

 

深刻理解SELinux SEAndroid

SEAndroidGoogleAndroid 4.4上正式推出的一套以SELinux爲基礎於核心的系統安全機制。而SELinux則是由美國NSA(國安局)和一些公司(RedHatTresys)設計的一個針對Linux的安全增強系統。java

NSA最初設計的安全模型叫FLASK,全稱爲Flux Advanced Security Kernel(由Uta大學和美國國防部開發,後來由NSA將其開源),當時這套模型針對DTOS系統。後來,NSA以爲Linux更具發展和普及前景,因此就在Linux系統上從新實現了FLASK,稱之爲SELinuxnode

Linux Kernel中,SELinux經過Linux Security Modules實現。在2.6以前,SElinux經過Patch方式發佈。從2.6開始,SELinux正式入駐內核,成爲標配。linux

思考:android

一樣是政府部門,差異咋這麼大?shell

一樣涉及操做系統和安全相關,NSA爲什麼敢用Linux,爲何千方百計要開源?express

因爲Linux有多種發行版本,因此各家的SELinux表現形式也略有區別。具體到Android平臺,Google對其進行了必定得修改,從而獲得SEAndroidapache

本文將先對SELinux相關知識進行介紹,而後看看Android是如何實現SELinux的(我們只看用戶空間)。編程

要求:最好能下到Android 4.4源碼,可http://blog.csdn.net/innost/article/details/14002899緩存

目標:學完本文,讀者應該能夠輕鬆修改相關安全策略文件,以進一步在安全方面定製本身的Android系統。

 

一 SELinux背景知識

1.  DAC和MAC

SELinux出現以前,Linux上的安全模型叫DAC,全稱是Discretionary Access Control,翻譯爲自主訪問控制。DAC的核心思想很簡單,就是:

  • 進程理論上所擁有的權限與執行它的用戶的權限相同。好比,以root用戶啓動Browser,那麼Browser就有root用戶的權限,在Linux系統上能幹任何事情。

顯然,DAC太過寬鬆了,因此各路高手千方百計都要在Android系統上搞到root權限。那麼SELinux如何解決這個問題呢?原來,它在DAC以外,設計了一個新的安全模型,叫MACMandatory Access Control),翻譯爲強制訪問控制。MAC的處世哲學很是簡單:即任何進程想在SELinux系統中幹任何事情,都必須先在安全策略配置文件中賦予權限。凡是沒有出如今安全策略配置文件中的權限,進程就沒有該權限。來看一個SEAndroid中設置權限的例子:

[例子1]

/*

  from external/sepolicy/netd.te

 下面這條SELinux語句表示 容許(allow )netd域(domain)中的進程  」寫(write)「 

 類型爲proc的文件

 注意,SELinux中安全策略文件有本身的一套語法格式,下文咱們將詳細介紹它

*/

allow netd proc:file write

若是沒有在netd.te中使用上例中的權限配置allow語句,則netd就沒法往/proc目錄下得任何文件中寫數據,即便netd具備root權限。

顯然,MACDAC在權限管理這一塊要複雜,要嚴格,要細緻得多。

那麼,關於DACMAC,此處筆者總結了幾個知識點:

  • Linux系統先作DAC檢查。若是沒有經過DAC權限檢查,則操做直接失敗。經過DAC檢查以後,再作MAC權限檢查。
  • SELinux中也有用戶的概念,但它和Linux中原有的user概念不是同一個東西。什麼意思呢?好比,Linux中的超級用戶rootSELinux中可能就是一個沒權限,沒地位,打打醬油的」路人甲「。固然,這一切都由SELinux安全策略的制定者來決定。

經過上述內容,讀者應該能感受到,在SELinux中,安全策略文件是最重要的。確實如此。事實上,對本文的讀者而言,學習SELinux的終極目標應該是:

  • 看懂現有的安全策略文件。
  • 編寫符合特定需求的安全策略文件。

前面也曾提到,SELinux有本身的一套規則來編寫安全策略文件,這套規則被稱之爲SELinux Policy語言。它是掌握SELinux的重點。

2.  SELinux Policy語言介紹

Linux中有兩種東西,一種死的(Inactive),一種活的(Active)。死的東西就是文件(Linux哲學,萬物皆文件。注意,萬不可狹義解釋爲File),而活的東西就是進程。此處的「死」和「活」是一種比喻,映射到軟件層面的意思是:進程能發起動做,例如它能打開文件並操做它。而文件只能被進程操做。

SELinux中,每種東西都會被賦予一個安全屬性,官方說法叫Security ContextSecurity Context(之後用SContext表示)是一個字符串,主要由三部分組成。例如SEAndroid中,進程的SContext可經過ps -Z命令查看,如圖1所示:

1  Nexus 7 ps -Z結果圖

1中最左邊的那一列是進程的SContext,以第一個進程/system/bin/logwrapperSContext爲例,其值爲u:r:init:s0,其中:

  • uuser的意思。SEAndroid中定義了一個SELinux用戶,值爲u
  • rrole的意思。role是角色之意,它是SELinux中一種比較高層次,更方便的權限管理思路,即Role Based Access Control(基於角色的訪問控制,簡稱爲RBAC)。簡單點說,一個u能夠屬於多個role,不一樣的role具備不一樣的權限。RBAC咱們到最後再討論。
  • init,表明該進程所屬的DomaininitMAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Accesc Control(簡稱TEAC,通常用TE表示)。對進程來講,Type就是Domain。好比init這個Domain有什麼權限,都須要經過[例子1]allow語句來講明。
  • S0SELinux爲了知足軍用和教育行業而設計的Multi-Level SecurityMLS)機制有關。簡單點說,MLS將系統的進程和文件進行了分級,不一樣級別的資源須要對應級別的進程才能訪問。後文還將詳細介紹MLS

再來看文件的SContext,讀者可經過ls -Z來查看,如圖2所示:

2 Nexus 7 ls -Z結果圖

2中,倒數第二列所示爲Nexus 7根目錄下幾個文件和目錄的SContext信息,以第一行root目錄爲例,其信息爲u:object_r:rootfs:s0

  • u:一樣是user之意,它表明建立這個文件的SELinux user
  • object_r:文件是死的東西,它無法扮演角色,因此在SELinux中,死的東西都用object_r來表示它的role
  • rootfs:死的東西的Type,和進程的Domain實際上是一個意思。它表示root目錄對應的Typerootfs
  • s0MLS的級別。

根據SELinux規範,完整的SContext字符串爲:

user:role:type[:range]

注意,方括號中的內容表示可選項。s0屬於range中的一部分。下文再詳細介紹range所表明的Security Level相關的知識。

看,SContext的核心實際上是前三個部分:user:role:type

剛纔說了,MAC基本管理單位是TEACType Enforcement Accesc Control),而後是高一級別的Role Based Accesc ControlRBAC是基於TE的,而TE也是SELinux中最主要的部分。

下面來看看TE

2.1  TE介紹

在例子1中,你們已經見過TEallow語句了,再來細緻研究下它:

[例子2]

allow netd proc:file write

這條語句的語法爲:

  • allowTEallow語句,表示受權。除了allow以外,還有allowauditdontauditneverallow等。
  • netdsource type。也叫subjectdomain
  • proctarget type。它表明其後的file所對應的Type
  • file:表明Object Class。它表明可以給subject操做的一類東西。例如FileDirsocket等。在Android系統中,有一個其餘Linux系統沒有的Object Class,那就是Binder
  • write:在該類Object Class中所定義的操做。

根據SELinux規範,完整的allow相關的語句格式爲:

rule_name source_type target_type : class perm_set

咱們直接來看幾個實例:

[例子3]

//SEAndroid中的安全策略文件policy.conf

#容許zygote域中的進程向init type的進程(Object Class爲process)發送sigchld信號

allow zygote init:process sigchld;

#容許zygote域中的進程search或getattr類型爲appdomain的目錄。注意,多個perm_set

#可用{}括起來

allow zygote appdomain:dir { getattr search };

#來個複雜點的:

#source_type爲unconfineddomain target_type爲一組type,由
#{ fs_type dev_type file_type }構成。object_class也包含兩個,爲{ chr_file file }

#perm_set語法比較奇特,前面有一個~號。它表示除了{entrypoint relabelto}以外,{chr_file #file}這兩個object_class所擁有的其餘操做

allow unconfineddomain {fs_type dev_type file_type}:{ chr_file file }   \

 ~{entrypoint relabelto};

#特殊符號除了~外,還有-號和*號,其中:

# 1):-號表示去除某項內容。

# 2):*號表示全部內容。

#下面這條語句中,source_type爲屬於appdomain,但不屬於unconfinedomain的進程。

#而 *表示全部和capability2相關的權限

#neverallow:表示毫不容許。

neverallow { appdomain -unconfineddomain } self:capability2 *;

特別注意,前面曾提到說權限必須顯示聲明,沒有聲明的話默認就沒有權限。那neverallow語句就不必存在了。由於」無權限「是不須要聲明的。確實如此,neverallow語句的做用只是在生成安全策略文件時進行檢查,判斷是否有違反neverallow語句的allow語句。例如,筆者修改shell.te中一個語句後,生成安全策略文件時就檢測到了衝突,如圖3所示:

3  neverallow的做用

如圖3所示,筆者修改shell.te後,意外致使了一條allow語句與neverallow語句衝突,從而生成安全策略文件失敗。

下面咱們來看上述allow語句中所涉及到的object classperm set

(1)  Object class和Perm Set

Object class很難用語言說清楚它究竟是怎麼定義的,因此筆者也不廢話,直接告訴你們常見的Object class有哪些。見下面的SEPolicy示例:

[external/sepolicy/security_classes示例]

.......

#此文件定義了Android平臺中支持的Object class

#根據SELinux規範,Object Class類型由class關鍵字申明

# file-related classes

class filesystem

class file  #表明普通文件

class dir   #表明目錄

class fd    #表明文件描述符

class lnk_file  #表明連接文件

class chr_file  #表明字符設備文件

 ......

 

# network-related classes

class socket   #socket

class tcp_socket

class udp_socket

......

class binder   #Android平臺特有的binder

class zygote   #Android平臺特有的zygote

 

#Android平臺特有的屬性服務。注意其後的userspace這個詞

class property_service # userspace和用戶空間中的SELinux權限檢查有關,下文再解釋

上述示例展現了SEAndroidObject Class的定義,其中:

  • Object Class須要經過class語句申明。這些申明通常放在一個叫security_class的文件中。
  • 另外,這些classkernel中相關模塊緊密結合。

聽說:在kernel編譯時會根據security_class文件生成對應的頭文件。從這裏能夠看出,SELinux須要根據發行平臺來作相應修改。同時能夠看出,該文件通常也不須要咱們去修改。

再來看Perm setPerm set指得是某種Object class所擁有的操做。以file這種Object class而言,其擁有的Perm set就包括readwriteopencreate,execute等。

Object class同樣,SELinuxSEAndroid所支持的Perm set也須要聲明,來看下面的例子:

[external/sepolicy/access_vectors]

#SELinux規範中,定義perm set有兩種方式,一種是使用下面的common命令

#其格式爲:common common_name { permission_name ... } common定義的perm set能

#被另一種perm set命令class所繼承

#如下是Android平臺中,file對應的權限(perm set)。其大部分權限讀者能猜出是幹什麼的。

#有一些權限須要結合文後的參考文獻來學習

common file {

      ioctl read write create getattr setattr lock relabelfrom relabelto

      append unlink link rename execute swapon quotaon mounton }

 

#除了common外,還有一種class命令也可定義perm set,以下面的例子:

#class命令的完整格式是:

#class class_name [ inherits common_name ] { permission_name ... }

#inherits表示繼承了某個common定義的權限  注意,class命令定義的權限其實針對得就是

#某個object class。它不能被其餘class繼承

class dir inherits file {

   add_name  remove_name reparent search rmdir open audit_access execmod

}

#來看SEAndroid中的binder和property_service這兩個Object class定義了哪些操做權限

class binder {

      impersonate  call set_context_mgr transfer }

class property_service { set }

提示:Object classPerm set的具體內容(SELinux中其實叫Access Vector)都和Linux系統/Android系統密切相關。因此,從知識鏈的角度來看,Linux編程基礎很重要。

(2)  type,attribute和allow等

如今再來看type的定義,和type相關的命令主要有三個,以下面的例子所示:

[external/sepolicy相關文件]

#type命令的完整格式爲:type type_id [alias alias_id,] [attribute_id]

#其中,方括號中的內容爲可選。alias指定了type的別名,能夠指定多個別名。

#下面這個例子定義了一個名爲shell的type,它和一個名爲domain的屬性(attribute)關聯

type shell, domain; #本例來自shell.te,注意,能夠關聯多個attribute

 

#屬性由attribute關鍵字定義,如attributes文件中定義的SEAndroid使用的屬性有:

attribute domain

attribute file_type

 

#能夠在定義type的時候,直接將其和某個attribute關聯,也能夠單獨經過

#typeattribue將某個type和某個或多個attribute關聯起來,以下面這個例子

#將前面定義的system類型和mlstrustedsubject屬性關聯了起來

typeattribute system mlstrustedsubject

特別注意:對初學者而言,attributetype的關係最難理解,由於「attribute」這個關鍵詞實在是沒取好名字,很容易產生誤解:

  • 實際上,typeattribute位於同一個命名空間,即不能用type命令和attribute命令定義相同名字的東西。
  • 其實,attribute真正的意思應該是相似type(或domain group這樣的概念。好比,將type Aattribute B關聯起來,就是說type A屬於group B中的一員。

使用attribute有什麼好處呢?通常而言,系統會定義數十或數百個Type,每一個Type都須要經過allow語句來設置相應的權限,這樣咱們的安全策略文件編起來就會很是麻煩。有了attribute以後呢,咱們能夠將這些Type與某個attribute關聯起來,而後用一個allow語句,直接將source_type設置爲這個attribute就能夠了:

  • 這也正是typeattribute位於同一命名空間的緣由。
  • 這種作法實際上只是減輕了TE文件編寫者的煩惱,安全策略文件在編譯時會將attribute拓展爲其包含的type。如例子4所示:

[例子4]

#定義兩個type,分別是A_t和B_t,它們都管理到attribute_test

type A_t attribute_test;

type B_t attribute_test;

 

#寫一個allow語句,直接針對attribute_test

allow attribute_test C_t:file {read write};

#上面這個allow語句在編譯後的安全策略文件中會被以下兩條語句替代:

allow A_t C_t:file {read write};

allow B_t C_t:file {read write};

前面講過,TE的完整格式爲:

rule_name source_type target_type : class perm_set

因此,attribute能夠出如今source_type中,也能夠出如今target_type中。

提示:通常而言,定義type的時候,都會在名字後添加一個_t後綴,例如type system_t。而定義attribute的時候不會添加任何後綴。可是Android平臺沒使用這個約定俗成的作法。不過不要緊,SEAndroid中定義的attribute都在external/sepolicy/attribute這個文件中,若是分不清是type仍是attribute,則能夠查看這個文件中定義了哪些attribute

最後咱們來看看TE中的rule_name,一共有四種:

  • allow:賦予某項權限。
  • allowauditaudit含義就是記錄某項操做。默認狀況下是SELinux只記錄那些權限檢查失敗的操做。allowaudit則使得權限檢查成功的操做也被記錄。注意,allowaudit只是容許記錄,它和賦予權限不要緊。賦予權限必須且只能使用allow語句。
  • dontaudit:對那些權限檢查失敗的操做不作記錄。
  • neverallow:前面講過,用來檢查安全策略文件中是否有違反該項規則的allow語句。如例子5所示:

[例子5]

#來自external/sepolicy/netd.te文件

#永遠不容許netd域中的進程 讀寫 dev_type類型的 塊設備文件(Object class爲blk_file)

neverallow netd dev_type:blk_file { read write }

(3)  RBAC和constrain

絕大多數狀況下,SELinux的安全配置策略須要咱們編寫各類各樣的xx.te文件。由前文可知,.te文件內部應該包含包含了各類allowtype等語句了。這些都是TEAC,屬於SELinux MAC中的核心組成部分。

TEAC之上,SELiunx還有一種基於Role的安全策略,也就是RBACRBAC究竟是如何實施相關的權限控制呢?咱們先來看SEAndroidRoleUser的定義。

[external/sepolicy/roles]

#Android中只定義了一個role,名字就是r

role r; 

#將上面定義的r和attribute domain關聯起來

role r types domain

再來看user的定義。

[external/sepolicy/users]

#支持MLS的user定義格式爲:

#user seuser_id roles role_id level mls_level range mls_range;

#不支持MLS user定義格式爲:

#user seuser_id roles role_id;

#SEAndroid使用了支持MLS的格式。下面定義的這個user u,將和role r關聯。

#注意,一個user能夠和多個role關聯。

#level以後的是該user具備的安全級別。s0爲最低級,也就是默認的級別,mls_systemHigh

#爲u所能得到的最高安全級別(security level)。此處暫且不表MLS

user u roles { r } level s0 range s0 - mls_systemhigh;

那麼,RolesUser中有什麼樣的權限控制呢?

1)首先,咱們應該容許從一個role切換(SELinuxTransition表達切換之意)到另一個role,例如:

#注意,關鍵字也是allow,但它和前面TE中的allow實際上不是一種東西

#下面這個allow容許from_role_id切換到to_role_id

allow from_role_id to_role_id;

2) 角色之間的關係。SELinux中,RoleRole之間的關係和公司中的管理人員的層級關係相似,例如:

#dominance語句屬於deprecated語句,MLS中有新的定義層級相關的語句。不過此處要介紹的是

#selinux中的層級關係

#下面這句話表示super_r dominate(統治,關鍵詞dom) sysadm_r和secadm_r這兩個角色

#反過來講,sysadm_r和secadm_r dominate by (被統治,關鍵詞 domby) super_r

#從type的角度來看,super_r將自動繼承sysadm_r和secadm_r所關聯的type(或attribute)

dominance { role super_r {role sysadm_r; role secadm_r; }

3)其餘內容,因爲SEAndroid沒有使用,此處不表。讀者可閱讀後面的參考文獻。

話說回來,怎麼實現基於RoleUser的權限控制呢?SELinux提供了一個新的關鍵詞,叫constrain,來看下面這個例子:

[例子6]

#constrain標準格式爲:

# constrain object_class_set perm_set expression ;

#下面這句話表示只有source和target的user相同,而且role也相同,才容許

#write object_class爲file的東東

constrain file write (u1 == u2 and r1 == r2) ;

前面已經介紹過object_classperm_set了,此處就再也不贅述。constrain中最關鍵的是experssion,它包含以下關鍵詞:

  • u1,r1,t1:表明sourceuserroletype
  • u2,r2,t2:表明targetuser,roletype
  • ==!===表示相等或屬於,!=表示不等或不屬於。對於u,r來講,==!=表示相等或不等,而當諸如t1==!=」某個attribute時,表示源type屬於或不屬於這個attribute
  • dom,domby,incomp,eq:僅針對role,表示統治,被統治,不要緊和相同(和==同樣)

關於constrain,再補充幾個知識點

  • SEAndroid中沒有使用constrain,而是用了MLS中的mlsconstrain。因此下文將詳細介紹它。
  • constrain是對TEAC的增強。由於TEAC僅針對TypeDomain,沒有針對userrole的,因此constrainTEAC的基礎上,進一步增強了權限控制。在實際使用過程當中,SELinux進行權限檢查時,先檢查TE是否知足條件,而後再檢查constrain是否也知足條件。兩者都經過了,權限才能知足。

關於RBACconstrain,咱們就介紹到此。

提示:筆者花了很長時間來理解RBACconstrain究竟是想要幹什麼。其實這玩意很簡單。由於TEType Enforcement,沒userrole毛事,而RBAC則可經過constrain語句來在userrole上再加一些限制。固然,constrain也能夠對type進行限制。如此而已!

2.2  Labeling介紹

前面陸陸續續講了些SELinux中最多見的東西。不過細心的人可能會問這樣一個問題:這些SContext最開始是怎麼賦給這些死的和活的東西的?Good Question

提示:SELinux中,設置或分配SContext給進程或文件的工做叫Security Labeling,土語叫打標籤。

(1)  sid和sid_context

這個問題的回答嘛,其實也蠻簡單。Android系統啓動後(其餘Linux發行版相似),init進程會將一個編譯完的安全策略文件傳遞給kernel以初始化kernel中的SELinux相關模塊(姑且用Linux Security Module:LSM來表示它把),而後LSM可根據其中的信息給相關Object打標籤。

提示:上述說法略有不許,先且表述如此。

LSM初始化時所須要的信息以及SContext信息保存在兩個特殊的文件中,以Android爲例,它們分別是:

  • initial_sids:定義了LSM初始化時相關的信息。SIDSELinux中一個概念,全稱是Security IdentifierSID其實相似SContextkey值。由於在實際運行時,若是總是去比較字符串(還記得嗎,SContext是字符串)會嚴重影響效率。因此SELinux會用SID來匹配某個SContext
  • initial_sid_context:爲這些SID設置最初的SContext信息。

來看這兩個文件的內容:

[external/sepolicy/initial_sidsinitial_sid_context]

#先看initial_sids

sid kernel  #sid是關鍵詞,用於定義一個sid

sid security

sid unlabeled

sid fs

sid file

sid file_labels

sid init

......

#再來看initial_sid_context

sid kernel u:r:kernel:s0   #將initial_sids中定義的sid和初始的SContext關聯起來

sid security u:object_r:kernel:s0

sid unlabeled u:object_r:unlabeled:s0

sid fs u:object_r:labeledfs:s0

sid file u:object_r:unlabeled:s0

sid file_labels u:object_r:unlabeled:s0

sid init u:object_r:unlabeled:s0

提示sid的細節須要查看LSM的實現。此處不擬深究它。另外,這兩個文件也是和Kernel緊密相關的,因此通常不用修改它們。

(2)  Domain/Type Transition和宏

SEAndroid中,init進程的SContextu:r:init:s0,而init建立的子進程顯然不會也不可能擁有和init進程同樣的SContext(不然根據TE,這些子進程也就在MAC層面上有了和init同樣的權限)。那麼這些子進程的SContext是怎麼被打上和其父進程不同的SContext呢?

SELinux中,上述問題被稱爲Domain Transtition,即某個進程的Domain切換到一個更合適的Domain中去。Domain Transition也是須要咱們在安全策略文件中來配置的,並且有相關的關鍵詞,來看例子7

[例子7-1]

#先要使用type_transition語句告訴SELinux

#type_transition的完整格式爲:

# type_transition source_type target_type : class default_type;

#對Domain Transition而言有以下例子:

type_transition init_t apache_exec_t : process apache_t;

上面這個例子的解釋以下,請讀者務必仔細:

  • init_t Domain中的進程執行typeapache_exec_t類型的可執行文件(forkexecv)時,其class(此處是process)所屬Domain(對process而言,確定是指Domain)須要切換到apache_t域。

明白了嗎?要作DT,確定須要先fork一個子進程,而後經過execv打開一個新的可執行文件,從而進入變成那個可執行文件對應的活物!因此,在type_transition語句中,target_type每每是那個可執行文件(死物)的typedefault_type則表示execv執行後,這個活物默認的Domain。另外,對DT來講,class必定會是process

請注意,DT屬於Labeling一部分,但這個事情還沒完。由於打標籤也須要相關權限。因此,上述type_transition不過是開了一個頭而已,要真正實施成功這個DT,還須要下面至少三個allow語句配合:

[例子7-2]

#首先,你得讓init_t域中的進程可以執行type爲apache_exec_t的文件

allow init_t apache_exec_t : file execute;

#而後,你還得告訴SELiux,容許init_t作DT切換以進入apache_t域

allow init_t apache_t : process transition;

#最後,你還得告訴SELinux,切換入口(對應爲entrypoint權限)爲執行apache_exec_t類型

#的文件

allow apache_t apache_exec_t : file entrypoint;

爲何會須要上述多達三個權限呢?這是由於在Kernel中,從forkexecv一共設置了三處Security檢查點,因此須要三個權限。

提示:讀者沒必要糾結這個了,按照規範作就完了。不過...,這致使咱們寫TE文件時候會比較麻煩啊!

確實比較麻煩,不過SELinux支持宏,這樣咱們能夠定義一個宏語句把上述4個步驟所有包含進來。在SEAndroid中,系統定義的宏全在te_macros文件中,其中和DT相關的宏定義以下:

[external/sepolicy/te_macros]

#定義domain_trans宏。$1,$2等等表明宏的第一個,第二個....參數

define(`domain_trans', `

# SEAndroid在上述三個最小權限上,還添加了本身的一些權限

allow $1 $2:file { getattr open read execute };

allow $1 $3:process transition;

allow $3 $2:file { entrypoint read execute };

allow $3 $1:process sigchld;

dontaudit $1 $3:process noatsecure;

allow $1 $3:process { siginh rlimitinh };

')

#定義domain_auto_trans宏,這個宏纔是咱們在te中直接使用的

#以例子7而言,該宏的用法是:

#domain_auto_trans(init_tapache_exec_tapache_t)

define(`domain_auto_trans', `

# 先allow相關權限

domain_trans($1,$2,$3)

# 而後設置type_transition

type_transition $1 $2:process $3;

')

external/sepolicy/init_shell.te中就有上述宏的用法:

./init_shell.te:4:domain_auto_trans(init, shell_exec, init_shell)

除了DT外,還有針對TypeTransition。舉個例子,假設目錄ASContextu:r:dir_a,那麼默認狀況下在該目錄下建立的文件都具備u:r:dir_a這個SContext。因此咱們也要針對死得東西進行打標籤。

DT相似,TT的語句也是type_transition,並且要順利完成Transition,也須要申請相關權限。廢話再也不多說,咱們直接看te_macros是怎麼定義TT所須要的宏的:

[external/sepolicy/te_macros]

# 定義file_type_trans(domain, dir_type, file_type)宏

#

define(`file_type_trans', `

# ra_dir_perms是一個宏,由global_macros文件定義,其值爲:

#define(`ra_dir_perms', `{ r_dir_perms add_name write }')

allow $1 $2:dir ra_dir_perms;

# create_file_perms也是一個宏,定義在global_macros文件中,其值爲:

# define(`create_file_perms', `{ create setattr rw_file_perms

#                link_file_perms }')

#而r_dir_perms=define(`r_dir_perms', `{ open getattr read search ioctl }

allow $1 $3:notdevfile_class_set create_file_perms;

allow $1 $3:dir create_dir_perms;

')

 

# 定義file_type_auto_trans(domain, dir_type, file_type)宏

#該宏的含義是:當domain域中的進程在某個Type爲dir_type的目錄中建立文件時,該文件的

#SContext應該是file_type

define(`file_type_auto_trans', `

file_type_trans($1, $2, $3)

type_transition $1 $2:dir $3;

#notdevfile_class_set也是一個宏,由global_macros文件定義,其值爲

# define(`notdevfile_class_set', `{ file lnk_file sock_file fifo_file }')

type_transition $1 $2:notdevfile_class_set $3;

')

WoWSEAndroid太這兩個宏定義太複雜了,來看看官方文檔中的最小聲明是什麼:

[例子8]

type_transition acct_t var_log_t:file wtmp_t;

allow acct_t var_log_t:dir { read getattr lock search ioctl

                                   add_name remove_name write };

allow acct_t wtmp_t:file { create open getattr setattr read

                                 write append rename link unlink ioctl lock };

SEAndroidapp.te中,有以下TT設置:

./app.te:86:file_type_auto_trans(appdomain, download_file, download_file)

DTTT就介紹到這,翻來覆去就這麼點東西,多看幾遍就「櫃」(用櫃字,打一成語,參考2014年中國首次猜謎大會)了

 

=======未完,待續========

接第一部分的內容(http://blog.csdn.net/innost/article/details/19299937)。

今天公司年會,哥高興,因此發佈第二部。SELinux/SEAndroid一共分三部分。第一和第二部分是SELinux的基礎知識,第三部分是SEAndroid的工做源碼分析。

        深刻理解SELinux SEAndroid 第二部分

3)  File/File System 打label

前面一節中,讀者見識到了DTTT。不過這些描述的都是Transition,即從某種TypeDomain進入另一種TypeDomain,而上述內容並無介紹最初的Type怎麼來。在SELinux中,對與File相關的死貨(比「死東西」少些一個字)還有一些特殊的語句。

直接看SEAndroid中的文件吧。

[external/sepolicy/file_contexts]

#從file_contexts這個文件名也可看出,該文件描述了死貨的SContext

#果真:SEAndroid多各類預先存在的文件,目錄等都設置了初始的SContext

#注意下面這些*,?號,表明通配符

/dev(/.*)?        u:object_r:device:s0

/dev/akm8973.*        u:object_r:akm_device:s0

/dev/accelerometer    u:object_r:accelerometer_device:s0

/dev/alarm        u:object_r:alarm_device:s0

/dev/android_adb.*    u:object_r:adb_device:s0

/dev/ashmem        u:object_r:ashmem_device:s0

/dev/audio.*        u:object_r:audio_device:s0

/dev/binder        u:object_r:binder_device:s0

/dev/block(/.*)?    u:object_r:block_device:s0

......

#注意下面的--號,SELinux中相似的符號還有:

#‘-b’ - Block Device ‘-c’ - Character Device

#‘-d’ - Directory ‘-p’ - Named Pipe

#‘-l’ - Symbolic Link ‘-s’ - Socket

#‘--’ - Ordinary file

/system(/.*)?        u:object_r:system_file:s0

/system/bin/ash        u:object_r:shell_exec:s0

/system/bin/mksh    u:object_r:shell_exec:s0

/system/bin/sh        --    u:object_r:shell_exec:s0

/system/bin/run-as    --    u:object_r:runas_exec:s0

/system/bin/app_process    u:object_r:zygote_exec:s0

/system/bin/servicemanager    u:object_r:servicemanager_exec:s0

/system/bin/surfaceflinger    u:object_r:surfaceflinger_exec:s0

/system/bin/drmserver    u:object_r:drmserver_exec:s0

上面的內容很簡單,下面來個面生的:

[external/sepolicy/fs_use]

#fs_use中的fs表明file system.fs_use文件描述了SELinux的labeling信息

#在不一樣文件系統時的處理方式

#對於常規的文件系統,SContext信息存儲在文件節點(inode)的屬性中,系統可經過getattr

#函數讀取inode中的SContext信息。對於這種labeling方式,SELinux定義了

#fs_use_xattr關鍵詞。這種SContext是永遠性得保存在文件系統中

fs_use_xattr yaffs2 u:object_r:labeledfs:s0;

fs_use_xattr jffs2 u:object_r:labeledfs:s0;

fs_use_xattr ext2 u:object_r:labeledfs:s0;

fs_use_xattr ext3 u:object_r:labeledfs:s0;

fs_use_xattr ext4 u:object_r:labeledfs:s0;

fs_use_xattr xfs u:object_r:labeledfs:s0;

fs_use_xattr btrfs u:object_r:labeledfs:s0;

 

#對於虛擬文件系統,即Linux系統運行過程當中建立的VFS,則使用fs_use_task關鍵字描述

#目前也僅有pipefssockfs兩種VFS格式

fs_use_task pipefs u:object_r:pipefs:s0;

fs_use_task sockfs u:object_r:sockfs:s0;

 

#還沒完,還有一個fs_use_trans,它也是用於Virtual File System,但根據SELinux官方

#描述,好像這些VFS是針對pseudo terminal和臨時對象。在具體labeling的時候,會根據

#fs_use_trans以及TT的規則來來決定最終的SContext

#咱們如下面這個例子爲例:

fs_use_trans devpts u:object_r:devpts:s0;

#假設還有一條TT語句

#type_transition sysadm_t devpts : chr_file sysadm_devpts_t:s0;

#表示當sysadm_t的進程在Type爲devpts下建立一個chr_file時,其SContext將是

#sysadm_devpts_t:s0。若是沒有這一條TT,則將使用fs_use_trans設置的SContext:

#u:object_r:devpts:s0 注意,和前面的TT比起來,這裏並非以目錄爲參考對象,而是

#以FileSystem爲參考對象

fs_use_trans tmpfs u:object_r:tmpfs:s0;

fs_use_trans devtmpfs u:object_r:device:s0;

fs_use_trans shm u:object_r:shm:s0;

fs_use_trans mqueue u:object_r:mqueue:s0;

到此,咱們介紹了fs_use_xattrfs_use_taskfs_use_trans,那麼這三種打標籤的方法是否涵蓋了全部狀況呢?答案確定是否,由於咱們還有一個兄弟沒出場呢。

[external/sepolicy/genfs_context]

#genfs中的gen爲generalized之意,即上述三種狀況以外的死貨,就須要使用genfscon

#關鍵詞來打labeling了。通常就是/目錄,proc目錄,sysfs等

genfscon rootfs / u:object_r:rootfs:s0

genfscon proc / u:object_r:proc:s0

genfscon proc /net/xt_qtaguid/ctrl u:object_r:qtaguid_proc:s0

......

到此,絕大部分能想到的死貨怎麼打標籤就介紹完了。

(4)  給網絡數據包/端口打標籤

不過,從知識完整性角度看,還有對網絡數據包打標籤的工做,這也是SELinux新增的功能。不過,它涉及到與iptables相關的工做,因此筆者也不想過多討論。在SEAndroid中,selinux-network.sh腳本就是來幹這個事情的,其內容如圖4所示:

網絡數據包打標籤

由圖4能夠看出,SEAndroid暫時也沒放開網絡數據包打標籤的功能。"-j SECMARK --selctx SContext"iptables(須要支持SELinux功能)新增選項,用來給各類數據包也打上標籤。

除了數據包外,還能夠給端口打標籤,這是由portcon關鍵詞來完成的。此處再也不詳述,讀者有個概念便可。

 

2.3  Security Level和MLS

(1)  Security Level

上文介紹的TERBAC基本知足了「平等社會」條件下的權限管理,但它沒法反映現實社會中等級的概念。爲此,SELinux又添加了一種新的權限管理方法,即Multi-Lever Security,多等級安全。多等級安全信息也被添加到SContext中。因此,在MLS啓用的狀況下(注意,你能夠控制SELinux啓用用MLS仍是不啓用MLS),完整的SContext

  • MLS未啓用前:user_u:role_r:type_t
  • MLS啓用後,user:role:type:sensitivity[:category,...]- sensitivity [:category,...]

看,MLS啓用後,SContext type後面的字段變得很是複雜,看着有些頭暈(至少筆者初學它時是這樣的)。下面立刻來解釋它。

[Security-level解析]

|-->low security level<--| -  |-->high security level<--|

sensitivity[:category,...]  - sensitivity [:category,...]

上述字符串由三部分組成:

  •  low security level:代表當前SContext所對應的東西(活的或死的)的當前(也就是最小)安全級別。
  • 連字符「-」,表示range
  • high security level:代表當前SContext所對應的東西(活的或死的)的最高可能得到的安全級別(英文叫clearance,不知道筆者的中文解釋是否正確)。

security level由兩部分組成,先來看第一部分由sensitivity關鍵字定義的sensitivity,其用法見以下例子:

[例子9]

#用sensitivity定義一個sens_id,alias指定別名。

sensitivity sens_id alias alias_id [ alias_id ];

#好比:

sensitivity s0 alias unclassified

sensitivity s1 alias seceret

sensitivity s2 alias top-seceret

.....

#Question:從alias看,彷佛so的級別<s1的級別<s2的級別。可是

#alias並非sensitivity的必要選項,並且名字能夠任取。

#在SELinux中,真正設置sensitivity級別的是由下面這個關鍵詞表示

dominance {s0 s1 s2.....sn}

#在上述dominance語句中,括號內最左邊的s0級別最低,依次遞增,直到最右邊的sn級別最高

再來看security level第二部分,即category關鍵字及用法,如例10所示:
[例子10]

#category cat_id alias alias_id;

#好比:

category c0

category c1 #等

#category和sensitivity不一樣,它定義的是類別,類別之間是沒有層級關係的。好比,

#小說能夠是一中cagetory,政府公文是另一種category,

SEAndroid中:

  • sensitivity只定義了s0
  • category定義了從c0c1023,共1024category

senstivitycategory一塊兒組成了一個security level(之後簡稱SLevel),SLevel由關鍵字level聲明,以下例所示:

[例子11]

#level sens_id [ :category_id ];

#注意,SLevel能夠沒有category_id。看一個例子:

#sensitivity爲s0,category從c0,c1,c2一直到c255,注意其中的.號

level s0:c0.c255;

#沒有category_id,如:

level s0

Role相似,SL1SL2之間的關係有:

  • dom:若是SL1 dom SL2的話,則SL1sensitivity >= SL2senstivitySL1category包含SL2category(Category of SL1Category of SL2的超集)

例如:

SL1="s2:c0.c5" dom SL2="s0:c2,c3"

  • domby:和dom相反。
  • eqsensitivity相等,category相同。
  • incomp:不可比。sensitivity不可比,category也不可比。

如今回過頭來看SContext,其完整格式爲:

user:role:type:sensitivity[:category,...]- sensitivity [:category,...]

#前面例子中,咱們看到Android中,SContext有:

u:r:init:s0 #在這種case中,Low SLevel等於High SLevel,並且SLevel沒有包含Category

好了,知道了SLevel後,下面來看看它如何在MAC中發揮本身的力量。和constrain相似,MLS在其基礎上添加了一個功能更強大的mlsconstrain關鍵字。

(2)  mlsconstrain和no read down/write up

mlsconstrain語法和constrain同樣同樣的:

mlsconstrain class perm_set expression;

constrain不同的是,expression除了u1,u2,r1,r2,t1,t2外還新增了:

  • l1,l2:小寫的Ll1表示源的low senstivity levell2表示targetlow sensitivity
  • h1,h2:小寫的Hh1表示源的high senstivity levelh2表示targethigh sensitivity
  • lh的關係,包括dom,domby,eqincomp

mlsconstrain只是一個Policy語法,那麼咱們應該如何充分利用它來體現多層級安全管理呢?來看圖5

5  MLS的做用

MLS在安全策略上有一個形象的描述叫no write downno read up

  • 高級別的東西不能往低級別的東西里邊寫數據:這樣可能致使高級別的數據泄露到低級別中。如圖4中,Process的級別是Confidential,它能夠往同級別的File B中讀寫數據,可是隻能往高級別的File A(級別是Secret)裏邊寫東西。
  • 高級別的東西只能從低級別的東西里邊讀數據:好比Process能夠從File CFile D中讀數據,可是不能往File CFile D上寫數據。

反過來講:

低級別的東西只能往高級別的東西里邊寫數據

-----我和小夥伴們解釋這一條的時候,小夥伴驚呆了,我也驚呆了。他們的想法是」低級別往高級別裏寫,豈不是把數據破壞了?「。暈!這裏討論的是泄不泄密的問題,不是討論數據被破壞的事情。破壞就破壞了,只要沒泄密就完了。

低級別的東西不能從高級別的東西那邊讀數據

(3)  MLS in SEAndroid

再來看看SEAndroid中的MLS

  • 首先,系統中只有一個sensitivity level,即s0
  • 系統中有1024category,從c0c1023

讀者經過mmm external/sepolicy --just-print能夠打印出sepolicymakefile執行狀況,其中有這樣的內容:

#m4用來處理Policy文件中的宏

m4 -D mls_num_sens=1 -D mls_num_cats=1024

external/sepolicy/mls文件中有:

[external/sepolicy/mls]

#SEAndroid定義的兩個和MLS相關的宏,位於mls_macro文件中

gen_sens(mls_num_sens)  #mls_num_sens=1

gen_cats(mls_num_cats)  #mls_num_cats=1024

#下面這個宏生成SLevel

gen_levels(mls_num_sens,mls_num_cats)

不必解釋上面的宏了,最終的policy.conf中(2.4節將介紹它是怎麼來的),咱們能夠看到:

[out/target/product/generic/obj/ETC/sepolicy_intermediates/policy.conf]

sensitivity s0;

dominance { s0  }

category c0;

......#目前能告訴你們的是,policy.conf文件中,宏,attribute等都會被一一處理喔!

category c1023

level s0:c0.c1023; #定義SLevel

#SEAndroid中,mls_systemlow宏取值爲s0

#mls_systemhigh宏取值爲s0:c0.c1023

user u roles { r } level s0 range s0 - s0:c0.c1023; #定義u

最後,來看一下mlsconstain的例子:

[例子12]

mlsconstrain dir search

(( l1 dom l2 ) or

(( t1 == mlsfilereadtoclr ) and ( h1 dom l2 )) or

( t1 == mlsfileread ) or

( t2 == mlstrustedobject ));

#上述標粗體的都是attribute

不解釋!

2.4  編譯安全策略文件

到此,SELinux Policy語言中的基本要素都講解完畢,相信讀者對着真實的策略文件再仔細研究下就能完全搞明白。

不過,咱們前面反覆提到的安全策略文件究竟是什麼?咱們前面看到的例子彷佛都是文本文件,難道就它們是安全策略文件嗎?

拿個例子說事,來看圖6Android的策略文件:

6  Android策略文件

Android中,SELinux的安全策略文件如圖6所示。這麼多文件,如何處理呢?來看圖7

7  SElinux安全配置文件生成

由圖7可知:

  • 左邊一列表明安全配置的源文件。也便是你們在圖6中看到的各類te文件,還有一些特殊的文件,例如前文提到的initial_sidinitial_sid_contextsaccess_vectorsfs_use,genfs_contexts等。在這些文件中,咱們要改的通常也是針對TE文件,其餘文件因爲和kernel內部的LSM等模塊相關,因此除了廠家定製外,咱們很難有機會去修改。
  • 這些文件都是文本文件,它們會被組合到一塊兒(圖7中是用cat命令,不一樣平臺處理方法不相同,但大體意思就是要把這些源文件的內容搞到一塊兒去)。
  • 搞到一塊兒後的文件中有使用宏的地方,這時要利用m4命令對這些宏進行拓展。m4命令處理完後獲得的文件叫policy.conf。前面咱們也見過這個文件了,它是全部安全策略源文件的集合,宏也被替換。因此,讀者能夠經過policy.conf文件查看整個系統的安全配置狀況,而不用到圖6中那一堆文件中去找來找去的。
  • policy.conf文件最終要被checkpolicy命令處理。該命令要檢查neverallow是否被違背,語法是否正確等。最後,checkpolicy會將policy.conf打包生成一個二進制文件。在SEAndroid中,該文件叫sepolicy,而在Linux發行版本上,通常叫policy.26等名字。26表示SELinux的版本號。
  • 最後,咱們再把這個sepolicy文件傳遞到kernel LSM中,整個安全策略配置就算完成。

提示:請讀者務必將上述步驟搞清楚。

8所示爲SEAndroidsepolicy makefile的執行狀況:

8  sepolicy makefile執行狀況

看明白了嗎?

提示

想知道如何打印make命令的執行狀況?請使用「--just-print」選項

進階閱讀

1)上述作法是將全部源文件打包生成一個單一的安全策略文件,這種方式叫Monolithic

     policy。顯然,在什麼都模塊化的今天,這種方式雖然用得最多,但仍是比較土。

     SELinux還支持另一種所謂的模塊化Policy。這種PolicyBase PolicyModule

     Policy兩個。BasePolicy爲基礎,先加載,而後能夠根據狀況動態加載Module Policy

     目前SEAndroid尚未該功能,不過之後可能會支持。相信有了它,開發定製企業級

     安全管理系統就更方便些。

2  安全策略源文件很是多。基本上,咱們都會在一個參考源文件上進行相應修改,

     而不會徹底從頭至尾都本身寫。因此,在發行版上有一個Reference Policy,裏邊

     涵蓋了普適的,經常使用的策略。很明顯,AOSP 4.4中的sepolicy也提供了針對Android

     平臺的Reference Policy

2.5  拓展討論

最後,做爲拓展討論,咱們來看看SELinux做爲一套複雜的系統安全模塊加強,其實現架構如圖9所示:

9  SELinux Component組成

其中:

  • Subject:表明發起操做的對象,通常是ProcessSELinux須要檢查Subject是否知足權限要求
  • Object Manager:管理着Object及相應的SContextOM將向Access Vector Cache查詢所要求的操做是否有權限。
  • AVC主要起一個加速的做用,它將緩存一些權限檢查的結果。當相同的權限檢查請求過來時,直接從AVC中返回所緩存的結果。
  • 若是AVC沒有這條權限檢查的結果,那麼它將向Security Server去查詢。SS內部保存有SePolicy,它能夠根據SEPolicy計算出權限檢查的結果。

9中所示的SELinux Component能夠:

  • 上述這些模塊所有運行在Kernel中,它們也是LSM SElinux的核心模塊。
  • OMAVC能夠存在於UserSpace中,這種caseSELinux awareapplication。說白了,就是一個使用SELinux的安全監管系統。在Android中,KernelUserspaceSELinux都使用了。對於userspaceSELinux相關app來講,須要使用開源動態庫libselinux。在Android平臺中,該庫位於external/libselinuxUserspaceSElinux APP也會和Kernel中的LSM Selinux交互,因此不能在沒有Kernel SELinux的系統中單獨使用SELinux app

10展現了一個完整的SELinux系統結構:

10  SELinux系統結構

10比較複雜,很大的緣由是它包含了其餘Linux發行版本上的一些和SELinux相關的工具,咱們從上往下看:

  • 最頂上,Reference Policy, checkmodule, semodule_package,semodule等講得都是Policy編譯相關的工具和參考文件。這些東西編譯完後,會生成最右邊那個圓柱體SELinux Policy
  • 中間的SELinux-aware APP,Linux Commands, policycoreutils, file Labeling utils, semanage等,都是Linux發行版中經常使用的SELinux管理工具。
  • SELinux-aware APP藉助libselinux庫,將最右邊的SELinux Policy配置文件傳遞到kernel中。這實際上是經過往系統一些特殊的文件中寫數據來完成的。例如/selinux/sys/fs/selinux等。
  • 而後咱們進入最下邊的Kernel中的SElinux,它包含AVC,LSM掛鉤的LSM HookSecurity Server等等。

2.6  參考文獻介紹

SELinux比較複雜,對於初學者,建議看以下幾本書:

1  SELinux NSA’s Open Source Security Enhanced Linux

下載地址:http://download.csdn.net/detail/innost/6947063

評價:講得SELinux版本比較老,不包括MLS相關內容。可是它是極好的入門資料。若是你徹底沒看懂本文,則建議讀本文。

2  SELinux by Example Using Security Enhanced Linux

 下載地址:http://download.csdn.net/detail/innost/6947093

評價:這本書比第1本書講得SELinux版本新,包括MLS等不少內容,幾乎涵蓋了目前SELinux相關的全部知識。讀者可跳過1直接看這本書。

3  The_SELinux_Notebook_The_Foundations_3rd_Edition

下載地址:http://download.csdn.net/detail/innost/6947077

評價:這是官方網站上下的文檔,但它倒是最不適合初學者讀的。該書更像一個彙總,解釋,手冊文檔。因此,請務必看完1或2的基礎上再來看它。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

接第二部分的內容(http://blog.csdn.net/innost/article/details/19641487

SEAndroid最後一部分

全文PDF下載地址爲:http://vdisk.weibo.com/s/z68f8l0xZUS9w

 

     深刻理解SELinux SEAndroid(結局)

 

 

二  SEAndroid源碼分析

有了上文的SELinux的基礎知識,本節再來看看Google是如何在Android平臺定製SELinux的。如前文所示,Android平臺中的SELinuxSEAndroid

先來看SEAndroid安全策略文件的編譯。

 

1.  編譯sepolicy

Android平臺中:

  • external/sepolicy:提供了Android平臺中的安全策略源文件。同時,該目錄下的tools還提供了諸如m4,checkpolicy等編譯安全策略文件的工具。注意,這些工具運行於主機(即不是提供給Android系統使用的)
  • external/libselinux:提供了Android平臺中的libselinux,供Android系統使用。
  • external/libsepol:提供了供安全策略文件編譯時使用的一個工具checkcon

對咱們而言,最重要的仍是external/sepolicy。因此先來看它。

讀者還記得上文提到的如何查看make命令的執行狀況嗎?經過:

mmm external/sepolicy  --just-print

,咱們能夠看到sepolicy編譯時都幹了些什麼。

#之後用SEPOLICY_TEMP代替

#     out/target/product/generic/obj/ETC/sepolicy_intermediates字符串

 

#建立臨時目錄

mkdir -p out/target/product/generic/obj/ETC/sepolicy_intermediates/

 

#----->處理一堆輸入源文件,最終輸出爲policy.conf

#執行m4命令,用來生成plicy.conf文件。m4命令將擴展SEAndroid定義的一些宏

m4 -D mls_num_sens=1 -D mls_num_cats=1024 -s

#m4的輸入文件。下面標黑體的是SEAndroid一些系統相關的文件,通常不會修改它

security_classes   initial_sids access_vectors

global_macros mls_macros mls

policy_capabilities te_macros attributes

#Android系統中的te文件。

adbd.te app.te bluetoothd.te  bluetooth.te   clatd.te dbusd.te debuggerd.te device.te dhcp.te dnsmasq.te domain.te drmserver.te file.te gpsd.te hci_attach.te healthd.te hostapd.te init_shell.te init.te installd.te isolated_app.te kernel.te keystore.te media_app.te mediaserver.te mtp.te netd.te net.te nfc.te ping.te platform_app.te ppp.te property.te qemud.te racoon.te radio.te release_app.te rild.te runas.te sdcardd.te servicemanager.te shared_app.te shell.te surfaceflinger.te su.te system.te tee.te ueventd.te unconfined.te untrusted_app.te vold.te watchdogd.te wpa_supplicant.te zygote.te

#其餘文件

roles  users initial_sid_contexts fs_use genfs_contexts port_contexts

#m4:將上述源文件處理完後,生成policy.conf

> SEPOLICY_TEMP/policy.conf

 

 

#下面這個命令將根據policy.conf中的內容,再生成一個policy.conf.dontaudit文件

sed '/dontaudit/d'

           SEPOLICY_TEMP/policy.conf >

           SEPOLICY_TEMP/policy.conf.dontaudit

 

mkdir -p SEPOLICY_TEMP/

#------>根據policy.conf文件,生成二進制文件。SEAndroid中,它叫sepolicy

#執行checkpolicy,輸入是policy.conf,輸出是sepolicy

#-M選項表示支持MLS

checkpolicy -M -c 26 -o SEPOLICY_TEMP/sepolicy

                             SEPOLICY_TEMP/policy.conf

#執行checkpolicy,輸入是policy.conf.dontaudit,輸出是sepolicy.dontaudit

checkpolicy -M -c 26 -o

            SEPOLICY_TEMP/sepolicy.dontaudit    

           SEPOLICY_TEMP/policy.conf.dontaudit

 

#--->將sepolicy拷貝到對應目標平臺的root目錄下

echo "Install: out/target/product/generic/root/sepolicy"

acp -fp SEPOLICY_TEMP/sepolicy

                  out/target/product/generic/root/sepolicy

 

#---->生成file_context文件

#用FILE_CONTEXT_TEMP代替

#    out/target/product/generic/obj/ETC/file_contexts_intermediates字符串

mkdir -p FILE_CONTEXT_TEMP/

m4 -s  external/sepolicy/file_contexts  > FILE_CONTEXT_TEMP/file_contexts

checkfc  SEPOLICY_TEMP/sepolicy

                  FILE_CONTEXT_TEMP/file_contexts

echo "Install: out/target/product/generic/root/file_contexts"

acp -fp FILE_CONTEXT_TEMP/file_contexts

                     out/target/product/generic/root/file_contexts

 

#--->生成seapp_context文件,這個是Android平臺特有的,其做用咱們下文再介紹

#用SEAPP_CONTEXT_TEMP代替

#     out/target/product/generic/obj/ETC/seapp_contexts_intermediates

mkdir -p SEAPP_CONTEXT_TEMP/

checkseapp -p SEPOLICY_TEMP /sepolicy

-o SEAPP_CONTEXT_TEMP/seapp_contexts SEAPP_CONTEXT_TEMP/seapp_contexts.tmp

echo "Install: out/target/product/generic/root/seapp_contexts"

acp -fp SEAPP_CONTEXT_TEMP/seapp_contexts

                        out/target/product/generic/root/seapp_contexts

 

#---->和Android平臺中的屬性相關。SEAndroid中,設置屬性也須要相關權限

#用PROPERTY_CONTEXT_TMP代替:

#         out/target/product/generic/obj/ETC/property_contexts_intermediates

mkdir -p PROPERTY_CONTEXT_TMP/

m4 -s  external/sepolicy/property_contexts  >

                         PROPERTY_CONTEXT_TMP/property_contexts

checkfc -p TARGET_SEPOLICY_TEMP/sepolicy

               PROPERTY_CONTEXT_TMP/property_contexts

echo "Install: out/target/product/generic/root/property_contexts"

acp -fp PROPERTY_CONTEXT_TMP/property_contexts

                      out/target/product/generic/root/property_contexts

上面展現了sepolicy編譯的執行狀況,讀者最好本身嘗試一下。注意,checkfccheckseapp等都是SEAndroid編譯時使用的工具,它們用來作策略檢查,看看是否有規則不符合的地方。

總結:

  • sepolicy的重頭工做是編譯sepolicy安全策略文件。這個文件來源於衆多的te文件,初始化相關的文件(initial_sid,initial_sid_context,users,roles,fs_context等)。
  • file_context:該文件記載了不一樣目錄的初始化SContext,因此它和死貨打標籤有關。
  • seapp_context:和Android中的應用程序打標籤有關。
  • property_contexts:和Android系統中的屬性服務(property_service)有關,它爲各類不一樣的屬性打標籤。

下面咱們來看看和SEAndroid相關的代碼,故事從init開始。

2.  initSEAndroid定製

Android平臺中,SEAndroid的初始化由進程的祖先initmain函數完成,相關代碼以下所示:

[-->init.c:main]

 

  process_kernel_cmdline();

  //向SELinux設置兩個回調函數,主要是打印log

 union selinux_callback cb;

 cb.func_log = klog_write;

 selinux_set_callback(SELINUX_CB_LOG, cb);

  cb.func_audit = audit_callback;

  //selinux_set_callback由libselinux提供。讀者可google libselinux各個API

  //的做用

  selinux_set_callback(SELINUX_CB_AUDIT, cb);

   //①初始化SEAndroid

    selinux_initialize(); 

   //②給下面幾個目錄打標籤!

   restorecon("/dev"); 

   restorecon("/dev/socket");

   restorecon("/dev/__properties__");

   restorecon_recursive("/sys");

上述代碼中的兩個重要函數:

  • selinux_initialize:初始化SEAndroid
  • 一堆的restoercon,全稱應該是restore context:就是根據file_contexts中的內容給一些目錄打標籤。

先來看selinux_initialize

2.1  selinux_initialize分析

[-->init.c:: selinux_initialize]

static void selinux_initialize(void)

{

   /*判斷selinux功能是否啓用。方法是:

   1) /sys/fs/selinux 是否存在。或者

   2)  ro.boot.selinux 屬性不爲disabled

  */

   if (selinux_is_disabled()) return;

 

      //加載sepolicy文件

    if (selinux_android_load_policy() < 0) {......}

 

    selinux_init_all_handles();

   /*selinux有兩種工做模式

    「permissive」:全部操做都被容許(即沒有MAC),可是若是有違反權限的話,會記錄日誌

    「enforcing」:全部操做都會進行權限檢查

    */

    bool is_enforcing = selinux_is_enforcing();

    //設置SELinux的模式

    security_setenforce(is_enforcing);

}

來看上述代碼中的兩個函數:

  • selinux_android_load_policy:加載sepolicy文件。
  • selinux_init_all_handles:初始化file_contextseapp_contextproperty_context相關內容。
(1)  selinux_android_load_policy

來看selinux_android_load_policy,其代碼以下所示:

[-->external/libselinux/src/android.c:: selinux_android_load_policy]

int selinux_android_load_policy(void)

{

    char *mnt = SELINUXMNT;// 值爲/sys/fs/selinux

    int rc;//掛載/sys/fs/selinux,SELINUXFS值爲"selinuxfs"

    rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);

     ......

    // /sys/fs/selinux爲userpace和kernel中的SELinux模塊交互的通道

    set_selinuxmnt(mnt);//此函數定義在selinux.h中,屬於libselinux API.

 

    return selinux_android_reload_policy(); //加載SEAndroid中的policy文件

}

11展現了Nexus 7/sys/fs/selinux的內容:

11  /sys/fs/selinux的內容

用戶空間進程可同讀寫/sys/fs/selinux的各個文件或其中的子目錄來通知Kernel中的SELinux完成相關的操做。

咱們此處此處舉一個例子,如圖11下方紅框中的booleans文件夾:

  • 咱們能夠SELinux的安全配置文件中寫一些相似if/else的語句。if中的是布爾判斷條件。好比booleans文件夾下有一個in_qemu文件,這個就是sepolicy安全配置文件中的一個布爾變量。in_qemu定義在domain.te文件中,關鍵詞是bool
  • cat booleans/in_qemu:打印in_qemu布爾變量的取值。讀者會發現它的值爲「0 0」。爲何有兩個零呢,這第一個0是它的當前值,第二個零表明pending取值。即尚未賦值給當前值的一箇中間變量。若是咱們經過 echo "1" > booleans/in_qemu的話,第二個零將變成1
  • 爲何須要有中間變量呢?讀者注意圖11的右上方有一個commit_pending_bools文件。原來,經過在布爾變量中設置一個pending變量,咱們能夠實現批處理操做。即先修改1個或多個布爾變量的pending變量,而後往commit_pending_bools1,這樣這些一個或多個的布爾變量將使用pending變量取代當前值。

接下來看看selinux_android_reload_policy函數:

 [-->external/libselinux/src/android.c:: selinux_android_reload_policy]

int selinux_android_reload_policy(void)

{

    int fd = -1, rc;  struct stat sb;   void *map = NULL;

    int i = 0;

   // sepolicy_file指明sepolicy文件的路徑。Android中有兩處,第一個是

  // /data/security/current/sepolicy。第二個是root目錄下的sepolicy文件。

  //下面這段邏輯可知,SEAndroid只使用其中的一個,若是/data/目錄下有sepolicy文件,則

  //優先使用它

    while (fd < 0 && sepolicy_file[i]) {

        fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);

        i++;

    }

    ......

    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

    ......

   //假設使用根目錄下的sepolicy文件。下面這個函數由selinux.h定義,它將此文件加載到

   //內核中

    rc = security_load_policy(map, sb.st_size);

    ......

    munmap(map, sb.st_size);

    close(fd);

     return 0;

}

init經過mmap的方式,將sepolicy文件傳遞給了kernelinit使用了libselinux提供的API函數來完成相關操做。而libselinux則是經過操做/sys/fs/selinux下的文件來完成和KernelSELinux模塊的交互。libselinux庫的API不是咱們研究的重點,感興趣的兄弟請本身研究源碼。

總之,selinux_android_load_policy幹得最重要的一件事情就是將sepolicy文件傳遞給Kernel,這樣Kernel就有了安全策略配置文件,後續的MAC才能開展起來。

在此,請讀者注意sepolicy文件的位置:

  • 首先查看/data/security/current/sepolicy:筆者自定義的策略文件通常放在這裏,init優先使用它。
  • /sepolicyroot根目錄下的sepolicy,若是data目錄下沒有sepolicy,則使用它。系統默認的sepolicy在此。
(2)  selinux_init_all_handles

前面講過,init要給一些死貨和property打標籤,爲了完成這個工做,根據libselinuxAPIinit須要先建立兩個handler,代碼在selinux_init_all_handles中:

[-->init.c:: selinux_init_all_handles]

void selinux_init_all_handles(void)

{

    sehandle = selinux_android_file_context_handle();

    sehandle_prop = selinux_android_prop_context_handle();

}

建立兩個handler,主要爲後續作labeling控制。咱們來看看propcontext

[-->init.c::selinux_android_prop_context_handle]

struct selabel_handle* selinux_android_prop_context_handle(void)

{

    int i = 0;

    struct selabel_handle* sehandle = NULL;

   //setopts_prop也有兩個值:

   //第一個是/data/security/property_contexts。第二個是/property_contexts

    while ((sehandle == NULL) && seopts_prop[i].value) {

        sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);

        i++;

    }

  //假設採用的是根目錄下的property_context文件

  ......

  return sehandle;

}

handler其實就是爲了打開xxx_context文件。因爲它們和restorecon有關,下面直接來看restorecon函數,看看這些handler是怎麼個用法。

2.2  restorecon分析

[-->init.c::restorecon]

int restorecon(const char *pathname)

{

    char *secontext = NULL;

    struct stat sb;

    int i;

 

    if (is_selinux_enabled() <= 0 || !sehandle)

        return 0;

 

    if (lstat(pathname, &sb) < 0)   return -errno;

    //查找file_context文件中是否包含有pathname路徑的控制選項

    if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)

        return -errno;

   //設置patchname目錄的security_context,lsetfilecon的實現很是簡單,就是調用

   //

    if (lsetfilecon(pathname, secontext) < 0) {

        freecon(secontext);

        return -errno;

    }

    freecon(secontext);

    return 0;

}

想知道selinux是如何labeling一個文件或目錄的嗎?答案在lsetfilecon中:

[-->external/libselinux/src/lsetfilecon.c:: lsetfilecon]

int lsetfilecon(const char *path, const security_context_t context)

{

 //設置文件系統的屬性

 return lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,0);

}

2.3  property權限檢查

通常而言,SELinux權限檢查都是由kernel來完成的,不過對於Android平臺中的Property而言,這卻徹底是一個用戶空間的內容。因此,咱們看看init是如何使用libselinux來完成用戶空間的權限檢查的。

每當其餘進程經過setprop函數設置屬性時,property_service中有一個叫check_

[system/core/init/property_service.c:: check_mac_perms]

static int check_mac_perms(const char *name, char *sctx)

{

    if (is_selinux_enabled() <= 0)  return 1;

 

    char *tctx = NULL;

    const char *class = "property_service";

    const char *perm = "set";

    int result = 0;

    ......

    //檢查property_context中是否認義了目標SContext,即tctx。

    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) goto err;

   //將源SContext和目標SContext進行比較,判斷是否有相關權限。name是屬性的名字

   //源SContext是調用setprop進程的SContext。目標SContext是property_context

   //文件中定義的SContext。

    if (selinux_check_access(sctx, tctx, class, perm, name) == 0)

        result = 1;

    freecon(tctx);

 err:

    return result;

}

怎麼樣?理解起來並不困難吧?用戶空間的權限檢查主要就是經過selinux_check_access完成,其輸入參數包括:

  • 源的SContext:它就是調用setprop的進程的SContext
  • 目標的SContext:不一樣的屬性有不一樣的SContext,這是在property_context中定義的。
  • 要檢查的Object class(系統所支持的類在external/sepolicy/security_classes文件中定義)。
  • 操做名稱(perm,由access vector定義。對Property這種Object class而言,其惟一須要作權限檢查的操做就是set。讀者可參考external/sepolicy/access_vectors這個文件)。

具體的哪個屬性(name參數指定,就是具體指明哪一文件)。

提示:關於這些API的說明,讀者請參考http://selinuxproject.org/page/User_Resources中的Manual pages文檔。

下面咱們來看Android中應用程序是如何使用SELinux的。

3.  應用程序中的SELinux

對應用程序而言,最重要的工做就是管理它們的DTTT

  • 全部AndroidApplication對應的進程都是從zygote進程中fork出來的。從前文介紹DT的知識可知,在作DT時,能夠根據所執行的不一樣Type的文件來轉換到不一樣的DT。但這個對Android而言不可行。由於zygotefork子進程後,並無執行execv
  • apk在安裝後,都會在/data/data/目錄下創建本身對於的文件夾,這個工做是由installd來完成的。一樣,installd應該給這些不一樣的文件夾打上對應的label

咱們先來看應用程序的DT

3.1  Java應用程序的DT

Android中應用進程(就是APK所在的進程)的DT轉換其實很簡單,它及其具備Android特點:

  • 普通的DT是根據所execv文件的Type來設置DT轉換條件。
  • Android中則根據該APK簽名信息來說最終的進程轉換到幾種預設值的Domain中。
(1)  mac_permissions.xml的用途

咱們先來看PackageManagerService

[-->PackageManagerService.java::PackageManageService]

......

/*下面這個函數將嘗試解析

 1)/data/security/mac_permissions.xml 或

 2)/system/etc/security/mac_permissions.xml 中的內容。

*/

mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

注意,mac_permissions.xml位於external/sepolicy中,圖12所示爲該文件的原始:

12  mac_permissions.xml的內容

在系統過程當中,圖12中的@RELEASE@PLATFORM等內容會被RELEASEPLATFORM簽名信息替換。圖13所示爲Nexus 7中該文件的內容。

13  Nexus7mac_permissions.xml內容

mac_permissions.xml保存了不一樣簽名所對應的seinfo:如seinfoplatform時的簽名是什麼,seinfomedia的時候簽名又是什麼。那麼,這些信息有啥用呢?來看下文。

(2)  掃描APK

APK安裝時,也就是APKPKMGS掃描的時候,有以下的代碼:

[-->PackageManagerService.java::ScanPackageLI]

if (mFoundPolicyFile) {

     //下面這個函數將根據簽名信息賦值seinfo值給對應的apk

     SELinuxMMAC.assignSeinfoValue(pkg);

   }

[-->SELinuxMMAC.java::assignSeinfoValue]

public static void assignSeinfoValue(PackageParser.Package pkg) {

 

     //對於系統app(預裝的,位於system目錄下的)

     if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||

          ((pkg.applicationInfo.flags &

                         ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {

   

        for (Signature s : pkg.mSignatures) {

                if (s == null)  continue;

              //sSigSeinfo存儲了mac_permissions.xml中seinfo標籤的內容

              if (sSigSeinfo.containsKey(s)) {

                    String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s);

                    return;

                }

            }

            //sPackageSeinfo存儲了xml中package標籤下seinfo子標籤的內容

            if (sPackageSeinfo.containsKey(pkg.packageName)) {

                String seinfo = pkg.applicationInfo.seinfo =

                              sPackageSeinfo.get(pkg.packageName);

                 return;

            }

        }

        //default標籤中seinfo的值

        String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null);

        ......

  }

assignSeinfoValue的功能如上代碼所示,它根據apk的簽名信息來賦值不一樣的seinfo,也就是諸如"platform",」media「之類的值。

提示:你們能想出爲何要設置seinfo嗎?恩,它就是AndroidApp定義的SContext中的Domain的值。

(3)  App的DT轉換

ActivityManagerService負責啓動目標應用進程,相關代碼以下所示:

[-->ActivityManagerService.java:: startProcessLocked]

Process.ProcessStartResult startResult =

                     Process.start("android.app.ActivityThread",

                    app.processName, uid, uid, gids, debugFlags, mountExternal,

                    app.info.targetSdkVersion, app.info.seinfo, null);

根據《深刻理解AndroidI》第4章對zygote的介紹,zygote進程將fork一個子進程,相關函數在:

[-->ZygoteConnection.java::runOnce]

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,

                    parsedArgs.seInfo,parsedArgs.niceName);

該函數由JNI實現,代碼在dalvik/vm/native/ dalvik_system_Zygote.cpp中,其中最重要的是內部所調用的forkAndSpecializeCommon

[-->dalvik_system_Zygote.cpp:: forkAndSpecializeCommon]

pid = fork();

if (pid == 0) {

  ......

    err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);

  .....}

 

[-->external/libselinux/android.c::selinux_android_setcontext]

int selinux_android_setcontext(uid_t uid,int isSystemServer,

                   const char *seinfo,const char *pkgname)

{

    char *orig_ctx_str = NULL, *ctx_str;  context_t ctx = NULL;

    int rc = -1;

    if (is_selinux_enabled() <= 0)  return 0;

   

    //重要函數:seapp_context_init,內部將調用selinux_android_seapp_context_reload

   //以加載seapp_contexts文件。

   // 1) /data/security/current/seapp_contexts 或者

   // 2) /seapp_contexts   本例而言,就是根目錄下的這個seapp_context文件

    __selinux_once(once, seapp_context_init);

   

    rc = getcon(&ctx_str);

    ctx = context_new(ctx_str);

    orig_ctx_str = ctx_str;

    //從zygote進程fork出來後,最初的SContext取值爲u:r:zygote:s0

   //下面這個函數將根據uid,pkgname等設置最終的SC。例如u:r:system_app:s0等

    rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname,

     ctx);

   ctx_str = context_str(ctx);

   rc = security_check_context(ctx_str);

   if (strcmp(ctx_str, orig_ctx_str)) {

        rc = setcon(ctx_str);

    }

 

    rc = 0;

    ......

    return rc;

}

14所示爲seapp_context的內容,很是簡單:

14  seapp_context內容

上面代碼中的seapp_context_lookup將根據圖14的內容,經過不一樣的apk所對應的seinfo,找到他們的目標domain,而後再設置爲它們新的SContext。例如圖15Nexus 7ps -Z的結果圖。

15  ps -Z查看apk進程的SContext

seapp_context_lookup是完成從seapp_context文件內容映射到具體對應爲哪一個Domain的關鍵函數,該函數第一次看起來嚇死人,其實蠻簡單。這裏就再也不多說。

anywaySEAndroid中,不一樣應用程序將根據它們的簽名信息獲得對應的SContext(主要是DomainMLS其實沒用上,但之後能夠用上,這是經過圖14中的levelFrom語句來控制的,具體可參考seapp_context_lookup的實現)。

DT完成後,咱們看系統如何爲它們的對應文件夾打標籤

3.2  App data目錄的TT

仍是在PackageManagerServicescanPackageLI函數中,

[-->PackageManagerService.java:: scanPackageLI]

int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,

                                           pkg.applicationInfo.seinfo);

createDataDirsLI最終會調用installd實現的函數:

[-->installd/commands.c::install]

//內部調用selinux_android_setfilecon2,它和上文的selinux_android_setcontext

//幾乎同樣。最終它將設置pkgdir的SContext。注意,它主要根據seapp_context文件中的

//type字段來肯定最終的Type值。

if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) {

     ......

 }

16展現了ls -Z /data/data目錄下的結果。

16  /data/data目錄下ls -Z的結果

是否是和圖14seapp_context文件的type字段描述同樣同樣的?

 

4  小試牛刀

下面,筆者將經過修改shell的權限,使其沒法設置屬性。

先來看shellte,以下所示:

[external/sepolicy/shell.te]

# Domain for shell processes spawned by ADB

type shell, domain;

type shell_exec, file_type;

#shell屬於unconfined_domain,unconfined便是不受限制的意思

unconfined_domain(shell)

 

# Run app_process.

# XXX Split into its own domain?

app_domain(shell)

unconfied_domain是一個宏,它將shell和以下兩個attribute相關聯:

[external/sepolicy/te_macros]

#####################################

# unconfined_domain(domain)

# Allow the specified domain to do anything.

#

define(`unconfined_domain', `

typeattribute $1 mlstrustedsubject; #這個和MLS有關

typeattribute $1 unconfineddomain;

')

unconfineddomain權限不少,它的allow語句定義在unconfined.te中:

[external/sepolicy/unconfined.te]

......

allow unconfineddomain property_type:property_service set;

從上面能夠看出,shell所關聯的unconfineddomain有權限設置屬性。因此,咱們把它改爲:

allow {unconfineddomain -shell} property_type:property_service set;

經過一個「-」號,將shell的權限排除。

而後:

  • 咱們mmm external/sepolicy,獲得sepolicy文件。
  • 將其push/data/security/current/sepolicy目錄下
  • 接着調用setprop selinux.reload_policy 1,使得init從新加載sepolicy,因爲/data目錄下有了sepolicy,因此它將使用這個新的。

17所示爲整個測試的例子:

17  測試結果

根據圖17

  • 從新加載sepolicy以前,筆者可經過"setprop wlan.driver.status test_ok"設置該屬性的值爲test_ok。注意,這個值筆者瞎設的。
  • 當經過setprop selinux.reload_policy 1的命令後,init從新加載了sepolicy
  • 今後,筆者再setprop wlan.driver.status 都不能修改該屬性的值。

18所示爲dmesg輸出,能夠看出,當selinux使用了data目錄下這個新的sepolicy後,shellsetprop權限就被否了!

18  dmesg輸出

提示:前面曾提到過audit,日誌一類的事情。恩,這個日誌由kernel輸出,可藉助諸如audit2allowhost上的工具查看哪些地方有違反權限的地方。系統會將源,目標SContext等信息都打印出來。

 

  全文總結

本文對SELinux的核心知識進行了介紹。從入門角度來講,有了這些內容,SELinux大概80%左右的知識都已經介紹,剩下來的工做就是不斷去修改和嘗試不一樣的安全配置文件。

而後咱們對SEAndroid進行了相關介紹,這部分基本上反映了Android是如何利用這些安全配置文件來構造本身的安全環境的。

從目前AOSP SEAndroid安全配置源文件來看,不少te文件中都使用了以下這樣的語句:

19  permissive定義

其中,permissive關鍵詞表示不用對上述這些type/domain進行MAC監管。permissive通常用於測試某個策略,看是否對整個系統有影響。一旦測驗經過,就能夠把permissve語句移掉,以真正提高安全。

基於SEAndroid,廣大搞機人能夠:

  • 針對行業,開發更加安全的安全策略。
  • 定製MLS,針對企業級或軍用級的多層權限管理。
  • 不知道google有沒有意向實現Modular Policy,這樣的話,SELinux靈活性更高。

另外,要提醒讀者的是,安全配置須要考慮的東西很是多,稍有不甚,就會影響系統其餘模塊的運行。好比筆者在研究SELinux時,不當心把Ubuntu的圖像界面系統啓動不了,後來只能移除SELinux後才解決。這也是爲何SELinux出來這麼多年,可是你們好像碰到它的機會不多的緣由,由於它的配置實在是太麻煩,很容易出錯!

最後,反覆提醒讀者,一旦修改了策略文件,務必進行全方位,多層面測試。

關於SEAndroid的更多官方說明,請參考

http://source.android.com/devices/tech/security/se-linux.html

相關文章
相關標籤/搜索