Android 5.1 SEAndroid分析之啓動篇

轉自:http://www.iloveandroid.net/2015/09/28/Android_SEAndroid_1/

前面介紹了init進程中啓動的核心服務中的zygote和property,接下來就介紹下SEAndroid.init進程中加載了SEAndroid的策略文件,開啓了SEAndroid.SEAndroid主要用來提升Android系統的安全體驗,基於SElinux實現.在完備的SEAndroid策略的支持下,縱然獲取了root權限,也沒有多大用處,再也不能像以前那樣爲所欲爲了.因爲在SEAndroid中,root用戶,也僅僅是一個普通用戶而已.

Android sandbox 模型

Android基於linux系統,Android 自然而然的繼承了linux的沙箱模型,只不過Android做了稍許修改而已.

linux系統中每個用戶都有一個UID,不同用戶之間的數據是隔離的,在沒有授權的情況下,用戶只能訪問自己的數據,而不能訪問其他用戶的數據.同一用戶啓動的進程,其UID和GID一致,但是可以通過使用setuid和setgid等系統調用改變UID和GID.Linux 支持多用戶工作,每個用戶之間都使用了因爲UID不同,進而達到相互隔離,互不影響,起到沙箱的作用.

Android擴展了Linux內核安全模型的用戶與權限機制,將多用戶操作系統的用戶隔離機制巧妙地移植爲應用程序隔離。在linux中,一個用戶標識(UID)識別一個給定用戶;在Android上,一個UID則識別一個應用程序。在安裝應用程序時向其分配UID。應用程序在設備上存續期間內,其UID保持不變。僅限用於允許或限制應用程序(而非用戶)對設備資源的訪問。如此,Android的安全機制與Linux內核的安全模型完美銜接!不同的應用程序分別屬於不同的用戶,因此,應用程序運行於自己獨立的進程空間,與UID不同的應用程序自然形成資源隔離,如此便形成了一個操作系統級別的應用程序“沙箱”。

Android系統中將UID通常稱爲APP ID.在手機:

1
/data/system/packages.list

中記錄了當前系統安裝的App信息,其中就有UID,也就是APP ID.

其中第二列就是APP ID.Android 系統本身定義了很多UID,比如1000 代表 system用戶等.

Android源碼/system/core/include/private/android_filesystem_config.h中記錄了Android系統定義的用戶UID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define AID_ROOT             0  /* traditional unix root user */

#define AID_SYSTEM        1000  /* system server */

#define AID_RADIO         1001  /* telephony subsystem, RIL */
#define AID_BLUETOOTH     1002  /* bluetooth subsystem */
#define AID_GRAPHICS      1003  /* graphics devices */
#define AID_INPUT         1004  /* input devices */
#define AID_AUDIO         1005  /* audio devices */
#define AID_CAMERA        1006  /* camera devices */
#define AID_LOG           1007  /* log devices */
#define AID_COMPASS       1008  /* compass device */
#define AID_MOUNT         1009  /* mountd socket */
#define AID_WIFI          1010  /* wifi subsystem */
#define AID_ADB           1011  /* android debug bridge (adbd) 
 . . . . . . 
#define AID_SDCARD_RW     1015  /* external storage write access */
. . . . . 
#define AID_SDCARD_R      1028  /* external storage read access */
. . . . 
#define AID_APP          10000  /* first app user */

...................

#define AID_USER        100000  /* offset for uid ranges for each user */

..........

可以看到安裝的app的 UID是從10000開始分配的.另外要注意的是,Android 已經支持多用戶了,多用戶機制後面有機會的話,會單獨開文章介紹.Android多用戶在手機上沒有太大的使用場景,因爲手機通常屬於私人設備,不像PC那樣,可能有多個人使用,有必要設置多個賬號.所以現在手機廠商默認都將android多用戶機制裁剪掉了.

adb shell 登陸手機終端,並執行ps命令:

第一列就是APPID,類似uY_aXXX,如上圖所示.其中XXX是相對於AID_APP.Y是Android user id(這裏的 user id和前面說的UID含義不一樣,是Android多用戶中的某個用戶ID).

前面android_filesystem_config.h中

1
#define AID_USER        100000  /* offset for uid ranges for each user */

可以看到每個 Android user id之間相差100000.比如上圖中的u0_a12,實際上就是100000+12=100012,也就是說其APPID是100012.

實際上linux 沙箱模型可以歸結爲一句話,進程的權限,取決於啓動他的用戶的權限.比如說某個進程是root啓動的,那麼他就擁有root權限.這種控制模型叫做DAC,全稱是Discretionary Access Control,翻譯爲自主訪問控制.

特殊權限標誌位

su這個程序,大家應該都不陌生,有了他,就能獲取root權限.它是怎麼做到的呢?

1
2
root@generic_x86_64:/system/xbin # ll su
-rwsr-x--- root     shell      338416 2015-02-14 16:10 su

看第一列,似乎多了一個特殊的權限標誌位”s”,這個特殊權限標誌位叫做SUID.

當一個設置了SUID 位的可執行文件被執行時,該文件將以所有者的身份運行,也就是說無論誰來執行這個文件,他都有文件所有者的特權。再來看su他的擁有者是誰,是root.所以su才能使其他程序獲得root權限.

Capability

Linux系統分爲root用戶和非root用戶,root用戶至高無上,想幹嘛幹嘛,至於非root用戶權限有限,想獲得root權限,可以通過setuid系統調用實現。如果一個進程想要一個大於非root用戶權限,只能將自己提升到root權限;實際上此進程並不需要這麼多權限,這可能會導致很多風險(一個進程權限太大),所以POSIX制定了Capability機制來細分root的權限。

Android系統中也使用到了這個機制.

Android源碼/system/core/include/private/android_filesystem_capability.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define CAP_CHOWN 0
#define CAP_DAC_OVERRIDE 1
#define CAP_DAC_READ_SEARCH 2
#define CAP_FOWNER 3
#define CAP_FSETID 4
#define CAP_KILL 5
#define CAP_SETGID 6
#define CAP_SETUID 7
#define CAP_SETPCAP 8
#define CAP_LINUX_IMMUTABLE 9
#define CAP_NET_BIND_SERVICE 10
#define CAP_NET_BROADCAST 11
#define CAP_NET_ADMIN 12
#define CAP_NET_RAW 13
#define CAP_IPC_LOCK 14
#define CAP_IPC_OWNER 15
#define CAP_SYS_MODULE 16
#define CAP_SYS_RAWIO 17
#define CAP_SYS_CHROOT 18
#define CAP_SYS_PTRACE 19
#define CAP_SYS_PACCT 20
#define CAP_SYS_ADMIN 21
. . . . .  .

共有37個權限.

怎麼查看進程具備哪些Capability呢?

我現在以 adb shell的方式連接到了 user版本的android設備,我想看 shell終端具有哪些能力,可以如下操作:

1
2
3
4
5
6
130|shell@shamu:/ $ ps | grep shell                                            
shell     5960  1     16980  212   ffffffff 00000000 S /sbin/adbd
shell     5979  5960  9320   764   c017b054 b6eb2130 S /system/bin/sh
shell     6045  5979  10676  992   00000000 b6f537e8 R ps
shell     6046  5979  10676  988   c022f7ac b6f237e8 S grep
shell@shamu:/ $

找到 shell的進程號爲5979.然後就從proc文件系統中查看shell進程具有哪些能力了:

1
2
3
4
5
6
. . . . . 
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000d
CapBnd: 00000000000000c0
. . . . .

是以位圖的形式表示的,前面說過有37個能力 ,所有37個bit來表示,爲1說明具有相應的能力;爲0說明不具備相應的能力.

其中 CapPrm表示進程具有的最大能力集,CapEff表示當前進程的有效能力集,通常是CapPrm的子集;CapInh表示當前進程啓動其他程序,那些可以被繼承的能力.

CapBnd很重要,表示邊界能力.上面shell進程CapBnd的能力位圖爲c0,即11000000,從android_filesystem_capability.h可以可知其代表

1
2
#define CAP_SETGID 6
#define CAP_SETUID 7

意味着從shell啓動的程序,就算具備特權標誌位,他的能力也會被限制爲CapBnd.shell進程CapInh也爲0,所以從shell啓動的進程的能力被限制爲CAP_SETUID和 CAP_SETGID capabilities,其他能力都被限制了.

也就是說,你有su,也白搭,因爲你的能力被完全限制了,只有37種能力中的兩種.倘若你執行的操作不涉及37種能力,則不受影響.當然如果你的設備是 eng或者debug版本的話,默認能力是全打開的.

能力是對root權限的切割,目前只切割出了這37種能力而已.

SEAndroid的引入

DAC太過寬鬆了,那麼SELinux如何解決這個問題呢?原來,它在DAC之外,設計了一個新的安全模型,叫MAC(Mandatory Access Control),翻譯爲強制訪問控制。MAC的處世哲學非常簡單:即任何進程想在SELinux系統中幹任何事情,都必須先在安全策略配置文件中賦予權限。凡是沒有出現在安全策略配置文件中的權限,進程就沒有該權限.

如下圖所示:

Subject:主體,通常指的是可執行程序.

Object: 客體,通常指某種資源,如文件,硬件等.

用規則來描述主體是否對客體有某種操作權限.

例如,我們可以設定這樣的一個管理策略,不允許用戶A將它創建的文件F授予用戶B訪問。這樣無論用戶A如何修改文件F的權限位,用戶B都是無法訪問文件F的。這種安全訪問模型可以強有力地保護系統的安全。

SELinux架構

SEAndroid可以理解爲是SELinux的精簡版,更適合移動設備.所以有必要介紹下SELinux的架構.

Linux內核中有一個Linux Security Modules,簡稱LSM框架,允許第三方權限訪問機制掛接到內核中來.很類似於linux驅動模型,框架什麼的都有了,只要你按照這個框架寫的東西,都可以掛接到內核中去.SElinux就是由美國NSA按照linux內核安全模型框架編寫的基於MAC訪問控制的模塊.

可以將LSM框架簡單的理解爲一系列的Hook方法,這些方法會在訪問資源的時候被調用,用來簡稱是否有權限.

下圖所示中間部分,即爲LSM模塊.

當某一進程主體發起對某一個文件客體寫操作的時候,LSM模塊Hook到了此次請求,LSM內部的Object Manager首先在 權限訪問緩存中查找是否有對應的規則,如果沒有的話,Security server就會去查詢安全策略中是否有該規則.如果沒有的話,就拒絕此次操作;有的話,就將查詢到的規則放到訪問向量緩存中去,然後向Object Manager報告,允許此次操作,那麼最後進程主體就可以對客體文件進行寫操作了.

DAC機制和MAC機制可以並存,執行的時候先檢查DAC是否滿足,如果不滿足,那就不需要進行MAC檢查了.只有當滿足DAC之後,纔會進行MAC檢查.

SELinux的三種狀態:

Disable: 關閉

Permissive: 寬鬆狀態,違反策略,緊緊是提示而已,操作仍能進行

Enforcing: 執行狀態,違反策略,操作會被拒絕執行.

adb shell進入android 設備終端,執行如下命令,可以查看當前狀態:

1
2
shell@shamu:/ $ getenforce                                                     
Enforcing

可以使用 setenforce命令,在Permission和Enforcing狀態切換,如果是Disable的話,不能切換狀態.

1
2
3
4
5
6
7
8
# getenforce
Enforcing
# setenforce 0
# getenforce
Permissive
# setenforce 1
# getenforce
Enforcing

Android 4.2之前的系統都是Disable.

Android 4.3: Permissive.

– With all domains permissive + unconfined.

Android 4.4: Enforcing.

– Enforcing for installd, netd, vold, and zygote.
– Permissive for app domains (logging denials).
– Permissive + unconfined for all other domains.

Android 5.0: Enforcing.從此版本開始,有了較完備的支持.

查看SELinux 安全上下文

在相關命令前,加-Z即可查看SElinux 安全上下文,如下圖所示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章