1. 制定smack規則
“Zygote”進程由init進程建立,它負責建立系統服務進程“systemserver”、“radio”進程和APP進程。其中“radio”進程的uid是1001,它能夠實現打電話和發簡訊的功能,“systemserver”進程uid是1000,它負責建立系統服務元件,通訊錄進程uid是10000,它能夠訪問通訊錄資料庫,uid大於等於10000的進程都屬於Android應用程式進程。
為了實現對“radio”和通訊錄進程的存取控制,本課題使用“libsmack”庫中“setsmack”函數將“radio”進程的安全性標籤設定為“1001”。將通訊錄進程的安全性標籤設定為“10000”。需要強調的是,上面兩個uid是被Android系統寫入程式碼,不隨Android版本改變而改變。假設某個進程的uid是XXX,當“Zygote”進程“fork”此進程時,該進程首先是一個特權進程,因此它可以使用“setsmack”函數將自身安全性標籤設定為“XXX”,並裝載Smack安全性原則。本研究課題在經過大量實驗基礎上總結得出下面規則:
(1)確保一個進程正常運行:“XXX _ rwxa”&& “_ XXX rwxa”
由於Smack被編譯到Android系統中,因此,在預設情況下,Android系統所有檔案和進程的安全性標籤都是“_”,一個被重新設定過安全性標籤的進程要想正常運行,必然要和安全性標籤是“_”進程進行通訊或者讀寫某些安全性標籤是“_”的檔案。
(2)禁止一個進程正常運行:“XXX _ ----”
(3)禁止一個進程發生簡訊:“XXX 1001 ----”
任何一個進程要想傳送簡訊必須在“Binder Driver”中與“radio”進程通訊,因此,只要該進程不能發送訊息給“radio”進程,那麼該進程就不能完成傳送簡訊的功能。
(4)容許一個進程發生簡訊:“XXX 1001 rwxa”&& “1001 XXX rwxa”
(5)容許通訊錄進程正常訪問通訊錄:“10000 contact rwxa”
“/data/data/com.android.providers.contacts/database/contact2.db”存放通訊錄裡的資訊,為此,在“dalvik_system_Zygote.cpp”中使用“libsmack”庫中的函數“setxattr”將這個資料庫檔案的安全性標籤設定為“contact”。為了使通訊錄進程能夠正常訪問通訊錄,必須保證通訊錄進程對此資料庫檔案有讀、寫、執行和“盲寫”的許可權。
(6)容許一個進程正常訪問通訊錄:
“XXX 10000 rwxa” && “10000 XXX rwxa”
在具備規則5的前提下,一個進程要想訪問通訊錄,它必須與通訊錄進程在“Binder Driver”中通訊,為此必須容許這兩個進程能夠互相發送訊息給對方。
(7)禁止一個進程訪問通訊錄和通話記錄:“XXX 10000 ----”
(8)容許一個進程訪問簡訊記錄:“XXX sms rwxa”
“/data/data/com.android.providers.telephony/database/mmssms.db”是簡訊和多媒體訊息的資訊資料庫檔案,同樣也是使用函數“setxattr”將這個資料庫檔案設定安全性標籤“sms”,任何一個進程要想查看簡訊,必須能夠訪問此資料庫檔案。
(9)禁止一個進程訪問簡訊記錄:“XXX sms ----”
(10)容許一個進程訪問SD卡檔案:“XXX sdcard rwxa”
Smack是利用虛擬檔案系統VFS的“inode”和“super_block”為檔案系統設定安全性標籤,因此不管SD卡採用什麼樣的檔案系統,SD卡上的檔案均可以被設定安全性標籤“sdcard”。
(11) 禁止一個進程訪問SD卡檔案:“XXX sdcard ----”
(12) 禁止Android系統打電話和發簡訊:“1001 _ ----”
這裡的“_”代表了radio守護進程,它是由“init”進程建立的,它的可執行檔是“/system/bin/radio”,Android系統打電話和發簡訊功能最終是要靠它來驅動硬體實現。“1001”進程就是在“Binder Driver”中與radio守護進程進行通訊,從而完成了打電話和傳送簡訊的功能。如果想要禁止Android系統中所有進程打電話和發簡訊,只要“1001”進程不能發訊息給radio守護進程即可。
(13) 容許Android系統正常打電話和發簡訊:
“1001 _ rwxa”&& “_ 1001 rwxa”
2. 裝載smack策略
由於Zygote每“fork”子進程,該子進程首先是一個特權進程,如下所示:
dvmDumpLoaderStats("zygote");
pid = fork();
if (pid == 0) {
int err;
... ...
}
因此,可以在定義變數err之後加入控制碼。這裡,本課題設計了如下四個函數:
#ifdef HAVE_SMACK
/*
* set process self smack label and smack rules
* return -1 if the database can not be opencorrectly
* return 2 if the uerId can not be found inthe smack rules table
* else return 1 if the smack label and rulecan be set correctly
* else return 0 if the smack label can not beset correctly
* */
static int setsmacklabelrules(intuserId);
setsmacklabelrules是根據uerId值到安全性原則資料庫中,尋找相關的smack規則。
/*
* set sdcard label to the files on sdcard interms of encryptedfiles table
* return -1 if the database can not be opencorrectly
* return 1 if files xattr can be set correctlyon the sdcard
* else return 0
* */
#ifdef HAVE_SMACK
static intsetlabelTosdcardfiles();
setlabelTosfcardfiles是從sdcard檔案清單中尋找檔案的絕對路徑,並調用setxattr為檔案設定安全性標籤,在此,設定簡訊資料庫和通訊錄資料庫安全性標籤的代碼也放入其中,如下所示:
if(setxattr("/data/data/com.android.providers.telephony/databases/mmssms.db",SMACKATTR, "sms", strlen("sms") + 1, 0) < 0) {
xattr = false;
}
if(setxattr("/data/data/com.android.providers.contacts/databases/contacts2.db",SMACKATTR, "contact", strlen("contact") + 1, 0) < 0) {
xattr = false;
}
為了能夠進一步控制打電話和發簡訊行為,本課題設計了InitializeOutgoingcallwhitelist函數將白名單資料表內容匯入白名單設定檔中,如下所示:
#ifdef HAVE_SMACK
/*
* to initialize outgoingcallwhitelist
* return 1 if the outgoingcallwhitelist fileis initialized correctly
* else return 0
* */
static int InitializeOutgoingcallwhitelist();
又因為radio所屬的組是user,所以它不能讀取Zygote建立的白名單設定檔,所以必須使用chmod修改白名單設定檔的訪問模式。