本文主要講述 FreeBSD 5.0 操作系統(tǒng)中新增的重要安全機制,即強制訪問控制機制( MAC )的使用與源代碼分析,主要包括強制訪問控制框架及多級安全( MLS )策略兩部分內(nèi)容。這一部分講述要將 MAC 框架與 MLS 策略用起來,應(yīng)該做的一些工作,以及如何有效使用它們的問題。
?
強制訪問控制(英文縮寫 MAC )是實現(xiàn)操作系統(tǒng)安全的一個重要的方法,現(xiàn)在幾乎所有的安全操作系統(tǒng)都采用強制訪問控制作為其核心安全機制之一。強制訪問控制是對操作系統(tǒng)的各種客體(如文件、 socket 、系統(tǒng) FIFO 、 SCD 、 IPC 等)進行細粒度的訪問控制,即當(dāng)用戶或用戶程序訪問系統(tǒng)的某個客體時,強制訪問控制機制對這種訪問的安全性進行檢查。與自主訪問控制不同,強制訪問控制對用戶及用戶程序的行為進行限制,從而達到更高的安全級別。
?
強制訪問控制是一種機制,它對用戶與用戶程序?qū)腕w的訪問進行檢查,但什么樣的訪問是安全的呢?這就需要引入安全策略的概念。安全策略可以認為是一組檢查條件,它為每次訪問的主體(用戶或用戶程序)和被訪問的客體(如文件等)定義一個安全標(biāo)記,再根據(jù)主體和客體的安全標(biāo)記來決定這次訪問是否安全。目前已經(jīng)開發(fā)出多種安全策略,其中 MLS 用得最多。 MLS 是多級安全的意思,它最早用于軍事領(lǐng)域。它的基本思想是定義一些安全級,如從低到高分普通、機密、絕密等安全級,要求高安全級別的信息不能泄露給低安全級別的用戶,這樣就要求低安全級的主體不能讀高安全級的客體,同時高安全級的主體不能寫低安全級的客體。詳情請參見有關(guān)資料。
?
與 Linux 一樣, FreeBSD 系統(tǒng)是開放源代碼的操作系統(tǒng),而且 FreeBSD 的結(jié)構(gòu)清晰,安全性好,所以使用也很廣泛。從 5.0RC2 版開始, FreeBSD 內(nèi)核開始引入強制訪問控制機制。它在內(nèi)核中實現(xiàn)了一個靈活通用 MAC 框架,這個框架對 FreeBSD 內(nèi)核中幾乎所有的核心對象進行了訪問控制,并且這個框架設(shè)計合理、接口簡潔,使得我們可以很方便地開發(fā)各種安全策略模塊并將之掛接到系統(tǒng),從而按我們自己的策略對系統(tǒng)進行安全控制。另外,系統(tǒng)還提供了包括 MLS 策略模塊在內(nèi)的多個策略模塊供我們選用。
?
本文從使用與源代碼的分析這兩方面詳細講述 FreeBSD 系統(tǒng)中的強制訪問控制機制,內(nèi)容主要包括 MAC 框架和 MLS 策略,相信會對對此部分內(nèi)容感興趣的朋友有所啟發(fā)。
1 FreeBSD 5.0中強制訪問控制機制的使用
FreeBSD 5.0 RC2 版本發(fā)布時,內(nèi)核源代碼中已經(jīng)包含了 MAC 框架和一些 MAC 策略模塊(如 MLS 策略模塊、用于開發(fā)及實驗的 MAC_NONE 策略模塊、完整性模塊 MAC_BIBA 等),但是這個版本的內(nèi)核并沒有正式對 MAC 提供支持,所以缺省情況下,在編譯內(nèi)核的時候沒有把實現(xiàn) MAC 框架的代碼編譯進去。另外,我們將以 MLS 策略為例,說明怎樣利用 MAC 框架加載策略模塊。為了讓 MLS 策略真正實用,還需要配置系統(tǒng)的擴展文件屬性等,我們將對之進行一定的介紹。最后我們將介紹如通過控制臺命令以及在程序中如何使用系統(tǒng)調(diào)用接口對文件或進程的 MAC 標(biāo)記進行操作。
1.1 重新編譯內(nèi)核
如上所述,由于 FreeBSD 5.0 RC2 版中的 MAC 框架還處于開發(fā)階段,所以缺省情況下,內(nèi)核二進制代碼中并沒有包括對 MAC 框架的支持。要使內(nèi)核支持 MAC 框架,必須配置并重新編譯內(nèi)核,具體方法如下。
?
到 /usr/src/sys/i386/conf 下,把 GENERIC 文件復(fù)制成另一個文件如 yxd_kernel (不要改動 GENERIC 文件),然后在 yxd_kernel 文件中找到 makeoptions 這個部分,仿照已有的格式,添加一行(詳細信息請參見 "FreeBSD Developers' Handbook" 中的 "TrustedBSD MAC FrameWork" 章節(jié)):
?
options MAC
?
這個選項將打開 MAC 編譯開關(guān),這樣編譯時將把相應(yīng)的 MAC 框架代碼編譯進內(nèi)核。
?
另外,為了支持文件及目錄的 MAC 標(biāo)記的存儲,必須讓內(nèi)核支持擴展文件系統(tǒng)(缺省情況下也不支持)。要達到這個目的,必須在 yxd_kernel 中加入如下兩個編譯選項:
?
mac_mls_load = "YES"
?
值得注意的一點是,當(dāng)我們修改并重新編譯了 mac_mls.ko 這個模塊后,必須把它從 /usr/src/sys/modules/mac_mls 目錄拷貝到 /boot/kernel 目錄,因為系統(tǒng)啟動的時候是從 /boot/kernel 目錄尋找模塊的。
1.3 配置擴展文件系統(tǒng)
?
當(dāng)我們做完 1.1 和 1.2 兩步后, MLS 模塊就已經(jīng)在系統(tǒng)中起作用了,我們可以使用 "getfmac 文件 / 目錄名 " 來得到文件或目錄的 MAC 標(biāo)記(形如 " 文件 / 目錄名 : mls/low" ,詳細的介紹請參閱 1.4 節(jié)),但此時的標(biāo)記是一種偽標(biāo)記,也就是說,這個標(biāo)記是 MLS 策略給每個文件的缺省標(biāo)記,且這個標(biāo)記在關(guān)閉系統(tǒng)的時候并沒有被存儲。但是按照我們的需要,我們希望每個文件或目錄的 MAC 標(biāo)記應(yīng)該有 " 非易逝性 " 的標(biāo)記,也就是說我們希望這個標(biāo)記與文件一樣被存儲在磁盤上。這就需要引入擴展文件系統(tǒng),使得每個文件或目錄的 MAC 標(biāo)記存儲在對應(yīng)文件或目錄的擴展屬性中。為了便于理解,下面對 FreeBSD 中的擴展文件系統(tǒng)進行一點簡要的介紹。
?
簡單地說,擴展文件系統(tǒng)是對現(xiàn)有文件系統(tǒng)的一種擴充。擴展屬性( EA , Extended Attribute )是相對于傳統(tǒng)文件系統(tǒng)的 inode 節(jié)點中已存儲的文件或目錄的標(biāo)準(zhǔn)屬性而言的,它可以為 inode 節(jié)點中存儲的文件或目錄增加額外的信息,這些信息再由系統(tǒng)根據(jù) inode 結(jié)點訪問到。每個文件系統(tǒng)的擴展屬性( EA )是一組( name , value )對。一個 inode 節(jié)點(文件或目錄)可能定義了某種屬性,也可能沒有定義。如果 inode 節(jié)點定義了某個屬性,則它可能包含 0 個,也可能包含多個字節(jié)的這種屬性的數(shù)據(jù)。這與一般 shell 的環(huán)境變量類似。這樣,擴展屬性機制就為 TrustedBSD 的各種安全特征( ACL 、 MAC 和能力等),提供了存儲訪問安全信息的簡單方法。一些非安全應(yīng)用也可以根據(jù)需要創(chuàng)建擴展屬性,例如文件的校驗和、密鑰等。擴展屬性可以動態(tài)地增加新的擴展屬性而不必改變文件系統(tǒng)在磁盤上的存儲格式。
?
如果使用的是 MLS 策略,那么返回的 MAC 標(biāo)記為 mls/[single_mac]([mac_range]) ,其中 mls 為策略名,后面用 "/" 與標(biāo)記數(shù)據(jù)隔開。 [single_mac] 為單一的 MAC 標(biāo)記,可能為 "low" 或 "high" 或 "equal" 。 [mac_range] 為一個 MAC 標(biāo)記范圍,往往主體(進程)有一個范圍。一個 MAC 標(biāo)記的例子為: mls/low(low-high) 。
?
在應(yīng)用程序中,可以使用的系統(tǒng)調(diào)用請參見 /usr/src/sys/sys/mac.h 文件中 #ifndef _KERNEL 這個塊中提供的函數(shù)原型,值得注意的是, man page 中的有些接口參數(shù)及返回值類型有誤,請以 mac.h 文件中的類型為準(zhǔn)。
?
下面是幾個最常用的函數(shù)的使用方法:
-
mac_get_proc , mac_get_file 的用法:
struct mac myMac;
char ss[60] = "mls";
myMac.m_string = ss;
myMac.m_buflen = 60;
mac_get_proc(&myMac);
mac_get_file("/tmp/test",&myMac);
-
mac_set_proc , mac_set_file 的用法:
struct mac myMac;
myMac.m_string = "mls/high";
myMac.m_buflen = strlen(myMac.m_string);
mac_set_proc(&myMac);
mac_set_file("/tmp/test",&myMac);
1.5 小結(jié)
由于 FreeBSD 5.0RC2 版才剛剛開始非正式地支持 MAC ,所以針對普通用戶而言,要將其真正用起來,要做的工作還比較多比較煩瑣的。對于 MLS 策略而言,還有很多值得完善的地方,比如現(xiàn)有的 MLS 策略不支持對用戶設(shè)置 MAC 標(biāo)記,主體對客體訪問的時候限制過多,還有 MLS 不支持可信進程等等,都是下一個版本需要完善的。
?
在使用上,從我個人的使用經(jīng)驗來看,比較不好用。當(dāng)然,這個問題不能全怪系統(tǒng), MLS 策略導(dǎo)致易用性降低已經(jīng)是不爭的事實,相信經(jīng)過一段時間的開發(fā),最終會給我們一個滿意的答案。
?
但是瑕不掩玉,撇開 MLS ,單看 MAC 框架,應(yīng)該說是設(shè)計得很完美的:良好的結(jié)構(gòu)、清晰的邏輯、非常簡潔的接口,這些優(yōu)點應(yīng)該來說可以給每一個對它有興趣的人一個大大的驚喜。即使是 MLS 策略,由于其作為一個 KLD 模塊來實現(xiàn),所以十分便于我們對它進行修改和擴充,相信經(jīng)過一段時間, MLS 模塊亦會成為我們的驚喜。如果大家有興趣了解 MAC 框架及 MLS 策略的實現(xiàn),請接著往下閱讀。
?
本文主要講述 FreeBSD 5.0 操作系統(tǒng)中新增的重要安全機制,即強制訪問控制機制( MAC )的使用與源代碼分析,主要包括強制訪問控制框架及多級安全( MLS )策略兩部分內(nèi)容。這一部分較系統(tǒng)地對 MAC 框架及 MLS 策略的源代碼進行分析。
2 MAC框架與MLS策略源代碼分析
與本文相關(guān)的源代碼文件主要有兩個,即 /usr/src/sys/kern/kern_mac.c 和 /usr/src/sys/security/mac_mls/mac_mls.c 。另外還有一些頭文件如 mac.h 、 mac_policy.h 等。
2.1 MAC框架整體結(jié)構(gòu)
?
下面是 MAC 框架的示意性結(jié)構(gòu)圖,當(dāng)用戶控制臺或用戶程序通過系統(tǒng)調(diào)用對內(nèi)核對象進行訪問的時候,由于內(nèi)核代碼中相應(yīng)的位置插入了 MAC 框架的檢查函數(shù),于是內(nèi)核就會調(diào)用 MAC 框架的相應(yīng)檢查函數(shù)來做安全性檢查。 MAC 框架會依次調(diào)用每個掛接在 MAC 框架上的安全策略,以決定訪問是否安全。另外,其它可能涉及到安全問題的系統(tǒng)事件,如初始化各種安全標(biāo)記、初始化各種內(nèi)核對象等,也會通知 MAC 框架,由它做出相應(yīng)的處理。
?
從圖中我們也可以看到,安全策略作為一個獨立的 KLD 模塊,可以獨立于內(nèi)核進行編譯,再在使用的時候掛接到 MAC 框架上。要判斷一次訪問是否安全, MAC 框架會調(diào)用所有的安全策略,只有當(dāng)所有的安全策略均表示同意, MAC 框架才會授權(quán)這次訪問。
2.2 安全標(biāo)記
?
安全標(biāo)記是由 MAC 框架和各個安全策略定義的一組數(shù)據(jù),用于描述主體或客體的安全信息,安全標(biāo)記與內(nèi)核描述主客體的其它數(shù)據(jù)一起存儲在內(nèi)核中。要實現(xiàn)強制訪問控制,首先必須為主客體定義安全標(biāo)記。不同的策略由于判斷的依據(jù)不一樣,可能定義的標(biāo)記也不相同。作為 MAC 框架,當(dāng)安全策略向它注冊的時候,它必須把該策略使用的安全標(biāo)記附加到各個內(nèi)核對象上去,這樣當(dāng)需要調(diào)用該策略做安全性檢查的時候,才能為策略提供它們自己定義和理解的安全標(biāo)記。我們先給出 MAC 框架與 MLS 策略定義的安全標(biāo)記,再對之作進一步的解釋。
?
MAC 框架中安全標(biāo)記的定義是這樣的:
?
struct label {
int l_flags;
union {
void *l_ptr;
long l_long;
} l_perpolicy[MAC_MAX_POLICIES];
};
?
其中 l_flags 是一個標(biāo)志,被 MAC 框架用來判斷是否初始化了整個標(biāo)記數(shù)據(jù)結(jié)構(gòu)。 l_perpolicy 數(shù)組為每個策略定義了一個聯(lián)合,這樣當(dāng)策略向 MAC 框架注冊時,它們既可以用一個 long 類的整數(shù)作為它們自己的安全標(biāo)記,也可以使用聯(lián)合中的指針指向一個它們自己定義的標(biāo)記數(shù)據(jù)結(jié)構(gòu)。 MLS 策略選擇了后者。
?
MLS 策略定義的安全標(biāo)記是這們的:
?
struct mac_mls_element {
u_short mme_type;
u_short mme_level;
u_char mme_compartments[MAC_MLS_MAX_COMPARTMENTS >> 3];
};
struct mac_mls {
int mm_flags;
struct mac_mls_element mm_single;
struct mac_mls_element mm_rangelow, mm_rangehigh;
};
?
在 mac_mls 結(jié)構(gòu)中,定義了一個單一標(biāo)記( mm_single )和一個標(biāo)記范圍( mm_rangelow , mm_rangehigh ),主客體既可以使用單一標(biāo)記來標(biāo)識單一安全級,也可以使用標(biāo)記范圍來標(biāo)識一個安全級范圍,還可以同時使用二者。如第 1 章中我們使用 getfmac 得到的輸出 "mls/high" 表明該文件使用的是值為 "high" 的單一安全標(biāo)記。再比如我們使用 getpmac 得到的輸出 "mls/low(low-high)" 表明進程同時使用了單一標(biāo)記和標(biāo)記范圍。至于究竟使用的是哪種標(biāo)記,由 mm_flags 標(biāo)識。
?
mac_mls_element 定義一個標(biāo)記,它定義的標(biāo)記功能很強大,既支持安全類型( mme_type 變量,值為 LOW 、 HIGH 、 EQUAL 和 UNDEFINE ),也支持多達 256 個級別的安全級(當(dāng) mme_type 的值為 LEVEL 時, mme_level 變量有效,由它定義安全級),同時還使用 mme_compartments 數(shù)組支持域( field ),后續(xù)章節(jié)將具體講述 MLS 策略是怎樣使用它所定義的標(biāo)記的。
?
當(dāng)用戶試圖打開一個文件時,內(nèi)核就會試圖打開一個 vnode ,在打開之前會調(diào)用這個函數(shù),用于檢查主體是否有權(quán)限打開這個 vnode 。 MAC_CHECK 宏定義如下:
?
#define MAC_CHECK(check, args...) do {
struct mac_policy_conf *mpc;
error = 0;
MAC_POLICY_LIST_BUSY();
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
if (mpc->mpc_ops->mpo_ ## check != NULL)
error = error_select(
mpc->mpc_ops->mpo_ ## check (args),
error);
}
MAC_POLICY_LIST_UNBUSY();
} while (0)
?
我們可以看到,代碼中使用 LIST_FOREACH 宏來遍歷安全策略鏈表中的每個策略,然后調(diào)用其在 mpc_ops 中注冊的檢查函數(shù) mpo_##check 。 mac_policy_ops 這個結(jié)構(gòu)中定義了很多事件處理函數(shù),進行細粒度的訪問控制,限于篇幅,在此不一一列出。這些函數(shù)共分四類:第一類是策略本身的初始化和銷毀函數(shù);第二類是對安全標(biāo)記的操作函數(shù),包括各種內(nèi)核對象的安全標(biāo)記的初始化與銷毀函數(shù),以及獲取與設(shè)置安全標(biāo)記的接口函數(shù);第三類是對文件系統(tǒng)、網(wǎng)絡(luò)系統(tǒng)及進程對象的標(biāo)記進行操作的事件處理函數(shù);第四類是檢查對各個內(nèi)核對象的訪問是否安全的檢查函數(shù)。詳見 mac_policy.h 。
?
2.4 安全策略的注冊
?
分析 MLS 策略,我們可以發(fā)現(xiàn),安全策略向 MAC 框架注冊是一件很簡單的事情。 mac_mls.c 文件中花了大量篇幅定義了所有的事件處理函數(shù),如前所述,這些函數(shù)是安全策略的核心,用于判斷訪問的安全性等。定義完這些函數(shù)后,在源代碼的最后,把這些函數(shù)的地址填入 mac_policy_ops 結(jié)構(gòu)中,再用一個 MAC_POLICY_SET 宏把 mac_policy_ops 結(jié)構(gòu)掛接到上面提到的 mac_policy_list 鏈表中去就可以了,如下:
?
MAC_POLICY_SET(&mac_mls_ops, trustedbsd_mac_mls, "TrustedBSD MAC/MLS", MPC_LOADTIME_FLAG_NOTLATE, &mac_mls_slot);
?
mac_policy_modevent 函數(shù)的核心代碼如下:
?
case MOD_LOAD:
if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
mac_late) {
printf("mac_policy_modevent: can't load %s policy "
"after booting", mpc->mpc_name);
error = EBUSY;
break;
}
error = mac_policy_register(mpc);
break;
case MOD_UNLOAD:
/* Don't unregister the module if it was never registered. */
if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) != 0)
error = mac_policy_unregister(mpc);
else
error = 0;
break;
?
當(dāng)模塊被 LOAD 的時候,會調(diào)用 mac_policy_register 函數(shù),它首先檢查該模塊是否已注冊,如果沒有,就會執(zhí)行下面的代碼: LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
其中 mpc 為我們上面提到的 mac_policy_conf 結(jié)構(gòu)的地址,這樣到此為止,就把 MLS 策略添加到 MAC 框架的策略列表中去了。
?
2.5 MLS策略源代碼分析
?
根據(jù) MLS 策略,高安全級別的主體不能寫低安全級別的客體,而低安全級別的主體則不能讀高安全級別的客體,只有主客體的安全級別相同,才能既讀又寫。 MLS 定義了三種標(biāo)記比較函數(shù):
?
mac_mls_dominate_single(a,b) :用于檢查 a 的單一標(biāo)記的安全級是否高于 b 的單一標(biāo)記的安全級。這個函數(shù)主要用于對內(nèi)核變量的讀、寫、查詢等事件進行安全性檢查。
?
我們只解釋一下最后一個 case ,即當(dāng) a 、 b 的類型均為 MAC_MLS_TYPE_LEVEL 時,也就是它們都使用一個數(shù)( 0 到 254 )標(biāo)識它們的安全級時,判斷是如何進行的。首先:
#define MAC_MLS_BIT_TEST(b, w) ((w)[(((b) - 1) >> 3)] & (1 << (((b) - 1) & 7)))
?
我們可以看到,在比較二者安全級之前,對它們的 mme_compartments 進行了位測試。 mme_compartments 是一個 256bit 的數(shù)據(jù)(由 uchar[32] 數(shù)組定義),每個 bit 都可以設(shè)置為 1 來表示該對象屬于某一個安全域,當(dāng)然也可以設(shè)置多個 bit 表示這個對象屬于多個安全域。 MLS 要求如果 a 可以訪問 b 的話, b 所屬的安全域必須要是 a 的子集,否則訪問被拒絕。對 mme_compartments 進行測試的目的也即是要判斷 b 中設(shè)置了 1 的那些 bit 在 a 中有否設(shè)置。
?
2.6 對MAC框架及MLS策略的擴充
?
最后我們對 MAC 框架作一點改進。前面提過, MAC 框架目前并不支持對用戶的安全級進行設(shè)置,也沒有提供存儲用戶安全級信息的地方,我們想對之做改進,以使其更實用。我們改進的思想是,攔截系統(tǒng)的 setuid 系統(tǒng)調(diào)用,在系統(tǒng)作 setuid 的時候(用戶登錄、運行 su 命令等),讀入用戶安全級別信息并作相應(yīng)設(shè)置。我們做了如下工作:
-
在 mac_policy.h 文件中的 mac_policy_ops 結(jié)構(gòu)中增加一個新函數(shù) mpo_get_cred_from_file() ,其參數(shù)和返回值與 mpo_create_cred() 完全一樣。
-
在 mac_mls.c 文件中增加一個新函數(shù) mac_mls_get_cred_from_file() ,其參數(shù)和返回值與 mac_mls_create_cred() 完全一樣。在這個函數(shù)里,增加在內(nèi)核中讀寫用戶安全級配置文件的語句,從而把用戶的安全級在這里讀到標(biāo)記中。然后在對 mac_policy_ops 結(jié)構(gòu)的設(shè)置語句中,增加一條語句: .mpo_get_cred_from_file = mac_mls_get_cred_from_file 。
-
在 kern_prot.c 文件中的 setuid() 函數(shù)里 crcopy() 函數(shù)替換為我們自己的 mac_crcopy() 函數(shù),并在調(diào)用這個函數(shù)之前加一條語句: newcred->cr_uid = uid; 。
?
mac_crcopy() 函數(shù)的代碼如下:
?
void mac_crcopy(struct ucred *dest,struct ucred *src)
{
uid_t uid = dest->cr_uid;
KASSERT(crshared(dest) == 0,("crcopy of shared ucred"));
bcopy(&src->cr_startcopy,&dest->cr_startcopy,
(unsigned)((caddr_t)&src->cr_endcopy -
(caddr_t)&src->cr_startcopy));
uihold(dest->cr_uidinfo);
uihold(dest->cr_ruidinfo);
if(jailed(dest))
prison_hold(dest->cr_prison);
#ifdef MAC
dest->cr_uid = uid;
mac_get_cred(src,dest);
dest->cr_uid = src->cr_uid;
#endif
}
修改相應(yīng)的頭文件,并重新編譯內(nèi)核。
2.7 小結(jié)
?
上面分析了 MAC 框架與 MLS 策略的主要內(nèi)容,限于篇幅,我們只給出主要邏輯,如果您想要了解更為詳細的技術(shù)細節(jié),請閱讀其源代碼或聯(lián)系我。另外, MAC 框架和 MLS 策略還用到了一些很重要的技術(shù),如系統(tǒng)控制( sysctl )機制、鎖等,我們也沒有提到,如有興趣的讀者可以繼續(xù)鉆研。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
