淺談SEAndroid安全機制及應用方法
吐槽:準備學習一下SELinux/SEAndroid手裏有一本書《深入理解Android內核設計思想》,看完章節“我是誰?我在哪?”能理解四層的意思,我發現另外的六層都是給會的人寫的,頭大難搞。趁着假期查資料看博客,一點一點修補本文章,有理解偏差或理解不到位的地方望大佬們糾正。
內容提綱:
➢SEAndroid/SELinux簡介
➢SEAndroid/SELinux框架
➢SELinux Policy介紹
➢安全策略文件(TE文件)
➢SELinux安全問題分析
----➢SELinux設備文件權限解決辦法
----➢SELinux服務權限解決辦法
----➢SELinux可執行權限解決辦法
➢補充
----➢客體類型添加
一.SEAndroid/SELinux簡介
SELinux呢這裏就不展開講述了,直接進行SEAndroid機制。前段時間u盤插上板子,作者利用串口交互,以root用戶想要刪除U盤裏的內容,就會報錯誤權限不足,這就得益於SEAndroid對設備的全面保護。
SEAndroid是Google在nlet 4.4 上正式推出的一套以SELinux爲基礎於核的系統安全機制。而SELinux則是由美國NSA (國安局)和一些公司( RedHat、Tresys )設計的一 個針對 的安全加強系統。NSA最初設計的安全模型叫FLASK ,全稱爲Flux Advanced Security Kernel (由Uta大學和美國國防部開發,後來由NSA將其開源) , 當時這套模型針對DTOS系統。後來, NSA覺得Linux更具發展和普及前景,所以就在Linux系統上重新實現了FLASK,稱之爲SELinux。
兩種安全機制DAC(Discretionary Access Control)和MAC(Mandatory Access Control)。通俗地講,這兩個機制的區別是。在DAC裏,如果個應用獲取了一個用戶權限,如Root,那他的所有操作操作都是基於這個用戶權限。而MAC就簡單霸道好多,無論你是誰,甚至是有Root用戶權限,文件權限爲777,但每個動作都是需要被允許之後可以被執行。這裏可以是在安全策略文件中被允許也可以是用戶手動允許 。
二.SEAndroid/SELinux框架
用戶看到的:服務權限、文件權限、屬性權限、APP權限。
SELinux最終編譯成libselinux.so文件,爲上層提供服務。
三.SELinux Policy介紹
SELinux兩個最基本的對象是主體( Subject )和客體(Object )。主體和客體分別對應的是"進程”和“文件”。這裏的文件並不單指的是實際存在的文件,而是指Linux裏"一 切皆文件”裏指的文件。如Socket ,系統屬性等。
在SEAndroid中對主體和客體進行了進一步形式上的封裝和擴展,其實差不多。SEAndroid裏細分爲 :系統文件,服務,系統屬性,Binder和Socket.這裏的系統屬性指的是build.prop裏的屬性,也是getprop命令查詢出來的屬性。
1.ps - Z可以查看當前進程(主體)安全上下文。
root@rk3288:/ # ps -Z
LABEL USER PID PPID NAME
u:r:init:s0 root 1 0 /init
u:r:kernel:s0 root 2 0 kthreadd
u:r:kernel:s0 root 3 2 ksoftirqd/0
u:r:kernel:s0 root 5 2 kworker/0:0H
u:r:kernel:s0 root 7 2 migration/0
u:r:kernel:s0 root 8 2 rcu_preempt
u:r:kernel:s0 root 9 2 rcu_bh
u:r:kernel:s0 root 10 2 rcu_sched
u:r:kernel:s0 root 11 2 watchdog/0
u:r:kernel:s0 root 12 2 watchdog/1
u:r:kernel:s0 root 13 2 migration/1
u:r:kernel:s0 root 14 2 ksoftirqd/1
u:r:kernel:s0 root 16 2 kworker/1:0H
u:r:kernel:s0 root 17 2 watchdog/2
u:r:kernel:s0 root 18 2 migration/2
u:r:kernel:s0 root 19 2 ksoftirqd/2
u:r:kernel:s0 root 21 2 kworker/2:0H
u:r:kernel:s0 root 22 2 watchdog/3
u:r:kernel:s0 root 23 2 migration/3
u:r:kernel:s0 root 24 2 ksoftirqd/3
u:r:kernel:s0 root 26 2 kworker/3:0H
u:r:kernel:s0 root 27 2 khelper
u:r:kernel:s0 root 28 2 kdevtmpfs
左邊的一列是Security Context。u:r:init:s0的意思是:
-
u,是指user,它代表SELinux的一個用戶。
-
r,爲role(角色)即Role Based Access(基於角色的訪問控制,簡稱爲RBAC),它是SELinux中比較高層次。簡單點說,一個u可以屬於多個role,不同的role具有不同的權限。
-
init/kernel,代表該進程所屬的Domain(域)。
-
s0,SELinux爲了滿足軍用和教育行業而設計的MultiLevel Security(MLS)機制。簡單點說,MLS將系統的進程和文件進行了分級,不同級別的資源需要對應的級別的進程才能進行訪問。
2.ls - Z可以查看當前文件(客體)安全上下文。
root@rk3288:/ # ls -Z
drwxr-xr-x root root u:object_r:cgroup:s0 acct
drwxrwxrwx root root u:object_r:rootfs:s0 bin
drwxrwx--- system cache u:object_r:cache_file:s0 cache
lrwxrwxrwx root root u:object_r:rootfs:s0 charger -> /sbin/healthd
dr-x------ root root u:object_r:rootfs:s0 config
lrwxrwxrwx root root u:object_r:rootfs:s0 d -> /sys/kernel/debug
drwxrwx--x system system u:object_r:system_data_file:s0 data
-rw-r--r-- root root u:object_r:rootfs:s0 default.prop
drwxr-xr-x root root u:object_r:device:s0 dev
drwx------ root root u:object_r:rootfs:s0 dmb
-rw-r--r-- root root u:object_r:rootfs:s0 drmboot.ko
drwxrwxrwx root root u:object_r:rootfs:s0 env_flag
lrwxrwxrwx root root u:object_r:rootfs:s0 etc -> /system/etc
-rw-r--r-- root root u:object_r:rootfs:s0 file_contexts
lrwxrwxrwx root root u:object_r:rootfs:s0 fstab.rk30board -> /fstab.rk30board.bootmode.emmc
-rw-r----- root root u:object_r:rootfs:s0 fstab.rk30board.bootmode.emmc
-rw-r----- root root u:object_r:rootfs:s0 fstab.rk30board.bootmode.unknown
drwxrwxrwx root root u:object_r:rootfs:s0 home
-rwxr-x--- root root u:object_r:init_exec:s0 init
-rwxr-x--- root root u:object_r:rootfs:s0 init.connectivity.rc
-rwxr-x--- root root u:object_r:rootfs:s0 init.environ.rc
-rwxr-x--- root root u:object_r:rootfs:s0 init.rc
-rw-r--r-- root root u:object_r:rootfs:s0 張志路-root.txt
- u,是user的意思,表示創建這個文件的SELinux user。
- object_r,這個標誌位在文件裏代表一個用戶角色(role),不同的role具有不同的權限。
- 這是一個type的標誌位,也是TE裏最重要的一個標誌位。不然怎麼怎麼稱爲TE(Type Enforcement);它表示root目錄對應的Type的rootfs。
- s0,MLS的級別。
在這裏細心的朋友就會注意到:“之前我們Linux的label不是UID/GID嗎?怎麼變成了user:role:type:security了呢?”沒錯這都是SEAndroid替換的,注意我說的是‘替換’。SEAndroid呢,主要通過label中的Type來定義安全策略的(這就是Type Enforment)這就是我們.te文件的由來。
讀到這裏你可能就要問了,上面分析的這些信息在哪裏被設置定義的呢?這些信息都在xxx_contexts文件中被登記在案的,前提是要先type定義客體,這個下面還會討論。
- file_contexts
即包括編譯過程中文件的安全標籤,也用於在運行時態對設備節點、socket端口、init.rc產生的/data目錄進行安全標籤的規劃。當你創建新的安全策略時,在某些情況下需要更新這個文件夾分配新的標籤。而爲了讓新標籤生效,這裏就要重新編譯image或者執行restorecon命令。 - genfs_contexts
- 這個文件用於爲不支持擴展屬性的文件系統(列如proc和vfat)添加標籤。這個配置將作爲核心策略的一部分被加載。
- property_contexts
這個文件用於定製Android系統各屬性的標籤,以確認哪些進程可以設置他們。它將在系統啓動時的init進程中被加載,或者是當selinux.reload_policy被置爲1時被重新加載。 - seapp_contexts
這個文件用於爲APP進程和/data/data文件夾指定標籤。系統將在三個時機讀取seapp_contexts文件:1.當一個APP被zygote進程孵化時;2.當installd在啓動時;3.當selinux.reload_policy屬性被置爲1時。
四.安全策略文件(TE文件)
1.介紹
MAC的安全策略文件學名是TEAC(Type Enforcement Access Control)。簡稱TE。裏面的語言被稱爲強制類型語言。
在Android源碼中對應的TE文件所在的路徑爲Android源碼/external/sepolicy/
2.語法
在SELinux當中,所有訪問都必須明確授權,SEL inx默認不允許任何訪問,完全不考慮當前UG0結構,即不考慮用戶/組ID是什麼。這也就意味着,在這裏沒有超級用戶了。那麼如果主體需要對客體進行訪問該如何進行呢?
在SELinux當中,通常是使用allow規則來指定主體類型(即域)對客體類型授子訪問權限,也就是allow規則規定了哪些類型的進程可以訪問哪些客體。allow規則由四部分組成:
/* 主體 客體 */
allow domains types:classes permissons
- domains,原類型(Source type (s) )主體類型, 即域。用於單一進程或一系列進程。
- types,目標類型(Target type(s)) 客體類型。用於標識客體(文件、Socket等)或一系列客體。
- classes,客體類別(Object class (es) )客體的類別。被訪問的客體(文件、Socket等)的具體種類。
- permissons,許可(Permission (s) )主體可以對客體執行哪些操作(讀、寫等)我們稱之爲訪問向量。
3.兩種模式
SELinux Mode,SELinux Mode 有兩種模式Permissve Mode(寬容模式)和Enforcing Mode(強制模式)。區別在於寬容模式只會打印SELinux Log。而強制模式會進行真正攔截。如果被攔截,kernel log中的關鍵字“avc:denied“。可以通過cat /sys/fs/selinux/enforc命令進行查看權限。
setenforce命令:
- setenforce 0 關閉權限。
- setenforce 1 打開權限。
五.SELinux安全問題分析
大致流程:
1.用type關鍵字定義客體。(這裏就發揮一下我的聯想類比能力。就好比出生去type一張身份證)
2.將定義的客體放到【file_contexts】或者【service_contexts】文件中,告訴系統你的客體。(就好像結婚登記)
3.用allow關鍵字添加說明主體訪問客體的權限。(就好像修訂自己家規家法)
log內容分析:
avc:denied{connectto} for pid=2671 comm="ping"
path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
- {connectto},代表的是發生的行爲。整個句子表示有人嘗試去鏈接一個unix stream socket。
- scontext,代表的是發生上述行爲的主體的具體環境。在這個例子中就是某個以shell運行的程序。
- tcontext,代表的是客體的具體環境。在這個例子中就是一個unix_stream_socket的所有者netd。
- comm,comm="ping"表示的是當denial發生時究竟執行了什麼語句。
1.SELinux設備文件權限解決辦法
[53692.570392] type=1400 audit(12565266.940:42): avc: denied
{ read write } for pid=10794 comm="m.example.hello" name="led1"
dev="tmpfs" ino=39430 scontext=u:r:untrusted_app:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=0
分析:
- 缺少什麼權限: read write
- 誰缺少權限: scontext=u:r:untrusted_app:s0 untrusted_app
- 對那個文件缺少權限:tcontext=u:object_r:device:s0 device
- 什麼類型的文件: tclass=chr_file chr_file
解決辦法:在untrusted_app.te文件中添加
Allow untrusted_app device:chr_file {read write }
把缺少的權限添加上去,添加的過程如下:
先進去Android源碼下的/external/sepolicy/下
①修改file_contexts
/dev/led1 u:object_r:led1_device:s0
②修改device.te
type led1_device, dev_type(, mlstrustedobject); (括號內爲6.0權限)
③修改untrusted_app.te
allow untrusted_app led1_device:chr_file rw_file_perms;
添加好了之後重新編譯Android的源碼,燒寫system.img和boot.img
2.SELinux服務權限解決辦法
131 E SELinux : avc: denied { add } for service=Hello
scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0
tclass=service_manager
分析:
- 缺少什麼權限: { add }權限,
- 誰缺少權限: system_server
- 對哪個文件缺少權限:default_android_service
- 什麼類型的文件: tclass=service_manager
解決方法:在system_server.te中添加
allow system_server default_android_service:service_manager add;
先進去Android源碼下的/external/sepolicy/下
①在service.te文件中添加
type Hello_service, (app_api_service,)service_manager_type; (括號內爲6.0權限)
②在service_contexts文件中添加
Hello u:object_r:Hello_service:s0
③在system_server.te文件中添加
allow system_server Hello_service: service_manager add;
3.SELinux可執行權限解決辦法
12-25 11:51:27.260 147 147 W init : type=1400
audit(0.0:4): avc: denied {execute_no_trans } for
path="/system/bin/test" dev="nandd" ino=476
scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0
tclass=file permissive=0
分析:
- 缺少什麼權限: execute_no_trans
- 誰缺少權限: init
- 對哪個文件缺少權限: system_file
- 什麼類型的文件: file
解決方法:在init.te中添加
allow init system_file:file execute_no_trans;
先進去Android源碼下的/external/sepolicy/下
①新建test.te文件中添加
type test,domain;
type test_exec,exec_type,file_type;
init_daemon_domain(test)
②在file_contexts文件中添加
/system/bin/test u:object_r:test_exec:s0
③在init.te文件中添加
allow test system_file:file execute_no_trans;
添加好了之後重新編譯Android的源碼,燒寫system.img和boot.img
六.補充
1.客體類型添加
根據我們上面講的TE文件語法那一小節,瞭解到allow語句。注意allow語句是主體訪問客體缺少權限,allow語句添加權限信息。
但是系統並不認識我們寫的客體,這時,我們就需要用type 語句定義一下我們的客體(客體類型添加),讓系統認識一下。
這裏我們先看一小段init.te的內容:
類型聲明語法:
- type 類型名稱 [alias 別名集] [屬性集],屬性集:設備屬性集dev_type,服務屬性集service_manager_type;
- 別名集如果有多個別名,可在一對大括號中用空
格將各個別名區別開來,如: alias {aliasa_t aliasb_t}。 - 屬性集如果同時指定多個屬性標識符,屬性之間使用逗號進行分隔,如:bin_ type, file_ type, exec_ type;
2.在Android系統中定義自己的SEAndroid
Android系統是允許設備廠商定製自己的安全策略的。先留個尾巴,後續再寫。