轉自: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 安全上下文,如下圖所示