快速SECCOMP入門
為什么不能只使用LSM?
為什么不能只使用seccomp?
結(jié)論
假設(shè)你已經(jīng)了解了LSM內(nèi)核安全模塊,也知道如何使用它們加固系統(tǒng)的安全。但是,你還知道了另一種工具seccomp(Linux安全計(jì)算)。你可能非常想知道,LSM和Seccomp有什么區(qū)別?為什么不能將Seccomp設(shè)計(jì)為L(zhǎng)SM模塊?什么時(shí)候使用Seccomp?接下來(lái),且聽(tīng)我娓娓道來(lái)。
Secomp和LSM都可以讓內(nèi)核限制進(jìn)程與系統(tǒng)的交互,但卻有大大的不同。也就是說(shuō),Seccomp限制進(jìn)程發(fā)起的系統(tǒng)調(diào)用,而LSM控制對(duì)內(nèi)核對(duì)象的訪問(wèn)。
快速SECCOMP入門
Andrea Arcangeli在2004年首次提案seccomp,限制用戶進(jìn)程進(jìn)入內(nèi)核模式的系統(tǒng)調(diào)用,只允許read、write、exit和sigreturn。Andrea將其用于CPUShare項(xiàng)目,其允許人們出租自己未使用的CPU資源,但這需要限制不可信代碼的行為。出售者肯定不想購(gòu)買者能夠輕易的通過(guò)fork bomb發(fā)起拒絕服務(wù)攻擊(DoS)。起初,Andrea使用一個(gè)運(yùn)行時(shí)受限的解釋器運(yùn)行不可信代碼,但是為了效率和靈活性,他專門設(shè)計(jì)了CPUShare用來(lái)直接運(yùn)行二進(jìn)制代碼。CPUShare需要限制這種不可信的二進(jìn)制代碼,以便只能讀取輸入,運(yùn)算,然后輸出結(jié)果。除此之外,不允許任何操作。有了Seccomp,管理進(jìn)程能夠加載不可信的共享對(duì)象文件,打開(kāi)文件進(jìn)行輸入和輸出,并進(jìn)入seccomp模式,然后,才調(diào)用不可信共享對(duì)象的入口點(diǎn),運(yùn)行二進(jìn)制代碼。之后,受限的進(jìn)程不能打開(kāi)任何新文件,更改目錄,創(chuàng)建新進(jìn)程,生成線程,執(zhí)行新程序。
seccomp的這種strict模式帶來(lái)了很強(qiáng)的隔離性,但是限制太多而無(wú)法更普遍的使用。那么就需要一種方法為進(jìn)程提供策略給內(nèi)核決定允許那些系統(tǒng)調(diào)用。2012年,內(nèi)核開(kāi)發(fā)者合并了seccomp filter mode,從而允許進(jìn)程決定它們自己的系統(tǒng)調(diào)用過(guò)濾策略。
Seccomp filter mode允許進(jìn)程通過(guò)prctl系統(tǒng)調(diào)用安裝BPF字節(jié)碼。一旦安裝,此BPF程序阻止調(diào)用進(jìn)程,或任何子進(jìn)程發(fā)起的系統(tǒng)調(diào)用。
讓我們來(lái)看一下Linux源碼中seccomp測(cè)試代碼片段,如下所示。該段代碼展示了BPF過(guò)濾器會(huì)殺死發(fā)起getpid系統(tǒng)調(diào)用的進(jìn)程:
?
struct sock_filter filter[] = { BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 0, 1), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog prog = { .len = (unsigned short)ARRAY_SIZE(filter), .filter = filter, }; ... ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
?
上面的代碼創(chuàng)建了一個(gè)seccomp過(guò)濾器。一旦將該過(guò)濾器添加到某個(gè)任務(wù)中,在對(duì)任務(wù)進(jìn)程進(jìn)行追蹤之后,但是在通過(guò)系統(tǒng)調(diào)用表分配之前,會(huì)先運(yùn)行該過(guò)濾器,從而限制某些系統(tǒng)調(diào)用。值得注意的是seccomp_data數(shù)據(jù)結(jié)構(gòu),如下所示:
?
/** * struct seccomp_data - BPF程序執(zhí)行的格式 * @nr: 系統(tǒng)調(diào)用號(hào) * @arch: 系統(tǒng)調(diào)用的約定,跟架構(gòu)相關(guān),相關(guān)定義位于 *文件中,以AUDIT_ARCH_*為前綴 * @instruction_pointer:指令指針 * @args: 6個(gè)系統(tǒng)調(diào)用參數(shù),64位值,不管是什么架構(gòu) */ struct seccomp_data { int nr; __u32 arch; __u64 instruction_pointer; __u64 args[6]; };
?
目前,BPF沒(méi)有提供解引用指針,或檢查用戶空間傳遞進(jìn)來(lái)的數(shù)據(jù)結(jié)構(gòu)。只有直接拷貝到seccomp_data結(jié)構(gòu)中的參數(shù)才可用。因此,BPF過(guò)濾器不能通過(guò)用戶空間傳遞的字符串確定系統(tǒng)調(diào)用。
為什么不能只使用LSM?
LSM和seccomp都是增加系統(tǒng)安全的工具。LSM實(shí)現(xiàn)的是強(qiáng)制訪問(wèn)控制(MAC),保護(hù)的內(nèi)核對(duì)象是:文件,inode,task_struct,IPC數(shù)據(jù)結(jié)構(gòu)。LSM會(huì)將安全屬性插入到這些對(duì)象中,根據(jù)先前加載的策略進(jìn)行檢查。具有特權(quán)的安全管理員(通常是root)負(fù)責(zé)加載和管理這些策略。非特權(quán)用戶不能改變這個(gè)策略。
相反,seccomp允許非特權(quán)進(jìn)程限制自身。與非特權(quán)進(jìn)程放棄自身能力(capability)一樣,seccomp允許非特權(quán)進(jìn)程放棄某些系統(tǒng)調(diào)用的能力。比如說(shuō),cat命令,可以open和read命令行中指定的文件,將它們的內(nèi)容輸出到標(biāo)準(zhǔn)輸出中。除了stdout(2)和stderr(3)之外,它不需要寫任何文件描述符。因此,cat開(kāi)發(fā)者可以使用seccomp過(guò)濾器,當(dāng)cat想要寫任何除了2和3之外的文件描述符時(shí),就會(huì)殺死它。
但是,通過(guò)LSM實(shí)現(xiàn)相同的功能就會(huì)非常復(fù)雜,因?yàn)檫M(jìn)程的標(biāo)準(zhǔn)輸出可能會(huì)重定向到不同內(nèi)核對(duì)象(設(shè)備,文件,管道),而LSM本身又沒(méi)有提供將這些對(duì)象映射到文件描述符的方法。另外,一個(gè)問(wèn)題就是存在多個(gè)LSM實(shí)現(xiàn):SELinux,?AppArmor,?Tomoyo,?SMACK,它們都有自己的管理策略的機(jī)制,這些機(jī)制要么要為每一個(gè)LSM模塊生成策略,要么限制用戶只能使用一種。
而且,還可以編寫自己的LSM模塊,當(dāng)然,還需要將其編譯進(jìn)內(nèi)核,并設(shè)計(jì)一種方法表示你這種特殊的策略,這既耗時(shí)又脆弱。在這一點(diǎn)上,seccomp是有優(yōu)勢(shì)的,如果內(nèi)核配置正確,不管系統(tǒng)如何配置其LSM模塊,都可以使用它。從二進(jìn)制的角度來(lái)說(shuō),
最后,因?yàn)閮?nèi)核會(huì)在系統(tǒng)調(diào)用之前檢查seccomp過(guò)濾器,也就是減少了攻擊者的攻擊面。LSM一般hook在系統(tǒng)調(diào)用底層的內(nèi)核對(duì)象上,不會(huì)像seccomp那樣減少攻擊面。具體的來(lái)說(shuō),內(nèi)核在將系統(tǒng)調(diào)用的參數(shù)映射到內(nèi)核對(duì)象之后運(yùn)行這些hook,本身這段代碼可能就包含缺陷。重申一遍:seccomp減少攻擊面。
為什么不能只使用seccomp?
seccomp無(wú)法對(duì)LSM采用的相同策略進(jìn)行建模。例如,你不能編寫seccomp過(guò)濾器阻止用戶進(jìn)程只打開(kāi)文件系統(tǒng)中某個(gè)位置的文件,比如,/etc/password。因?yàn)閟eccomp過(guò)濾器不能解引用指針,所以它就不能比較用戶傳遞給open系統(tǒng)調(diào)用的路徑參數(shù)(像AppArmor那樣),也不能檢查通過(guò)文件安全屬性檢查inode節(jié)點(diǎn)(像SELinux那樣)。
另外,也沒(méi)有機(jī)制移除或修改已經(jīng)附加到進(jìn)程的過(guò)濾器。你只能給進(jìn)程添加新的過(guò)濾器,而且新過(guò)濾器的作用也不能與已經(jīng)存在的過(guò)濾器相反。因此,想要從全局給系統(tǒng)創(chuàng)建一組過(guò)濾器是非常困難的。最接近的方法是使用systemd的系統(tǒng)調(diào)用過(guò)濾器或者在容器中使用seccomp過(guò)濾器(比如docker)
即使使用systemd的系統(tǒng)調(diào)用過(guò)濾器和docker seccomp策略,seccomp過(guò)濾器的管理最好還是由應(yīng)用程序開(kāi)發(fā)者實(shí)現(xiàn),而不是系統(tǒng)管理員。因?yàn)閼?yīng)用開(kāi)發(fā)者比系統(tǒng)管理員更清楚他們的應(yīng)用程序需要哪些系統(tǒng)調(diào)用。另外,在應(yīng)用程序改變時(shí),開(kāi)發(fā)者更清楚在哪里更新這些過(guò)濾器。
結(jié)論
LSM和seccomp都提供了限制進(jìn)程與系統(tǒng)交互的機(jī)制。但它們不是不直接保護(hù)你的程序免受攻擊的工具,而是阻止攻擊者利用某個(gè)程序的漏洞進(jìn)而攻擊系統(tǒng)其它部分的工具。LSM實(shí)現(xiàn)的MAC強(qiáng)制訪問(wèn)控制策略是你實(shí)現(xiàn)系統(tǒng)全局細(xì)粒度安全控制策略的工具,而seccomp過(guò)濾器是限制非特權(quán)進(jìn)程進(jìn)行某些系統(tǒng)調(diào)用的工具,同時(shí)還是常見(jiàn)的進(jìn)程沙箱技術(shù)(如linux container)的重要組件。
審核編輯:湯梓紅
評(píng)論