Android 4.3安全機制探討.

Posted by Lawpig on 6月 04, 2017 | No comments

Android 4.3安全機制探討.

Android 4.3安全機制探討.
by loda
“Good for you, you’ve decided to clean the elevator!”
– The Elevator, from Dark Star
Android 預設的安全機制是透過Linux User-Authentication Security Control,基於使用者帳號與群組管理,提供每個應用程式單一帳號的管理機制. 這機制又稱為DAC (Discretionary access control, 隨意存取控制),所倚靠的就是使用者帳號/群組(ID/Group)的密碼認證稽核,基於此,Linux也是一個供Multi-User使用的環境.但如果有一個應用程式得到Linux系統的Root權限,就有能力沒有限制的存取與竄改系統資料,造成安全問題.
新版的Android將提供Multi-User的操作環境,也就是說一個Android 裝置將有機會被一個以上的使用者登入使用,這情景可能是一個家庭共用的Android 平板電腦,或其它可能基於Android 開發出來的Multi-User裝置. 但同樣的,Android裝置被Root後,獲取本機應用最高執行權,就可存取其他使用者的資料,直接讀寫儲存裝置的Raw Block,或植入惡意程式偷取Multi-User資料.
要解決這問題,原本Linux Kernel DAC機制需要加以強化,而Android 4.3加入的SELinux也是其中最適當的方案,就算使用者在以Linux DAC保護下,取得Root權限,但基於SELinux的Policy,卻能限制Root使用者程式能操作的範圍,並保護Multi-User操作下其他使用者的資料安全問題.
SELinux 對Security Policy是採取白名單 (Whitelist)的策略,也就是說只有被同意的行為才能夠被允許.當開發商為新增的裝置,開發新的功能,就會有需求要不要新增Security Policy,用以確保新的行為正確無誤.Android本身,Android也接受開發商提交對其它開發商也有幫助的Security Policy改動 (http://source.android.com/source/submit-patches.html),       用以作為長期維護的方案.
雖然,最新的Linux Kernel版本已經演進到3.10,且這版本的Linux Kernel也即將成為下一代的Long-Term Support Kernel,但目前Android Kernel最活躍的主線,還是Android 3.4.(https://android.googlesource.com/kernel/common/+/android-3.4).,為了便於訊息的一致性,本文所查核的Linux Kernel Source Code會以筆者使用的3.4.58 Kernel為主.
同樣的,本文在撰寫過程一定會盡力查證相關資訊,但若仍不免有所缺失,還請見諒. 希望本文能對同樣熱愛技術的開發者,有所助益.
Android 4.3 + SELinux Kernel Source Code的取得
首先下載最新的repo程式,
curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/repo
並執行如下命令
~/repo sync
就可以取得Android 4.3 的Source Code.有關Linux Kernel部分,建議是下載最新的Android 3.4 Kernel,但若你的開發環境為x86 Emulator的話,筆者透過SDK升級後,Android SDK內置開發環境還是使用2.6.39 Kernel 版本,使用SELinux上會有困難,若你需要在這環境驗證Android 4.3 + SELinux,則可以透過如下指令下載最新的GoldFish 3.4 Kernel Source Code
git clone https://android.googlesource.com/kernel/goldfish
git checkout –track -b android-goldfish-3.4 origin/android-goldfish-3.4
並透過如下編譯流程
make goldfish_armv7_defconfig
make zImage
就可取得能在Android x86模擬器上執行的zImage (請自行rename到你的x86 Android-18模擬器環境中的kernel-qemu.), 如此即可透過x86模擬器驗證Android 4.3 + SELinux的環境.
Android 4.3 Security新增項目.
要了解Android 4.3 Security的變動,最佳參考資料就是Google的 “Security Enhancements in Android 4.3” 網頁(http://source.android.com/devices/tech/security/enhancements43.html). 不過網頁上所例舉的項目,有些其實在Android 4.3之前就已經包括(可參考筆者另一篇拙作 ”Android 4.1 Jelly Bean安全機制探討” (http://loda.hala01.com/2012/08/android-4-1-jelly-bean%E5%AE%89%E5%85%A8%E6%A9%9F%E5%88%B6%E6%8E%A2%E8%A8%8E-2/),或筆者認為應該跟其它項目結合在一起討論比較適合,就會先以自己的分類來做說明.開發者可根據自己的需求,自行進一步探索.
透過下表讓我們把Android 4.3的Security項目做一個分類後的快速檢視
安全改進項目說明
透過SELinux強化Android sandbox目前Linux Kernel支援多種LSM(Linux Security Modules)模塊,像是AppArmor,SELinux,Smack 與 Tomoyo, Android 4.3選擇的是最被廣為應用的SELinux. 這是一個基於 MAC(Mandatory Access Control)強制存取控制的安全機制 為了避免對應用程式的影響,Enforcing Mode將不會被開啟,而只會維持在Permissive Mode的狀態,以避免有些違反SELinux原則的應用因為開啟這機制後而有預期外的執行結果.但因為是基於Permissive Mode,所以雖然應用程式還是可以執行,但Kernel Log會打印出SELinux AVC(Access Vector Cache)的訊息,可供系統開發者透過Log,查核系統中SELinux違例的狀況.
限制具備SUID/SGID bit (setuid/setgid)能力的程式檔案Linux 檔案系統支援SUID/SGID bits,會讓應用程式在執行時,有機會藉此讓Effective User-ID成為檔案擁有者的權限(“例如該檔案擁有者為root”),若程式本身沒有做好稽核的行為,就會因此開出一個後門導致root權限被取得. 為了防堵這類問題, Android原本就對/data與/cache檔案系統mount時設定”nosuid”,以防止這類情況發生. 新版Android除了盡可能移除具備SUID/SGID bits的程式檔案外,筆者驗證的 /system檔案系統其實也尚未去除nosuid,或許再來的改版會有機會看到Android 4.3把/system檔案系統用nosuid 進行mount,以避免來自Zygote/或衍生的Java APP Process執行SUID程式,導致root權限攻擊的風險.
ADB RSA Authentication.支持ADB在跟電腦連接時,透過RSA Key進行認證機制. 用以避免入侵者透過電腦以未經授權的ADB連線進入Android手機裝置.

限制Android Process Capability的繼承關係在Android 4.3中,導入Linux Kernel 的PR_CAPBSET_DROP屬性,用以在產生新的Process時,透過Kernel把屬於特權等級的Capability給過濾掉,以避免可能存在的安全問題.像是在1, Dalvik VM中,會透過函式forkAndSpecializeCommon(in dalvik/vm/native/dalvik_system_Zygote.cpp)
在要fork出新的Process時,若使用者不為Root,會透過PR_SET_KEEPCAPS設置,以讓當新的Process 改變UID時,所被賦與的權限不被清掉.並透過PR_CAPBSET_READ,從0開始逐一確認Kernel賦與該Process特權的Bit(定義在 include/linux/capability)是否有被設定,若是則透過PR_CAPBSET_DROP逐一的清除掉.
2,在ADB執行時,會透過函式should_drop_privileges(in system/core/adb/adb.c)確認ADB是否要以root權限執行,若非要以root權限執行,就會藉由函式drop_capabilities_bounding_set_if_needed(in system/core/adb/adb.c),除了保留CAP_SETUID與CAP_SETGID bits為,其它的Kernel被賦與的額外權限都會被清除掉.
KeyChain支援查核isBoundKeyAlgorithm透過KeyChain提供isBoundKeyAlgorithm(in frameworks/base/keystore/java/android/security/KeyChain.java),查核裝置的KeyStore是否有設定 KEYMASTER_SOFTWARE_ONLY,若無則表示這裝置支援透過Hardware儲存,並能保護System-wide Key不被Export出去的能力.
支援與強化記憶體溢位查核FORTIFY_SOURCE功能透過致能FORTIFY_SOURCE能在 “bionic/libc/bionic/” 目錄下支援__fgets_chk,__stack_chk_fail,__strlcpy_chk,__umask_chk,__memcpy_chk,__strcat_chk,__strlen_chk,__vsnprintf_chk,
__memmove_chk,__strcpy_chk,__strncat_chk,__vsprintf_chk,
__memset_chk,__strlcat_chk,__strncpy_chk 這些函式,用以查核記憶體是否溢位.目前Android 4.3已在ARM/x86/MIPS的平台上開啟. (設定-D_FORTIFY_SOURCE=1)
改善EntropyMixer在EntropyMixer函式(in frameworks/base/services/java/com/android/server/EntropyMixer.java),透過mBroadcastReceiver支援接收系統發出的ACTION_SHUTDOWN,ACTION_POWER_CONNECTED與ACTION_REBOOT Event,並在收到上述Event時,執行函式writeEntropy.並跟原有的writeEntropy一起搭配,用以確保Entropy結果被妥善保存,以便在系統重啟時提供給立即有需求的裝置使用.
UID/EUID((Effective User ID)  GID/EGID((Effective Group ID)的概念
如前述介紹,考量進一步的安全保護需求,Android會限制Filesystem與檔案SUID/SGID的配置. 因此我們針對這部份的主題,先做一個簡要的介紹,以便讓各位可以清楚SUID/SGID對系統的影響為何.
Linux的chmod指令除了可以設定檔案或目錄的“Owner(rwx):Group(rwx):Others(rwx)”權限外,其實每個檔案都還包括了 “SUID:SGID:SBIT” 這三個 Bits,簡要敘述如下
BitNameNote
2SUIDSet User-ID
會讓執行這檔案的使用者,在這檔案執行過程中Process的Effective User-ID會變成這檔案的擁有者,並擁有同樣的User權限.
1SGIDSet Group-ID
會讓執行這檔案的Group群組,在這檔案執行過程中Process的Effective Group-ID會變成這檔案的擁有Group群組,並擁有同樣的Group權限.
0SBITSticky Bit
這功能只對檔案目錄有意義,設定這個Bit後,就只有本機Root或是目錄擁有者可以刪除該目錄.
透過SUID/SGID我們就可以在特定的應用流程,讓執行該檔案的使用者可以有機會把User ID或Group ID切換為檔案的擁有者 User ID/Group ID.藉此達成特定的目的.最經典的例子應該就是 su與sudo這兩個指令,如下所示
[hlchou@www ~]$ ls -l /bin/su
-rwsr-xr-x. 1 root root 32488 May 30  2011 /bin/su
[hlchou@www ~]$ ls -l /usr/bin/sudo
—s–x–x. 2 root root 186768 Nov 12  2010 /usr/bin/sudo
因為這兩個指令的執行檔案有設定SUID,所以當使用者執行這兩個程式時,就會以 Root 作為當下的Effective UID (也就是具備Root權限的能力),而這兩個程序只要確保沒有”Bug”,在執行過程中也有正確的稽核使用者輸入的密碼,就可以在考慮到基本安全的前提下認證使用者的密碼無誤後,才讓使用者可以切換為指定的使用者帳號(su)或是用Root權限去執行所要執行的應用程式.
再來筆者就用 SUID/SGID設定的例子,來示範操作Set UID/Set GID的Linux流程. 參考如下的test.c範例程式
#include <stdio.h>
int main()
{
printf(“Current UID:%d EUID:%d \n”,getuid(),geteuid());
printf(“Current GID:%d EGID:%d \n”,getgid(),getegid());
return 0;
}
先以root權限編譯後,設定 711讓其他使用者也可以執行.
[root@www hlchou]# gcc test.c -o test
[root@www hlchou]# chmod 711 test
[root@www hlchou]# ls -l test
-rwx–x–x. 1 root root 6731 Aug 11 07:55 test
當以一般使用者帳號執行時,可以看到UID/EUID都是屬於該使用者的對應ID
[hlchou@www ~]$ ./test
Current UID:503 EUID:503
Current GID:504 EGID:504
如果設定 SUID bit,在執行這應用程式的過程讓seteuid的流程發生,操作如下
[root@www hlchou]# chmod 4711 test
[root@www hlchou]# ls -l test
-rws–x–x. 1 root root 6731 Aug 11 07:55 test
我們在以剛才一般使用者帳號,重新執行一次 test 執行檔,就可以看到UID/EUID執行結果如下
[hlchou@www ~]$ ./test
Current UID:503 EUID:0
Current GID:504 EGID:504
也就是執行者的UID=503, 但因為該檔案有SUID Bit,所以EUID最後會是root的UID=0,也因此這個Process就會以Linux DAC root權限來執行.
如下所示,當也設定 SGID時
[root@www hlchou]# chmod 6711 test
[root@www hlchou]# ls -l test
-rws–s–x. 1 root root 7060 Aug 11 08:24 test
轉換到非Root帳號執行後,會發現不只是EUID變成root,連執行當下有效的EGID都會變成root所屬的Group.
[root@www hlchou]# su hlchou
[hlchou@www ~]$ ./test
Current UID:503 EUID:0
Current GID:504 EGID:0
把最基礎的SUID/SGID問題做說明後,再來就以Linux提供的LSM Plug-in為標的進一步加以解析.
Linux Security Modules
Linux Kernel支援Security Plug-in的LSM(Linux Security Modules)機制,用以讓希望在Kernel加入Security稽核的產品,可以有一個標準化的作法,而不是每個Security模塊各自根據自己的需求在Linux Kernel Source Code去安插查核點的代碼,並衍生後續維護上的困難.如下,為目前Linux Kernel支援LSM模塊的示意圖
查核2.6 Kernel Source Code,最早被納入LSM的模塊為美國國家安全局NSA(National Security Agency, http://www.nsa.gov/research/selinux/)所開發的SELinux架構.(筆者能查到的日期/版本為2003年Linux kernel 2.6.0-test3) 概念為以類似燒瓶的安全架構(Flask security architecture),基於MAC(mandatory access control)針對不同的Role/Domain/Object提供彈性的強制存取管控安全需求.
隨後,到了2.6.25 Kernel,由Casey Schaufler所開發的Smack(Simplied Mandatory Access Control Kernel)也被納入,作為另一套LSM的選擇,參考作者的Paper “Smack in Embedded Computing” (fromhttp://ols.fedoraproject.org/OLS/Reprints-2008/schaufler-reprint.pdf),主要透過最長23個字元以Null結尾的字串來表示Label, 每一個Task對Object的存取都必需要跟Label定義的稽核機制吻合才能放行,這方案設計主要應用在Embedded System的安全需求,已知像是MeeGo,WindRiver..etc都有相關產品應用.目前的官網為 http://schaufler-ca.com/.
之後,在2.6.30 Kernel 加入了由日本NTT Data Corporation所開發的TOMOYO,作為新的LSM成員,最早加入Linux 主線的版本為TOMOYO Linux 2.2 (最新版本則為TOMOYO Linux 2.5),這是一套以Pathname為基礎的Security稽核機制,有一篇在LWN的文章 “TOMOYO Linux and pathname-based security” (in http://lwn.net/Articles/277833/),可供有興趣的開發者參考,目前的官網為http://tomoyo.sourceforge.jp/ .
到了2.6.36 Kernel,則加入了由Immunix開發的AppArmor(Application Armor),並由Novell支持至2007年後終止,這也是一套以Pathname為基礎的Security稽核機制,跟SELinux最大的不同在於,SELinux識別FileSystem Object是以inode的編號為主,因此就算同一個檔案產生兩個不同的Hard Link,都還是可以透過SELinux識別出正確的Security Object參數.但AppArmor是以File Path為識別的基礎,因此在AppArmor下,只要把檔案Hard Link到不同的路徑就可以避開稽核.由於Linux本身就包含了Path-based 與 Inode-based 的存取控制,只要使用者檔案權限有正確設定,就還是能夠涵蓋這部份的安全操作. (例如設定為chmod 700的檔案就算Hard Link還是會繼承前者的700權限設定),目前AppArmor的官網為http://wiki.apparmor.net/index.php/Main_Page.
到了3.4 Kernel,則新增了Yama, 作者為Chromium OS的開發者 Kees, Yama 是一個基於LSM機制用來強化Linux DAC的安全機制,本身並非如前述LSM模塊,要成為功能完整的Security Module,而只針對現有DAC要強化的部份進行補強.像是改善ptrace的安全問題,傳統上,使用者可以藉由GDB呼叫ptrace去執行一個要被Attach的Process,或具有Root權限的使用者,也可以透過ptrace去Attach想要抓取記憶體資料的Process,基於Yama LSM,在透過“/proc/sys/kernel/yama/ptrace_scope”設定為Mode 1 “restricted ptrace”時,則需先藉由PR_SET_PTRACER設定能被ptrace Attach的Process關係,才能讓ptrace Attach發揮作用,藉此強化DAC環境的安全. 有關Yama的進一步資訊,可參考Linux Kernel Soruce Code中的文件 “Documentation/security/Yama.txt”.
再來就是從LSM代碼進行查核,但由於這並非本文主要的議題,會盡量簡要的說明,有興趣的開發者還請自行參閱Linux Kernel Source Code.
LSM 的進一步探究
Linux Security Modules (LSM) Source Code位於 security目錄下,每個想在Linux Kernel實現 Linux Security Modules的Securuity機制都可以透過函式 register_security (in security/security.c),註冊屬於自己的Linux Security Modules (LSM)機制,由於LSM已經在Kernel關鍵的位置都埋好Security查核的點,因此要支援LSM的開發者,只需要透過函式 register_security 註冊 struct security_operations *security_ops (in include/linux/security.h),就可以讓Linux Kernel在運作時,主動在關鍵的查核點呼叫所提供的Callback函式,確認當下Security稽核的狀況. 有關struct security_operations 的定義可以參考線上Source Code “http://hala01.com/src/linux/linux-3.4.58/HTML/S/3591.html#L1381″.
談完了LSM,再來就該鎖定Android 4.3最大的改動SELinux來做說明.其實只要Google一下就會發現深入介紹SELinux的技術文章非常多,既然這是一個成熟也被廣泛使用的技術,重新撰寫同樣的文章其實幫助有限,接下來對SELinux的簡述,會以概要的方式帶過這體系的演進,有關SELinux技術與實際的操作,還請自行參閱網路上的文件.
SElinux緣起
SELinux是在2003年的Linux Kernel 2.6之後納入到Linux Kernel的範疇中,最早的發想是來自於美國國家安全局NSA(National Security Agency).參考美國國家安全局(NSA)的網頁(http://www.nsa.gov/research/selinux/),SELinux是採用類似燒瓶的安全架構(Flask security architecture),用以提供多樣的強制存取管控,可針對包括存取的類型/角色/不同等級的安全需求. 如下圖所示,使用者登入後會被賦與對應的Role,再根據應用的場景會被轉移到不同的Domain中,而不同的Domain就會具備不同層級的安全存取權限.
支援Security-enhanced Linux kernel的核心,會基於MAC(mandatory access control)原則,限制使用者程序或服務擁有最小能運作的權限,因為是基於這樣嚴格受限的權限管控概念,當使用者的程式或服務因為緩衝區溢位(Buffer Overflow),或一些設計上的錯誤導致安全問題發生時,就可以把損害降到可控的範圍.相對於原本Linux Kernel基於使用者的帳號/群組的概念,SELinux並沒有所謂的Root使用者(也就是Super-User)的概念,也不需透過setuid/setgid來規範使用者/群組的權限,它是一個獨立於傳統Linux Access Control的機制.傳統的Linux Kernel會仰賴系統管理者有正確的設定應用程式帳號權限,與保護好重要帳號權限的安全問題,一旦特權等級使用者的帳號被破壞,那整個系統的傷害也就不容小覷.而SELinux是基於對Kernel與Security Policy正確設定來施行保護,當應用程式發生安全問題時,則能把損害範圍限制在個別使用者的應用程式或系統服務範圍中.可避免因為其它應用程式的安全問題而讓整個系統受到安全威脅.
SELinux設計用來防範應用程式資料被其他程序讀取或是竄改,或藉漏洞跳過安全稽核的檢查,執行不被信賴的應用程式,透過違反系統安全原則(Security Policy)干擾其他應用程式. SELinux 的實做包括 LSM 與 MSL for Sensitivity Levels and Categories 兩部份, SELinux預設的MLS (Multi-Level Security)數值起點為 s0,數值越大表示安全要求的Sensitivity Level越高,而Security Category表示所屬Security Level對應的分類 (若不設定,預設為 c0),不同的Categories就算是屬於同一個Sensitivity Level,也是不能Access對應的物件. 原因在於MLS是把同一個Sensitivity Level,但不同的Categories 視為兩個不同的Sensitivity Level來源,因此會認為這兩個不同來源的Access,應該分屬兩個不同的群體,因而不具備另一方的Access權限.
Android SELinux解析
Android 4.3中,SELinux Security Policy制定的檔案主要存放在Android 4.3 Source Code “external/sepolicy/” 目錄下,並提供以下三個命令供SELinux使用上查核
1,/system/bin/getenforce:可用以查核系統支援SELinux的狀況,像是
root@generic:/ # getenforce
Permissive è表示SELinux示在Permissive Mode
root@generic:/ # getenforce
Enforcing è表示SELinux示在Permissive Mode
root@generic:/ # getenforce
Disabledè當下組態,並不支援SELinux (通常是Linux Kernel 沒有被設定正確)
2,/system/bin/setenforce:用以在有支援SELinux的環境,決定要使用Enforcing或Permissive Mode.
sroot@generic:/ # etenforce
usage:  setenforce [ Enforcing | Permissive | 1 | 0 ]
3, /system/bin/sepolicy:用以載入指定位置的SELinux Policy二進位檔案
127|root@generic:/ # load_policy
usage:  load_policy policy-file
1|root@generic:/ # load_policy /sepolicy
load_policy /sepolicy
ANDROID 4.3 + SELinux的環境,因為採用白名單的概念,只有關於系統安全/應用必需的選項,才會致能,基本的概念就是最小特權開放的原則 (Principle of least privilege, http://en.wikipedia.org/wiki/Principle_of_least_privilege).
Android SELinux文件中提供了以下Use Case作為範例,用以說明SELinux Policy.
1, Symlinks
在Linux的環境中,Symbol Link會以檔案的方式存在,這可能會帶來一些問題. 例如,init程式會在初始化的過程中去改變檔案的權限,若駭客透過Symbol Link產生檔案,並用自己的帶有惡意代碼的檔案置換.就有機會產生安全上的風險.  對SELinux來說,若我們已經很明確的知道自己的程式一定不會去Access透過 Symbol Link產生的檔案,就可以透過SELinux Policy來禁止這樣的行為.
2, System files
透過SELinux,可以定義一類(Class)的檔案為System Server才會存取的檔案,就算其它行程是以Root身分所執行的,也都不能存取這些檔案.除非這些行程能把自己切換到System Server執行的Domain.
3, APP Data
在實際應用上,如果有行程必需要具備Root權限才能達成任務.而這個行程又不需具備去存取網路應用有關程式的資料.只要不把這行程加入白名單中,就可確保這部份資料的安全無虞.
4, setattr
可透過把檔案區分為 APP/Shell/System…etc(app_data_files,shell_data_files and system_data_files).用以限定像是透過 chmod/chown這類會改變檔案Attributes的指令只能在App Data類的檔案有作用.
再來就是針對Android SELinux的相關設定與配置加以說明,
1,SELinux policy source (*.te) 檔案路徑
針對整個Android SELinux通用的 Policy 檔案路徑為 external/sepolicy
針對特定裝置的 SELinux Policy檔案路徑為
device/asus/grouper/sepolicy
device/lge/mako/sepolicy
device/samsung/manta/sepolicy
device/samsung/tuna/sepolicy
針對特定產品的Security Policy檔案,建議放在對應裝置的路徑中.
2,修改 BoradConfig.mk
可透過 device目錄下,看到如下產品的參考設定.
./device/asus/grouper/BoardConfig.mk
./device/lge/mako/BoardConfig.mk
./device/samsung/manta/BoardConfig.mk
./device/samsung/tuna/BoardConfig.mk
有關BoardConfig.mk跟SELinux Policy設定有關的變數說明,可以參考如下表的簡述.
SELinux Policy Generation Variables in BoardConfig.mk以Ausu Grouper產品為例,路徑在device/asus/grouper/BoardConfig.mk
NameNote
BOARD_SEPOLICY_REPLACE用以取代/置換原本放在 external/sepolicy 屬於跟Device無關的Policy定義檔案. 如果所指定要置換的檔案並不存在  external/sepolicy 目錄下,則會產生錯誤.
BOARD_SEPOLICY_UNION用以作為原本放在external/sepolicy目錄下Policy定義檔案的擴充,會跟同名的檔案做聯集,成為一個包括Android原本Policy定義與也包括特定裝置客製化Policy定義的內容.
以Ausu Grouper產品為例,
BOARD_SEPOLICY_UNION := \
file_contexts \
genfs_contexts \
app.te \
btmacreader.te \
compatibility.te \
device.te \
drmserver.te \
init_shell.te \
file.te \
rild.te \
sensors_config.te \
shell.te \
surfaceflinger.te \
system.te \
zygote.te
BOARD_SEPOLICY_DIRS用以指向存有供特定裝置的BOARD_SEPOLICY_UNION 與BOARD_SEPOLICY_REPLACE 使用的Policy檔案目錄路徑.
(編譯後,可參考路徑out/target/product/<device>/etc/sepolicy_intermediates/policy.conf).
參考上述的說明,如果同一個檔案同時被BOARD_SEPOLICY_UNION 與 BOARD_SEPOLICY_REPLACE所包括,則會產生錯誤.
以Ausu Grouper產品為例,
BOARD_SEPOLICY_DIRS := \
device/asus/grouper/sepolicy
BOARD_SEPOLICY_IGNORE如果有指定目錄下的Policy檔案是這個裝置所不希望納入的,則可在這變數中加入.
3,修改 file_contexts,加入要納入Policy的檔案,
例如路徑 device/asus/grouper/sepolicy/file_contexts,
開發者只需加入要納入Policy的檔案,重新編譯,以便讓新增的檔案/Policy發揮作用.
一個Android SELinux的 Policy檔案主要包括三個部份
1,Allow: 把對目標 Context 執行操作的權限, 交給指定的Domain.
2,Domain: 定義Policy指定的Domain範圍,對Kernel而言會對應到一個SID (Security Identifier).
3,Context: 定義該Policy Rule的內容, 對Kernel而言,會對應到一個 Rule ID (Identitier),已供識別
因此一個完整的Policy描述會像是如下
“allow appdomain app_data_file:file rw_file_perms;”
其中
1,ALLow: allow
2,Domain: appdomain
3,Context: app_data_file:file rw_file_perms
這個Policy Rule用來表示, 屬於Domain Appdomain的應用程式,被允許可以讀寫有被標籤屬於 “app_data_file” 的應用程式檔案.在編譯過程後,這就會成為SELinux Policy新增的一部分.
關於Android SELinux Class的定義, 參考 Android external/sepolicy/access_vectors, external/sepolicy/security_classes 與 Linux Kernel security/selinux/include/classmap.h檔案,可以看到Android/SELinux會把系統行為分類為幾大類的Class,主要包括 File,Socket,IPC,Userspace Database Object,Pointer and Keyboard這幾大類,如下表格所示
Class CategoriesClass Name
File-related objectsFilesystem,Dir,File,lnk_file,
chr_file,blk_file,sock_file,fifo_file,fd.
Network-related objectsSocket,tcp_socket,udp_socket,rawip_socket,
node,netif,netlink_socket,packet_socket,
key_socket,unix_stream_socket,unix_dgram_socket
Process-related objectsprocess
Ipc-related objectsIPC, sem, msgq , msg, shm
Security serversecurity
System operationssystem
Controling capabiliescapability,capability2
Controlling changes to passwd informationpasswd
SE-X Windows stuffx_drawable, x_screen, x_gc, x_font, x_colormap, property,x_selection,x_cursor,x_client,x_device,
x_server,x_extension,x_resource,x_event,x_synthetic_event
Extended Netlink classesnetlink_route_socket,netlink_firewall_socket,netlink_tcpdiag_socket,
netlink_nflog_socket,netlink_xfrm_socket,netlink_selinux_socket,
netlink_audit_socket,netlink_ip6fw_socket,netlink_dnrt_socket
Controlling access and communication through the D-BUS messaging systemdbus
Controlling access through the name service cache daemon (nscd)nscd
Controlling access to IPSec network data by associationassociation
Updated Netlink class for KOBJECT_UEVENT familynetlink_kobject_uevent_socket
network peer labelspeer
Othersappletalk_socket,packet,key,context,dccp_socket,memprotect,
db_database,db_table,db_procedure,db_column,db_tuple,
db_blob,x_application_data,kernel_service,tun_socket,
x_pointer,x_keyboard,db_schema,db_view,db_sequence,
db_language,binder,zygote,property_service
並會透過 File Contexts (in external/sepolicy/file_contexts) 設定對應路徑預設的SELinux檔案屬性.
SELinux Access vector cache (AVC) Kernel Log
在有啟動SELinux的環境下,例如以筆者的Linux工作站為例,透過dmesg就可以看到有關SELinux作用下,的檢查機制訊息.
type=1400 audit(1376604216.234:41987): avc:  denied  { search } for  pid=17022 comm=”sendmail” dev=sdb3 ino=59113482 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:postfix_spool_t:s0 tclass=dirtype=1400 audit(1376604216.273:41988): avc:  denied  { search } for  pid=17023 comm=”sendmail” dev=sdb3 ino=59113482 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:postfix_spool_t:s0 tclass=dir
但如果你在目前版本的Android 4.3上,也希望可以查核到類似的SELinux AVC存取稽核錯誤訊息,會發現Kernel Log並找不到這些字串,原因除了目前預設為Permissive Mode外 (Permissive只是不禁止操作,但還是會打印違規的Log),最重要的是目前的Android 4.3 SELinux Policy支援了”unconfined_domain”的TE巨集,目前主要的Domain TE設定檔案,會把在定義Domain時也加上”unconfined_domain”巨集的設定,如此就會讓所有的SELinux Domain都成為毫無限制的Domain. 如果要實際驗證SELinux AVC的稽核結果,筆者的作法為修改檔案” external/sepolicy/te_macros”中的
#####################################
# unconfined_domain(domain)
# Allow the specified domain to do anything.
#
define(`unconfined_domain’, `
typeattribute $1 mlstrustedsubject;
typeattribute $1 unconfineddomain;
‘)
改為
#####################################
# unconfined_domain(domain)
# Allow the specified domain to do anything.
#
define(`unconfined_domain’, `
#typeattribute $1 mlstrustedsubject;
#typeattribute $1 unconfineddomain;
‘)
刻意讓”unconfined_domain”巨集內容為空,重新編譯後,就可以看到你的Android 4.3 SELinux AVC Kernel Log在打印相關的違例訊息了.
在Android 4.3裝置上,就可透過dmesg指令,查詢有avc 字串的SELinux Kernel Log了. (或透過adb shell dmesg | grep avc). 筆者摘要Android 4.3上SELinux AVC Kernel Log內容如下所示
<5>[ 2057.468752] (1)[237:adbd]type=1400 audit(1357001068.255:4584): avc:  denied  { open } for  pid=237 comm=”adbd” path=”/dev/ptmx” dev=”tmpfs” ino=3147 scontext=u:r:adbd:s0 tcontext=u:object_r:ptmx_device:s0 tclass=chr_file
<5>[ 2057.472129] (1)[237:adbd]type=1400 audit(1357001068.255:4585): avc:  denied  { ioctl } for  pid=237 comm=”adbd” path=”/dev/ptmx” dev=”tmpfs” ino=3147 scontext=u:r:adbd:s0 tcontext=u:object_r:ptmx_device:s0 tclass=chr_file
<5>[ 2057.474762] (1)[237:adbd]type=1400 audit(1357001068.255:4586): avc:  denied  { fork } for  pid=237 comm=”adbd” scontext=u:r:adbd:s0 tcontext=u:r:adbd:s0 tclass=process
<5>[ 2065.183385] (1)[5459:ps]type=1400 audit(1357001075.965:4607): avc:  denied  { getattr } for  pid=5459 comm=”ps” path=”/proc/3796″ dev=”proc” ino=16450 scontext=u:r:init_shell:s0 tcontext=u:r:shell:s0 tclass=dir
<5>[ 2065.185931] (1)[5459:ps]type=1400 audit(1357001075.965:4608): avc:  denied  { search } for  pid=5459 comm=”ps” dev=”proc” ino=16450 scontext=u:r:init_shell:s0 tcontext=u:r:shell:s0 tclass=dir
<5>[ 2065.189092] (1)[5459:ps]type=1400 audit(1357001075.975:4609): avc:  denied  { read } for  pid=5459 comm=”ps” dev=”proc” ino=15703 scontext=u:r:init_shell:s0 tcontext=u:r:shell:s0 tclass=dir
<5>[ 2065.191501] (1)[5459:ps]type=1400 audit(1357001075.975:4610): avc:  denied  { open } for  pid=5459 comm=”ps” path=”/proc/3796/task” dev=”proc” ino=15703 scontext=u:r:init_shell:s0 tcontext=u:r:shell:s0 tclass=dir
Android SELinux Run-TimeID/Process/檔案配置.
接下來讓我們透過簡單的指令,查核Android 4.3下有關SELinux的環境與配置狀況.
首先,可以透過 id –Z,查核使用者帳號與其Security配置
IDid -Z for security info.
rootuid=0(root) gid=0(root) context=u:r:shell:s0
su to radiouid=1001(radio) gid=1001(radio) context=u:r:su:s0
su to u0_a23uid=10023(u0_a23) gid=10023(u0_a23) context=u:r:su:s0
查核Process Security配置,則可透過 ps –Z,簡要內容分類如下(根據不同的Domain區分Process)
Domain nameReference process
kernelkthreadd,ksoftirqd,kworker,
khelper,sync_supers,bdi-default,
kblockd,rpciod,kswapd,
fsnotify_mark,crypto,
mtdblock0,mtdblock,
binder, deferwq,ccc,flush
init/init
ueventd/sbin/ueventd
servicemanager/system/bin/servicemanager
vold/system/bin/vold
netd/system/bin/netd
debuggerd/system/bin/debuggerd
surfaceflinger/system/bin/surfaceflinger
zygotezygote
drmserver/system/bin/drmserver
mediaserver/system/bin/mediaserver
installd/system/bin/installd
keystore/system/bin/keystore
qemud/system/bin/qemud
init_shell/system/bin/sh
adbd/sbin/adbd
systemsystem_server
radiocom.android.phone
release_appcom.android.providers.calendar,
com.android.browser,
android.process.acore,
com.svox.pico,
com.android.email,
com.android.exchange
shared_appcom.android.launcher,
com.android.inputmethod.latin,
com.android.quicksearchbox
platform_appcom.android.systemui,
com.android.sharedstoragebackup,
com.android.defcontainer
untrusted_app…etc
isolated_app…etc
rild/system/bin/rild
shell/system/bin/sh,
ps,logcat
sush
透過 ls –Z,則可以查核每個檔案物件配置的Security屬性,同樣的根據File Type,Security與路徑簡要分類如下
File TypeSecurity SettingsReference Path
rootfsu:object_r:rootfs:s0/config
/init
/init.rc
cache_fileu:object_r:cache_file:s0/cache
cgroupu:object_r:cgroup:s0/acct
procu:object_r:proc:s0/proc
sysfsu:object_r:sysfs:s0/sys
unlabeledu:object_r:unlabeled:s0/data/resource-cache
/data/security
/data/data
/data/data/com.android.shell
system_fileu:object_r:system_file:s0system
system_data_fileu:object_r:system_data_file:s0/data
/data/nativebenchmark
/data/nativetest
/data/data/com.android.settings
platform_app_data_fileu:object_r:platform_app_data_file:s0/data/data/com.android.providers.calendar
/data/data/com.android.providers.contacts
/data/data/com.android.providers.downloads
radio_data_fileu:object_r:radio_data_file:s0/data/data/com.android.providers.telephony
app_data_fileu:object_r:app_data_file:s0/data/data/com.android.widgetpreview
/data/data/com.example.android.apis
/data/data/com.example.android.livecubes
/data/data/com.example.android.softkeyboard
tombstone_data_fileu:object_r:tombstone_data_file:s0/data/tombstones
backup_data_fileu:object_r:backup_data_file:s0/data/backup
anr_data_fileu:object_r:anr_data_file:s0/data/anr
apk_data_fileu:object_r:apk_data_file:s0/data/app
總結上述系統的瀏覽狀況,我們可以從Role,Process,Domain與檔案Object的關係得到如下的示意圖,使用者必需要在具有權限Access的Domain中才可以去存取想要的物件. 就算是具備Root權限的使用者,如果沒有存取對應Object所需的安全配置,也會被禁止存取物件,藉此確保系統的安全性.
最後,就是讓筆者碎碎念一下對於MLS/DAC/MAC這些機制差異的部份,除了讓自己長一些知識外,也希望對大家有幫助.
MLS (Multi-Level Security)
MLS是目前SELinux採用的MAC (Mandatory access control)前身,由美國軍方單位所推展,主要概念為把Subject/Object定義不同的安全等級,並管控資料從低安全等級向高安全等級傳遞,低安全等級只能對高安全等級的Object寫入資料,不能讀取.而高安全等級只能跟低安全等級的Object讀取資料而不能寫入.運作的概念如下圖所示.
但由於MLS是非常嚴格的限定資料的流向管控,但卻並不適用於所有的安全場景中,此外也並非所有High-Level Security等級的內容都與機密有關,因此需要一個有彈性,且基於Type的Access Control,用以實現安全管控的高度配置能力.
隨意存取控制DAC (Discretionary access control)
DAC(Discretionary Access Control)是傳統Unix/Linux環境的安全管控機制,透過使用者帳號(Identity)或群組(Group)歸屬的方式,來限制控管物件的存取權限,相較於完全沒有安全管控的環境(也就是每個使用者都可以存取所有檔案資料的機制), DAC主要基於 “Owner(rwx):Group(rwx):Others(rwx)” 為概念 (如下所示),定義存取執行權限,用以提供最基本的保護措施.
$ ls -l
-rwxr-xr-x.  1 root   root        2458 May 20  2012 set-xcode-analyzer
-rw-r–r–.  1 root   root       16917 May 20  2012 sorttable.js
drwxr-xr-x.  2 root   root        4096 Jul 28  2012 spider
如同前述UID/EUID的操作範例,一旦系統管理者的檔案設定了SUID,但又因為安全漏洞,導致這檔案本身的稽核流程疏失,而讓第三方的程式有機會藉此取得系統的Root權限,就會導致管控以外的重大安全漏洞.在傳統的Linux DAC機制下,我們可能因為一些系統設計上的需求,就把Root權限給了特定的使用者,    取得這權限的使用者,就有機會可以對Storage執行 Raw Block的寫入操作,進而有機會去竄改系統的設定,但在SELinux MAC保護下,雖然使用者具備Root權限,但因為MAC Policy並不允許直接對Storage Raw Block作寫入的操作,     也因此,這樣的操作就會被MAC Policy稽核的流程給擋下.進而確保系統的安全性.
強制存取控制 MAC (Mandatory access control) –
MAC跟DAC的機制在定義上可說是相對的,因此查詢資料時,MAC又稱為 ”Non-Discretionary Access Control”.  MAC (Mandatory access control) 指的是更嚴格的安全管理措施,針對像是Process/Thread所能使用的記憶體單元,檔案(Files),目錄(Directory),TCP/UDP Ports,進行管理的措施.當有一個Process/Thread要對這些資源進行存取的行為時,作業系統就會驗證兩者安全屬性(Security Attributes),是否符合才許可執行後續的動作.甚至,包括像是資料庫系統,也可以套用MAC管理機制,針對要存取資料庫Table/View/Procedures的Process/Thread進行安全管控.
參考 Android 4.3 CCD (Compatibility Definition Document)文件 (http://source.android.com/compatibility/android-4.3-cdd.pdf),Android 4.3 Sandbox會基於SELinux MAC(Mandatory Access Control)提供安全保護措施.並讓安全機制與Framework的改動,是讓使用者,開發者與應用程式執行流程沒有差異,確保相容性問題,所提供的API也要避免可讓任一APP設定後而影響到其它APP的行為.因此,Android 4.3預設的 SELinux的行為是Permissive Mode (非強制開啟的Enforcing Mode),所有應用程式違例的操作只會顯示在透過dmesg查看的Kernel Log中,而不會讓應用程式真的因此而無法執行,或導致相關的正確性問題.並支援Dynamic Policy Update, 可以不用整個System Image都更新,只更新所需的Security Policy. Android 4.3 SELinux的Policy主要儲存在根目錄的 /sepolicy檔案中.
在同時包括DAC+MAC的系統上 (也就是把Linux 中的SELinux打開的組合).我們可以把DAC看成是Linux 環境中原生就支援的基礎安全管理措施,MAC則是又把DAC的安全性,更進一步的強化,使用者具備的操作權限會如下圖一般被嚴格的限制住.(也更適用於Multi-User的執行環境).
結語
當前一版Android釋放出Multi-User的概念時,當下會覺得現在Android被Root的裝置滿普遍的,一旦又支援Multi-User,那使用者資料被竊取,或是資安問題肯定會比現在更多.但從這版Android 4.3來看,確實Android的安全性已經不同於我們過去的認知,也更具備保護Multi-User環境下的使用者資料能力.
希望本文能對大家有所幫助,也感謝有這樣的Open Source環境,讓我們可以持續的長知識,又拓展自己的技術視野….Orz

























0 意見:

張貼留言