1. 程式人生 > >深入理解SELinux SEAndroid之二

深入理解SELinux SEAndroid之二

今天公司年會,哥高興,所以釋出第二部。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 網路資料包打標籤

由圖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上寫資料。

反過來說:

1 低級別的東西只能往高級別的東西里邊寫資料

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

2 低級別的東西不能從高級別的東西那邊讀資料

(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

評價:講得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的基礎上再來看它。