深入理解SELinux SEAndroid之二
今天公司年會,哥高興,所以釋出第二部。SELinux/SEAndroid一共分三部分。第一和第二部分是SELinux的基礎知識,第三部分是SEAndroid的工作原始碼分析。
深入理解SELinux SEAndroid 第二部分
3) File/File System 打label
前面一節中,讀者見識到了DT和TT。不過這些描述的都是Transition,即從某種Type或Domain進入另外一種Type或Domain,而上述內容並沒有介紹最初的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關鍵字描述
#目前也僅有pipefs和sockfs兩種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_xattr,fs_use_task和fs_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 網路資料包打標籤
由圖4可以看出,SEAndroid暫時也沒放開網路資料包打標籤的功能。"-j SECMARK --selctx SContext"是iptables(需要支援SELinux功能)新增選項,用來給各種資料包也打上標籤。
除了資料包外,還可以給埠打標籤,這是由portcon關鍵詞來完成的。此處不再詳述,讀者有個概念即可。
2.3 Security Level和MLS
(1) Security Level
上文介紹的TE,RBAC基本滿足了“平等社會”條件下的許可權管理,但它無法反映現實社會中等級的概念。為此,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定義了從c0到c1023,共1024個category。
senstivity和category一起組成了一個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類似,SL1和SL2之間的關係有:
- dom:如果SL1 dom SL2的話,則SL1的sensitivity >= SL2的senstivity,SL1的category包含SL2的category(即Category of SL1是Category of SL2的超集)。
例如:
SL1="s2:c0.c5" dom SL2="s0:c2,c3"
- domby:和dom相反。
- eq:sensitivity相等,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:小寫的L。l1表示源的low senstivity level。l2表示target的low sensitivity。
- h1,h2:小寫的H。h1表示源的high senstivity level。h2表示target的high sensitivity。
- l和h的關係,包括dom,domby,eq和incomp。
mlsconstrain只是一個Policy語法,那麼我們應該如何充分利用它來體現多層級安全管理呢?來看圖5。
圖5 MLS的作用
MLS在安全策略上有一個形象的描述叫no write down和no read up:
- 高級別的東西不能往低級別的東西里邊寫資料:這樣可能導致高級別的資料洩露到低級別中。如圖4中,Process的級別是Confidential,它可以往同級別的File B中讀寫資料,但是隻能往高級別的File A(級別是Secret)裡邊寫東西。
- 高級別的東西只能從低級別的東西里邊讀資料:比如Process可以從File C和File D中讀資料,但是不能往File C和File D上寫資料。
反過來說:
1 低級別的東西只能往高級別的東西里邊寫資料
-----我和小夥伴們解釋這一條的時候,小夥伴驚呆了,我也驚呆了。他們的想法是”低級別往高級別裡寫,豈不是把資料破壞了?“。暈!這裡討論的是洩不洩密的問題,不是討論資料被破壞的事情。破壞就破壞了,只要沒洩密就完了。
2 低級別的東西不能從高級別的東西那邊讀資料
(3) MLS in SEAndroid
再來看看SEAndroid中的MLS:
- 首先,系統中只有一個sensitivity level,即s0。
- 系統中有1024個category,從c0到c1023。
讀者通過mmm external/sepolicy --just-print可以打印出sepolicy的makefile執行情況,其中有這樣的內容:
#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語言中的基本要素都講解完畢,相信讀者對著真實的策略檔案再仔細研究下就能徹底搞明白。
不過,我們前面反覆提到的安全策略檔案到底是什麼?我們前面看到的例子似乎都是文字檔案,難道就它們是安全策略檔案嗎?
拿個例子說事,來看圖6中Android的策略檔案:
圖6 Android策略檔案
Android中,SELinux的安全策略檔案如圖6所示。這麼多檔案,如何處理呢?來看圖7:
圖7 SElinux安全配置檔案生成
由圖7可知:
- 左邊一列代表安全配置的原始檔。也即是大家在圖6中看到的各種te檔案,還有一些特殊的檔案,例如前文提到的initial_sid,initial_sid_contexts,access_vectors、fs_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所示為SEAndroid中sepolicy makefile的執行情況:
圖8 sepolicy makefile執行情況
看明白了嗎?
提示:
想知道如何列印make命令的執行情況?請使用“--just-print”選項
進階閱讀:
1)上述做法是將所有原始檔打包生成一個單一的安全策略檔案,這種方式叫Monolithic
policy。顯然,在什麼都模組化的今天,這種方式雖然用得最多,但還是比較土。
SELinux還支援另外一種所謂的模組化Policy。這種Policy分Base Policy和Module
Policy兩個。BasePolicy為基礎,先載入,然後可以根據情況動態載入Module Policy
目前SEAndroid還沒有該功能,不過以後可能會支援。相信有了它,開發定製企業級
安全管理系統就更方便些。
2)安全策略原始檔非常多。基本上,我們都會在一個參考原始檔上進行相應修改,
而不會完全從頭到尾都自己寫。所以,在發行版上有一個Reference Policy,裡邊
涵蓋了普適的,常用的策略。很明顯,AOSP 4.4中的sepolicy也提供了針對Android
平臺的Reference Policy
2.5 拓展討論
最後,作為拓展討論,我們來看看SELinux作為一套複雜的系統安全模組增強,其實現架構如圖9所示:
圖9 SELinux Component組成
其中:
- Subject:代表發起操作的物件,一般是Process。SELinux需要檢查Subject是否滿足許可權要求
- Object Manager:管理著Object及相應的SContext。OM將向Access Vector Cache查詢所要求的操作是否有許可權。
- AVC主要起一個加速的作用,它將快取一些許可權檢查的結果。當相同的許可權檢查請求過來時,直接從AVC中返回所快取的結果。
- 如果AVC沒有這條許可權檢查的結果,那麼它將向Security Server去查詢。SS內部儲存有SePolicy,它可以根據SEPolicy計算出許可權檢查的結果。
圖9中所示的SELinux Component可以:
- 上述這些模組全部執行在Kernel中,它們也是LSM SElinux的核心模組。
- OM和AVC可以存在於UserSpace中,這種case叫SELinux aware的application。說白了,就是一個使用SELinux的安全監管系統。在Android中,Kernel和Userspace的SELinux都使用了。對於userspace的SELinux相關app來說,需要使用開源動態庫libselinux。在Android平臺中,該庫位於external/libselinux。Userspace的SElinux 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 Hook,Security Server等等。
2.6 參考文獻介紹
SELinux比較複雜,對於初學者,建議看如下幾本書:
1 SELinux NSA’s Open Source Security Enhanced Linux:
評價:講得SELinux版本比較老,不包括MLS相關內容。但是它是極好的入門資料。如果你完全沒看懂本文,則建議讀本文。
2 SELinux by Example Using Security Enhanced Linux:
評價:這本書比第1本書講得SELinux版本新,包括MLS等很多內容,幾乎涵蓋了目前SELinux相關的所有知識。讀者可跳過1直接看這本書。
3 The_SELinux_Notebook_The_Foundations_3rd_Edition:
評價:這是官方網站上下的文件,但它卻是最不適合初學者讀的。該書更像一個彙總,解釋,手冊文件。所以,請務必看完1或2的基礎上再來看它。