TShopping

 找回密碼
 註冊
搜索
查看: 3191|回復: 0
打印 上一主題 下一主題

[教學] 深入理解SELinux SEAndroid

[複製鏈接]
跳轉到指定樓層
1#
發表於 2017-11-3 20:21:56 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
 
Push to Facebook
SEAndroid是Google在Android 4.4上正式推出的一套以SELinux為基礎於核心的系統安全機制。而SELinux則是由美國NSA(國安局)和一些公司(RedHat、Tresys)設計的一個針對Linux的安全加強系統。
NSA最初設計的安全模型叫FLASK,全稱為Flux Advanced Security Kernel(由Uta大學和美國國防部開發,後來由NSA將其開源),當時這套模型針對DTOS系統。後來,NSA覺得Linux更具發展和普及前景,所以就在Linux系統上重新實現了FLASK,稱之為SELinux。
Linux Kernel中,SELinux通過Linux Security Modules實現。在2.6之前,SElinux通過Patch方式發布。從2.6開始,SELinux正式入駐內核,成為標配。
思考:
1同樣是政府部門,差別咋這麼大?
2同樣涉及操作系統和安全相關,NSA為何敢用Linux,為什麼想方設法要開源?

由於Linux有多種發行版本,所以各家的SELinux表現形式也略有區別。具體到Android平台,Google對其進行了一定得修改,從而得到SEAndroid。
本文將先對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之外,設計了一個新的安全模型,叫MAC(Mandatory Access Control),翻譯為強制訪問控制。MAC的處世哲學非常簡單:即任何進程想在SELinux系統中乾任何事情,都必須先在安全策略配置文件中賦予權限。凡是沒有出現在安全策略配置文件中的權限,進程就沒有該權限。來看一個SEAndroid中設置權限的例子:
[例子1]
  1. /*
  2. from external/sepolicy/netd.te
  3. 下面這條SELinux語句表示允許(allow )netd域(domain)中的進程 ”寫(write)“
  4. 類型為proc的文件
  5. 注意,SELinux中安全策略文件有自己的一套語法格式,下文我們將詳細介紹它
  6. */
  7. allow netd proc:file write
複製代碼


如果沒有在netd.te中使用上例中的權限配置allow語句,則netd就無法往/proc目錄下得任何文件中寫數據,即使netd具有root權限。
顯然,MAC比DAC在權限管理這一塊要復雜,要嚴格,要細緻得多。
那麼,關於DAC和MAC,此處筆者總結了幾個知識點:
Linux系統先做DAC檢查。如果沒有通過DAC權限檢查,則操作直接失敗。通過DAC檢查之後,再做MAC權限檢查。
SELinux中也有用戶的概念,但它和Linux中原有的user概念不是同一個東西。什麼意思呢?比如,Linux中的超級用戶root在SELinux中可能就是一個沒權限,沒地位,打打醬油的”路人甲“。當然,這一切都由SELinux安全策略的製定者來決定。

通過上述內容,讀者應該能感覺到,在SELinux中,安全策略文件是最重要的。確實如此。事實上,對本文的讀者而言,學習SELinux的終極目標應該是:
看懂現有的安全策略文件。
編寫符合特定需求的安全策略文件。
前面也曾提到,SELinux有自己的一套規則來編寫安全策略文件,這套規則被稱之為SELinux Policy語言。它是掌握SELinux的重點。
2. SELinux Policy語言介紹

Linux中有兩種東西,一種死的(Inactive),一種活的(Active)。死的東西就是文件(Linux哲學,萬物皆文件。注意,萬不可狹義解釋為File),而活的東西就是進程。此處的“死”和“活”是一種比喻,映射到軟件層面的意思是:進程能發起動作,例如它能打開文件並操作它。而文件只能被進程操作。
SELinux中,每種東西都會被賦予一個安全屬性,官方說法叫Security Context。Security Context(以後用SContext表示)是一個字符串,主要由三部分組成。例如SEAndroid中,進程的SContext可通過ps -Z命令查看,如圖1所示:


圖1 Nexus 7 ps -Z結果圖
圖1中最左邊的那一列是進程的SContext,以第一個進程/system/bin/logwrapper的SContext為例,其值為u:r:init:s0,其中:
u為user的意思。SEAndroid中定義了一個SELinux用戶,值為u。
r為role的意思。role是角色之意,它是SELinux中一種比較高層次,更方便的權限管理思路,即Role Based Access Control(基於角色的訪問控制,簡稱為RBAC)。簡單點說,一個u可以屬於多個role,不同的role具有不同的權限。RBAC我們到最後再討論。
init,代表該進程所屬的Domain為init。MAC的基礎管理思路其實不是針對上面的RBAC,而是所謂的Type Enforcement Accesc Control(簡稱TEAC,一般用TE表示)。對進程來說,Type就是Domain。比如init這個Domain有什麼權限,都需要通過[例子1]中allow語句來說明。
S0和SELinux為了滿足軍用和教育行業而設計的Multi-Level Security(MLS)機制有關。簡單點說,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目錄對應的Type是rootfs。
s0:MLS的級別。
根據SELinux規範,完整的SContext字符串為:
user:role:type

注意,方括號中的內容表示可選項。s0屬於range中的一部分。下文再詳細介紹range所代表的Security Level相關的知識。
看,SContext的核心其實是前三個部分:user:role:type。
剛才說了,MAC基本管理單位是TEAC(Type Enforcement Accesc Control),然後是高一級別的Role Based Accesc Control。RBAC是基於TE的,而TE也是SELinux中最主要的部分。
下面來看看TE。
2.1 TE介紹

在例子1中,大家已經見過TE的allow語句了,再來細緻研究下它:
[例子2]
  1. allow netd proc:file write
複製代碼

這條語句的語法為:
allow:TE的allow語句,表示授權。除了allow之外,還有allowaudit、dontaudit、neverallow等。
netd:source type。也叫subject,domain。
proc:target type。它代表其後的file所對應的Type。
file:代表Object Class。它代表能夠給subject操作的一類東西。例如File、Dir、socket等。在Android系統中,有一個其他Linux系統沒有的Object Class,那就是Binder。
write:在該類Object Class中所定義的操作。

根據SELinux規範,完整的allow相關的語句格式為:
  1. rule_name source_type target_type : class perm_set
複製代碼

我們直接來看幾個實例:
[例子3]
  1. //SEAndroid中的安全策略文件policy.conf
  2. #允許zygote域中的進程向init type的進程(Object Class為process)發送sigchld信號
  3. allow zygote init:process sigchld ;
  4. #允許zygote域中的進程search或getattr類型為appdomain的目錄。注意,多個perm_set
  5. #可用{}括起來
  6. allow zygote appdomain:dir { getattr search } ;
複製代碼
  1. #來個複雜點的:
  2. #source_type為unconfineddomain target_type為一組type,由
  3. #{ fs_type dev_type file_type } 構成。object_class也包含兩個,為{ chr_file file }
  4. #perm_set語法比較奇特,前面有一個~號。它表示除了{entrypoint relabelto}之外,{chr_file #file}這兩個object_class所擁有的其他操作
  5. allow unconfineddomain {fs_type dev_type file_type} : { chr_file file }    \
  6. ~{entrypoint relabelto} ;
  7. #特殊符號除了~外,還有-號和*號,其中:
  8. # 1):-號表示去除某項內容。
  9. # 2):*號表示所有內容。
  10. #下面這條語句中,source_type為屬於appdomain,但不屬於unconfinedomain的進程。
  11. #而*表示所有和capability2相關的權限
  12. #neverallow:表示絕不允許。
  13. >neverallow { appdomain -unconfineddomain } self:capability2 *;
複製代碼

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

圖3 neverallow的作用
如圖3所示,筆者修改shell.te後,意外導致了一條allow語句與neverallow語句衝突,從而生成安全策略文件失敗。
下面我們來看上述allow語句中所涉及到的object class和perm set。
(1) Object class和Perm Set


Object class很難用語言說清楚它到底是怎麼定義的,所以筆者也不廢話,直接告訴大家常見的Object class有哪些。見下面的SEPolicy示例:
[external/sepolicy/security_classes示例]
  1. #此文件定義了Android平台中支持的Object class
  2. #根據SELinux規範,Object Class類型由class關鍵字申明
  3. # file-related classes
  4. class filesystem
  5. class file #代表普通文件
  6. class dir #代表目錄
  7. class fd #代表文件描述符
  8. class lnk_file #代錶鍊接文件
  9. lass chr_file #代表字符設備文件

  10. # network-related classes
  11. class socket #socket
  12. class tcp_socket
  13. class udp_socket
  14. ......
  15. class binder    #Android平台特有的binder
  16. class zygote    #Android平台特有的zygote

  17. #Android平台特有的屬性服務。注意其後的userspace這個詞
複製代碼

class property_service # userspace和用戶空間中的SELinux權限檢查有關,下文再解釋
上述示例展示了SEAndroid中Object Class的定義,其中:
Object Class需要通過class語句申明。這些申明一般放在一個叫security_class的文件中。

另外,這些class和kernel中相關模塊緊密結合。
據說:在kernel編譯時會根據security_class文件生成對應的頭文件。從這裡可以看出,SELinux需要根據發行平台來做相應修改。同時可以看出,該文件一般也不需要我們去修改。
再來看Perm set。Perm set指得是某種Object class所擁有的操作。以file這種Object class而言,其擁有的Perm set就包括read,write,open,create,execute等。
和Object class一樣,SELinux或SEAndroid所支持的Perm set也需要聲明,來看下面的例子:
[external/sepolicy/access_vectors]
  1. #SELinux規範中,定義perm set有兩種方式,一種是使用下面的common命令
  2. #其格式為:common common_name { permission_name ... } common定義的perm set能
  3. #被另外一種perm set命令class所繼承
  4. #以下是Android平台中,file對應的權限(perm set)。其大部分權限讀者能猜出是乾什麼的。
  5. #有一些權限需要結合文後的參考文獻來學習
  6. common file {
  7.       ioctl read write create getattr setattr lock relabelfrom relabelto
  8.       append unlink link rename execute swapon quotaon mounton }

  9. #除了common外,還有一種class命令也可定義perm set,如下面的例子:
  10. #class命令的完整格式是:</font>
  11. # class class_name [ inherits common_name ] { permission_name ... }
  12. # inherits表示繼承了某個common定義的權限注意,class命令定義的權限其實針對得就是
  13. #某個object class。它不能被其他class繼承
  14. class dir inherits file {
  15. add_name remove_name reparent search rmdir open audit_access execmod
  16. }
  17. #來看SEAndroid中的binder和property_service這兩個Object class定義了哪些操作權限
  18. class binder {
  19.       impersonate call set_context_mgr transfer }
  20. class property_service { set }
複製代碼

提示:Object class和Perm set的具體內容(SELinux中其實叫Access Vector)都和Linux系統/Android系統密切相關。所以,從知識鏈的角度來看,Linux編程基礎很重要。
(2) type,attribute和allow等

現在再來看type的定義,和type相關的命令主要有三個,如下面的例子所示:
[external/sepolicy相關文件]
  1. #type命令的完整格式為:type type_id [alias alias_id,] [attribute_id]
  2. #其中,方括號中的內容為可選。alias指定了type的別名,可以指定多個別名。
  3. #下面這個例子定義了一個名為shell的type,它和一個名為domain的屬性(attribute)關聯
  4. type shell, domain ; # 本例來自shell.te,注意,可以關聯多個attribute

  5. #屬性由attribute關鍵字定義,如attributes文件中定義的SEAndroid使用的屬性有:
  6. attribute domain
  7. attribute file_type

  8. #可以在定義type的時候,直接將其和某個attribute關聯,也可以單獨通過
  9. #typeattribue將某個type和某個或多個attribute關聯起來,如下面這個例子
  10. #將前面定義的system類型和mlstrustedsubject屬性關聯了起來
  11. typeattribute system mlstrustedsubject
複製代碼

特別注意:對初學者而言,attribute和type的關係最難理解,因為“ attribute ”這個關鍵詞實在是沒取好名字,很容易產生誤解:
實際上,type和attribute位於同一個命名空間,即不能用type命令和attribute命令定義相同名字的東西。
其實,attribute真正的意思應該是類似type(或domain)group這樣的概念。比如,將type A和attribute B關聯起來,就是說type A屬於group B中的一員。

使用attribute有什麼好處呢?一般而言,系統會定義數十或數百個Type,每個Type都需要通過allow語句來設置相應的權限,這樣我們的安全策略文件編起來就會非常麻煩。有了attribute之後呢,我們可以將這些Type與某個attribute關聯起來,然後用一個allow語句,直接將source_type設置為這個attribute就可以了:
這也正是type和attribute位於同一命名空間的原因。
這種做法實際上只是減輕了TE文件編寫者的煩惱,安全策略文件在編譯時會將attribute拓展為其包含的type。如例子4所示:

[例子4]
#定義兩個type,分別是A_t和B_t,它們都管理到attribute_test
  1. type A_t attribute_test ;
  2. type B_t attribute_test ;

  3. #寫一個allow語句,直接針對attribute_test
  4. allow attribute_test C_t:file {read write} ;
  5. #上面這個allow語句在編譯後的安全策略文件中會被如下兩條語句替代:
  6. allow A_t C_t:file {read write} ;
  7. allow B_t C_t:file {read write} ;
複製代碼

前面講過,TE的完整格式為:
  1. 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:賦予某項權限。
allowaudit:audit含義就是記錄某項操作。默認情況下是SELinux只記錄那些權限檢查失敗的操作。allowaudit則使得權限檢查成功的操作也被記錄。注意,allowaudit只是允許記錄,它和賦予權限沒關係。賦予權限必須且只能使用allow語句。
dontaudit:對那些權限檢查失敗的操作不做記錄。
neverallow:前面講過,用來檢查安全策略文件中是否有違反該項規則的allow語句。

如例子5所示:
[例子5]
  1. #來自external/sepolicy/netd.te文件
  2. #永遠不允許netd域中的進程讀寫dev_type類型的塊設備文件(Object class為blk_file)
  3. neverallow netd dev_type:blk_file { read write }
複製代碼

(3) RBAC和constrain

絕大多數情況下,SELinux的安全配置策略需要我們編寫各種各樣的xx.te文件。由前文可知,.te文件內部應該包含包含了各種allow,type等語句了。這些都是TEAC,屬於SELinux MAC中的核心組成部分。
在TEAC之上,SELiunx還有一種基於Role的安全策略,也就是RBAC。RBAC到底是如何實施相關的權限控制呢?我們先來看SEAndroid中Role和User的定義。
[external/sepolicy/roles]
  1. #Android中只定義了一個role,名字就是r
  2. role r;
  3. #將上面定義的r和attribute domain關聯起來
  4. role r types domain ;
複製代碼

再來看user的定義。
[external/sepolicy/users]
  1. #支持MLS的user定義格式為:
  2. #user seuser_id roles role_id level mls_level range mls_range;
  3. #不支持MLS user定義格式為:
  4. #user seuser_id roles role_id;
  5. #SEAndroid使用了支持MLS的格式。下面定義的這個user u,將和role r關聯。
  6. #注意,一個user可以和多個role關聯。
  7. #level之後的是該user具有的安全級別。s0為最低級,也就是默認的級別,mls_systemHigh
  8. #為u所能獲得的最高安全級別(security level)。此處暫且不表MLS
  9. user u roles { r } level s0 range s0 - mls_systemhigh;
複製代碼

那麼,Roles和User中有什麼樣的權限控制呢?
1)首先,我們應該允許從一個role切換(SELinux用Transition表達切換之意)到另外一個role,例如:
  1. #注意,關鍵字也是allow,但它和前面TE中的allow實際上不是一種東西
  2. #下面這個allow允許from_role_id切換到to_role_id
  3. allow from_role_id to_role_id;
複製代碼

2)角色之間的關係。SELinux中,Role和Role之間的關係和公司中的管理人員的層級關係類似,例如:
  1. #dominance語句屬於deprecated語句,MLS中有新的定義層級相關的語句。不過此處要介紹的是
  2. #selinux中的層級關係
  3. #下面這句話表示super_r dominate(統治,關鍵詞dom) sysadm_r和secadm_r這兩個角色
  4. #反過來說,sysadm_r和secadm_r dominate by (被統治,關鍵詞domby ) super_r
  5. #從type的角度來看,super_r將自動繼承sysadm_r和secadm_r所關聯的type(或attribute)
  6. dominance { role super_r {role sysadm_r; role secadm_r; }
複製代碼

3)其他內容,由於SEAndroid沒有使用,此處不表。讀者可閱讀後面的參考文獻。
話說回來,怎麼實現基於Role或User的權限控制呢?SELinux提供了一個新的關鍵詞,叫constrain,來看下面這個例子:
[例子6]
  1. #constrain標準格式為:
  2. # constrain object_class_set perm_set expression ;
  3. #下面這句話表示只有source和target的user相同,並且role也相同,才允許
  4. #write object_class為file的東東
  5. constrain file write (u1 == u2 and r1 == r2) ;
複製代碼

前面已經介紹過object_class和perm_set了,此處就不再贅述。constrain中最關鍵的是experssion,它包含如下關鍵詞:
u1,r1,t1:代表source的user,role和type。
u2,r2,t2:代表target的user,role和type。
==和!=:==表示相等或屬於,!=表示不等或不屬於。對於u,r來說,==和!=表示相等或不等,而當諸如t1 “ ==或!= ”某個attribute時,表示源type屬於或不屬於這個attribute。
dom,domby,incomp,eq:僅針對role,表示統治,被統治,沒關係和相同(和==一樣)

關於constrain,再補充幾個知識點:
SEAndroid中沒有使用constrain,而是用了MLS中的mlsconstrain。所以下文將詳細介紹它。
constrain是對TEAC的加強。因為TEAC僅針對Type或Domain,沒有針對user和role的,所以constrain在TEAC的基礎上,進一步加強了權限控制。在實際使用過程中,SELinux進行權限檢查時,先檢查TE是否滿足條件,然後再檢查constrain是否也滿足條件。二者都通過了,權限才能滿足。

關於RBAC和constrain,我們就介紹到此。
提示:筆者花了很長時間來理解RBAC和constrain到底是想要幹什麼。其實這玩意很簡單。因為TE是Type Enforcement,沒user和role毛事,而RBAC則可通過constrain語句來在user和role上再加一些限制。當然,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初始化時相關的信息。SID是SELinux中一個概念,全稱是Security Identifier。SID其實類似SContext的key值。因為在實際運行時,如果老是去比較字符串(還記得嗎,SContext是字符串)會嚴重影響效率。所以SELinux會用SID來匹配某個SContext。
initial_sid_context:為這些SID設置最初的SContext信息。

來看這兩個文件的內容:
[external/sepolicy/initial_sids和initial_sid_context]
  1. #先看initial_sids
  2. sid kernel   #sid是關鍵詞,用於定義一個sid
  3. sid security
  4. sid unlabeled
  5. sid fs
  6. sid file
  7. sid file_labels
  8. sid init
  9. ......
  10. #再來看initial_sid_context
  11. sid kernel u:r:kernel:s0 #將initial_sids中定義的sid和初始的SContext關聯起來
  12. sid security u:object_r:kernel:s0
  13. sid unlabeled u:object_r:unlabeled:s0
  14. sid fs u:object_r:labeledfs:s0
  15. sid file u:object_r:unlabeled:s0
  16. sid file_labels u:object_r:unlabeled:s0
  17. sid init u:object_r:unlabeled:s0
複製代碼

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

(2) Domain/Type Transition和宏

SEAndroid中,init進程的SContext為u:r:init:s0,而init創建的子進程顯然不會也不可能擁有和init進程一樣的SContext(否則根據TE,這些子進程也就在MAC層面上有了和init一樣的權限)。那麼這些子進程的SContext是怎麼被打上和其父進程不一樣的SContext呢?
SELinux中,上述問題被稱為Domain Transtition,即某個進程的Domain切換到一個更合適的Domain中去。Domain Transition也是需要我們在安全策略文件中來配置的,而且有相關的關鍵詞,來看例子7。
[例子7-1]
  1. #先要使用type_transition語句告訴SELinux
  2. #type_transition的完整格式為:
  3. # type_transition source_type target_type : class default_type;
  4. #對Domain Transition而言有如下例子:
  5. type_transition init_t apache_exec_t : process apache_t;
複製代碼

上面這個例子的解釋如下,請讀者務必仔細:
當init_t Domain中的進程執行type為apache_exec_t類型的可執行文件(fork並execv)時,其class(此處是process)所屬Domain(對process而言,肯定是指Domain)需要切換到apache_t域。

明白了嗎?要做DT,肯定需要先fork一個子進程,然後通過execv打開一個新的可執行文件,從而進入變成那個可執行文件對應的活物!所以,在type_transition語句中,target_type往往是那個可執行文件(死物)的type。default_type則表示execv執行後,這個活物默認的Domain。另外,對DT來說,class一定會是process。
請注意,DT屬於Labeling一部分,但這個事情還沒完。因為打標籤也需要相關權限。所以,上述type_transition不過是開了一個頭而已,要真正實施成功這個DT,還需要下面至少三個allow語句配合:

[例子7-2]

  1. #首先,你得讓init_t域中的進程能夠執行type為apache_exec_t的文件
  2. allow init_t apache_exec_t : file execute ;
  3. #然後,你還得告訴SELiux,允許init_t做DT切換以進入apache_t域
  4. allow init_t apache_t : process transition ;
  5. #最後,你還得告訴SELinux,切換入口(對應為entrypoint權限)為執行apache_exec_t類型
  6. #的文件
  7. allow apache_t apache_exec_t : file entrypoint ;
複製代碼

為什麼會需要上述多達三個權限呢?這是因為在Kernel中,從fork到execv一共設置了三處Security檢查點,所以需要三個權限。
提示:讀者不必糾結這個了,按照規範做就完了。不過...,這導致我們寫TE文件時候會比較麻煩啊!
確實比較麻煩,不過SELinux支持宏,這樣我們可以定義一個宏語句把上述4個步驟全部包含進來。在SEAndroid中,系統定義的宏全在te_macros文件中,其中和DT相關的宏定義如下:
[external/sepolicy/te_macros]
  1. #定義domain_trans宏。$1,$2等等代表宏的第一個,第二個....參數
  2. define(` domain_trans ', `
  3. # SEAndroid在上述三個最小權限上,還添加了自己的一些權限
  4. allow $1 $2:file { getattr open read execute } ;
  5. allow $1 $3:process transition ;
  6. allow $3 $2:file { entrypoint read execute } ;
  7. allow $3 $1:process sigchld ;
  8. dontaudit $1 $3:process noatsecure ;
  9. allow $1 $3:process { siginh rlimitinh } ;
  10. ')
  11. #定義domain_auto_trans宏,這個宏才是我們在te中直接使用的
  12. #以例子7而言,該宏的用法是:
  13. #domain_auto_trans( init_t , apache_exec_t , apache_t )
  14. define(` domain_auto_trans ', `
  15. # 先allow相關權限
  16. domain_trans($1,$2,$3)
  17. <font size="3"># 然後設置type_transition
  18. <font size="3">type_transition $1 $2:process $3 ;
  19. <font size="3">')
複製代碼

在external/sepolicy/init_shell.te中就有上述宏的用法:
  1. ./init_shell.te:4:domain_auto_trans(init, shell_exec, init_shell)
複製代碼

除了DT外,還有針對Type的Transition。舉個例子,假設目錄A的SContext為u:r:dir_a,那麼默認情況下在該目錄下創建的文件都具有u:r:dir_a這個SContext。所以我們也要針對死得東西進行打標籤。
和DT類似,TT的語句也是type_transition,而且要順利完成Transition,也需要申請相關權限。廢話不再多說,我們直接看te_macros是怎麼定義TT所需要的宏的:
[external/sepolicy/te_macros]
  1. # 定義file_type_trans(domain, dir_type, file_type)宏
  2. #
  3. define(` file_type_trans ', `
  4. # ra_dir_perms是一個宏,由global_macros文件定義,其值為:
  5. #define(`ra_dir_perms', `{ r_dir_perms add_name write }')
  6. allow $1 $2:dir ra_dir_perms ;
  7. # create_file_perms也是一個宏,定義在global_macros文件中,其值為:
  8. # define(`create_file_perms', `{ create setattr rw_file_perms
  9. # link_file_perms }')
  10. #而r_dir_perms=define(`r_dir_perms', `{ open getattr read search ioctl }
  11. allow $1 $3:notdevfile_class_set create_file_perms ;
  12. allow $1 $3:dir create_dir_perms ;
  13. ')

  14. # 定義file_type_auto_trans(domain, dir_type, file_type)宏
  15. #該宏的含義是:當domain域中的進程在某個Type為dir_type的目錄中創建文件時,該文件的
  16. #SContext應該是file_type
  17. define(`file_type_auto_trans', `
  18. file_type_trans($1, $2, $3)
  19. type_transition $1 $2:dir $3 ;
  20. #notdevfile_class_set也是一個宏,由global_macros文件定義,其值為
  21. # define(`notdevfile_class_set', `{ file lnk_file sock_file fifo_file }')
  22. type_transition $1 $2:notdevfile_class_set $3 ;
  23. ')
複製代碼

WoW,SEAndroid太這兩個宏定義太複雜了,來看看官方文檔中的最小聲明是什麼:
[例子8]
  1. type_transition acct_t var_log_t:file wtmp_t ;
  2. allow acct_t var_log_t:dir { read getattr lock search ioctl
  3.                                  add_name remove_name write };
  4. allow acct_t wtmp_t:file { create open getattr setattr read
  5.                                  write append rename link unlink ioctl lock };
複製代碼

在SEAndroid的app.te中,有如下TT設置:
  1. ./app.te:86:file_type_auto_trans(appdomain, download_file, download_file)
複製代碼

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


本文已收錄於以下專欄:深入理解Android
文章出處


 

臉書網友討論
*滑块验证:
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-5-3 17:49 , Processed in 0.084159 second(s), 25 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表