概述:
云原生(Cloud Native)是一套技術(shù)體系和方法論。云原生(Cloud Native)由2個(gè)詞組成,云(Cloud)和原生(Native)。云(Cloud)表示應(yīng)用程序位于云中,而不是傳統(tǒng)的數(shù)據(jù)中心;原生(Native)表示應(yīng)用程序從設(shè)計(jì)之初即考慮到云的環(huán)境,原生為云而設(shè)計(jì),在云上以優(yōu)質(zhì)狀態(tài)運(yùn)行,充分利用和發(fā)揮云平臺(tái)的彈性和分布式優(yōu)勢(shì)。
云原生的代表技術(shù)包括容器、服務(wù)網(wǎng)格(Service Mesh)、微服務(wù)(Micro Service)、不可變基礎(chǔ)設(shè)施和聲明式API。
更多對(duì)于云原生的介紹請(qǐng)參考文末鏈接1。
云原生安全技術(shù)沙盤(Security View)
筆者將“云原生安全”抽象成如上圖所示的技術(shù)沙盤。自底向上看,底層從硬件安全(可信環(huán)境)到宿主機(jī)安全 。將容器編排技術(shù)(Kubernetes等)看作云上的“操作系統(tǒng)”,它負(fù)責(zé)自動(dòng)化部署、擴(kuò)縮容、管理應(yīng)用等。在它之上由微服務(wù)、Service Mesh、容器技術(shù)(Docker等)、容器鏡像(倉(cāng)庫(kù))組成。它們之間相輔相成,以這些技術(shù)為基礎(chǔ)構(gòu)建云原生安全。
再對(duì)容器安全做一層抽象,又可以看作構(gòu)建時(shí)安全(Build)、部署時(shí)安全(Deployment)、運(yùn)行時(shí)安全(Runtime)。
在美團(tuán)內(nèi)部鏡像安全由容器鏡像分析平臺(tái)保障。它以規(guī)則引擎的形式運(yùn)營(yíng)監(jiān)管容器鏡像,默認(rèn)規(guī)則支持對(duì)鏡像中dockerfile、可疑文件、敏感權(quán)限、敏感端口、基礎(chǔ)軟件漏洞、業(yè)務(wù)軟件漏洞以及CIS和NIST的最佳實(shí)踐做檢查,并提供風(fēng)險(xiǎn)趨勢(shì),同時(shí)它確保部分構(gòu)建時(shí)安全。
容器在云原生架構(gòu)下是由容器編排技術(shù)(例如:Kubernetes)負(fù)責(zé)部署的,部署安全同時(shí)也與上文提及的容器編排安全有交集。
運(yùn)行安全管控交由HIDS負(fù)責(zé)(可以參考,分布式HIDS集群架構(gòu)設(shè)計(jì),文末鏈接2)。本文所討論的范疇也屬于運(yùn)行安全之一,主要解決以容器逃逸為模型構(gòu)建的風(fēng)險(xiǎn)(在本文中,若無(wú)特殊說(shuō)明,容器指代Docker)。
對(duì)于安全實(shí)施準(zhǔn)則,我們將其分為三個(gè)階段:
1.攻擊前:裁剪攻擊面,減少對(duì)外暴露的攻擊面(本文涉及的場(chǎng)景關(guān)鍵詞:隔離)。
2.攻擊時(shí):降低攻擊成功率(本文涉及的場(chǎng)景關(guān)鍵詞:加固)。
3.攻擊后:減少攻擊成功后攻擊者所能獲取的有價(jià)值的信息、數(shù)據(jù)以及增加留后門難度等。
近些年,數(shù)據(jù)中心的基礎(chǔ)架構(gòu)逐漸從傳統(tǒng)的虛擬化(例如:KVM+Qemu架構(gòu))轉(zhuǎn)向容器化(Kubernetes+Docker架構(gòu)),但逃逸始終都是企業(yè)要在這2種架構(gòu)下所需要面對(duì)的最嚴(yán)峻的安全問(wèn)題,同時(shí)它也是容器風(fēng)險(xiǎn)中最具代表性的安全問(wèn)題。筆者將以容器逃逸為切入點(diǎn),從攻擊者角度(容器逃逸)到防御者角度(緩解容器逃逸)去闡述容器安全實(shí)踐,從而緩解容器風(fēng)險(xiǎn)。
容器風(fēng)險(xiǎn)
容器提供了將應(yīng)用程序的代碼、配置、依賴項(xiàng)打包到單個(gè)對(duì)象的標(biāo)準(zhǔn)方法。容器建立在2項(xiàng)關(guān)鍵技術(shù)之上,Linux Namespace和Linux Cgroups。
Namespace創(chuàng)建一個(gè)近乎隔離的用戶空間并為應(yīng)用程序提供系統(tǒng)資源(文件系統(tǒng)、網(wǎng)絡(luò)棧、進(jìn)程和用戶ID)。Cgroup強(qiáng)制限制硬件資源,如CPU、內(nèi)存、設(shè)備和網(wǎng)絡(luò)。
容器和VM不同之處在于,VM模擬硬件系統(tǒng),每個(gè)VM都可以在獨(dú)立環(huán)境中運(yùn)行OS。管理程序模擬CPU、內(nèi)存、存儲(chǔ)、網(wǎng)絡(luò)資源等,這些硬件可由多個(gè)VM共享多次。
容器攻擊面(Container Attack Surface)
容器一共有7個(gè)攻擊面:Linux Kernel、Namespace/Cgroups/Aufs、Seccomp-bpf、Libs、Language VM、User Code、Container(Docker) engine。
筆者以容器逃逸為風(fēng)險(xiǎn)模型,提煉出3個(gè)攻擊面:
1. Linux內(nèi)核漏洞
2. 容器自身
3. 不安全部署(配置)
一、Linux內(nèi)核漏洞
容器的內(nèi)核與宿主內(nèi)核共享,使用Namespace與Cgroups這兩項(xiàng)技術(shù)使容器內(nèi)的資源與宿主機(jī)隔離,所以Linux內(nèi)核產(chǎn)生的漏洞能導(dǎo)致容器逃逸。
內(nèi)核提權(quán)VS容器逃逸——通用Linux內(nèi)核提權(quán)方法論
信息收集
收集一切對(duì)寫(xiě)exploit有幫助的信息。如:內(nèi)核版本,需要確定攻擊的內(nèi)核是什么版本?這個(gè)內(nèi)核版本開(kāi)啟了哪些加固配置?還需知道在寫(xiě) shellcode 的時(shí)候會(huì)調(diào)用哪些內(nèi)核函數(shù)?這時(shí)候就需要查詢內(nèi)核符號(hào)表,得到函數(shù)地址。還可從內(nèi)核中得到一些對(duì)編寫(xiě)利用有幫助的地址信息、結(jié)構(gòu)信息等等。
觸發(fā)階段
觸發(fā)相關(guān)漏洞,控制RIP,劫持內(nèi)核代碼路徑,簡(jiǎn)而言之獲取在內(nèi)核中任意執(zhí)行代碼的能力。
布置shellcode
在編寫(xiě)內(nèi)核exploit代碼的時(shí)候需要找到一塊內(nèi)存來(lái)存放我們的shellcode 。這塊內(nèi)存至少得滿足兩個(gè)條件:
第一:在觸發(fā)漏洞的時(shí)候我們要劫持的代碼路徑,必須保證代碼路徑可以到達(dá)存放shellcode的內(nèi)存。
第二:這塊內(nèi)存是可以被執(zhí)行的,換句話說(shuō),存放 shellcode 的這塊內(nèi)存具有可執(zhí)行權(quán)限。
執(zhí)行階段
第一:獲取高于當(dāng)前用戶的權(quán)限,一般我們都是直接獲取root 權(quán)限,畢竟它是 Linux 中最高權(quán)限,也就是執(zhí)行我們的shellcode。
第二:保證內(nèi)核穩(wěn)定,不能因?yàn)槲覀冃枰釞?quán)而破壞原來(lái)內(nèi)核的代碼路徑、內(nèi)核結(jié)構(gòu)、內(nèi)核數(shù)據(jù)等等,使內(nèi)核崩潰了,這樣的話,即使得到 root 權(quán)限也沒(méi)什么太大的意義。
簡(jiǎn)而言之,收集對(duì)編寫(xiě)exploit有幫助的信息,然后觸發(fā)漏洞去執(zhí)行特權(quán)代碼,達(dá)到提權(quán)的效果。
容器逃逸簡(jiǎn)易模型(Container Escape Model)
容器逃逸和內(nèi)核提權(quán)只有細(xì)微的差別,需要突破namespace的限制。將高權(quán)限的namespace賦到exploit進(jìn)程的task_struct中。這部分的詳細(xì)技術(shù)細(xì)節(jié)不在本文討論范圍內(nèi),筆者會(huì)抽空再寫(xiě)一篇關(guān)于容器逃逸的技術(shù)文章,詳細(xì)介紹相關(guān)技術(shù)細(xì)節(jié)。
經(jīng)典的DirtyCoW
筆者以Dirty CoW漏洞來(lái)說(shuō)明Linux漏洞導(dǎo)致的容器逃逸。漏洞雖老,奈何太過(guò)經(jīng)典。寫(xiě)到這,筆者不禁想問(wèn):多年過(guò)去,目前國(guó)內(nèi)外各大廠,Dirty Cow漏洞的存量機(jī)器修復(fù)率是多少?
在Linux內(nèi)核的內(nèi)存子系統(tǒng)處理私有只讀內(nèi)存映射的寫(xiě)時(shí)復(fù)制(Copy-on-Write,CoW)機(jī)制的方式中發(fā)現(xiàn)了一個(gè)競(jìng)爭(zhēng)沖突。一個(gè)沒(méi)有特權(quán)的本地用戶可能會(huì)利用此漏洞獲得對(duì)其他情況下只讀內(nèi)存映射的寫(xiě)訪問(wèn)權(quán)限,從而增加他們?cè)谙到y(tǒng)上的特權(quán),這就是知名的Dirty CoW漏洞。
Dirty CoW漏洞的逃逸這里的實(shí)現(xiàn)思路和上述的思路不太一樣,采取Overwrite vDSO技術(shù)。
vDSO(Virtual Dynamic Shared Object)是內(nèi)核為了減少內(nèi)核與用戶空間頻繁切換,提高系統(tǒng)調(diào)用效率而設(shè)計(jì)的機(jī)制。它同時(shí)映射在內(nèi)核空間以及每一個(gè)進(jìn)程的虛擬內(nèi)存中,包括那些以root權(quán)限運(yùn)行的進(jìn)程。通過(guò)調(diào)用那些不需要上下文切換(context switching)的系統(tǒng)調(diào)用可以加快這一步驟(定位vDSO)。vDSO在用戶空間(userspace)映射為R/X,而在內(nèi)核空間(kernelspace)則為R/W。這允許我們?cè)趦?nèi)核空間修改它,接著在用戶空間執(zhí)行。又因?yàn)槿萜髋c宿主機(jī)內(nèi)核共享,所以可以直接使用這項(xiàng)技術(shù)逃逸容器。
利用步驟如下:
1.獲取vDSO地址,在新版的glibc中可以直接調(diào)用getauxval()函數(shù)獲取。
2.通過(guò)vDSO地址找到clock_gettime()函數(shù)地址,檢查是否可以hijack。
3.創(chuàng)建監(jiān)聽(tīng)socket。
4.觸發(fā)漏洞,Dirty CoW是由于內(nèi)核內(nèi)存管理系統(tǒng)實(shí)現(xiàn)CoW時(shí)產(chǎn)生的漏洞。通過(guò)條件競(jìng)爭(zhēng),把握好在恰當(dāng)?shù)臅r(shí)機(jī),利用CoW的特性可以將文件的read-only映射為write。子進(jìn)程不停的檢查是否成功寫(xiě)入。父進(jìn)程創(chuàng)建二個(gè)線程,ptrace_thread線程向vDSO寫(xiě)入shellcode。
madvise_thread線程釋放vDSO映射空間,影響ptrace_thread線程CoW的過(guò)程,產(chǎn)生條件競(jìng)爭(zhēng),當(dāng)條件觸發(fā)就能寫(xiě)入成功。
5.執(zhí)行shellcode,等待從宿主機(jī)返回root shell,成功后恢復(fù)vDSO原始數(shù)據(jù)。
二、容器自身
我們先簡(jiǎn)單的看一下Docker的架構(gòu)圖:
Docker架構(gòu)圖(圖片來(lái)自網(wǎng)絡(luò)如有侵權(quán)聯(lián)系刪除)
Docker本身由docker(docker client)和dockerd(docker daemon)組成。但從Docker 1.11開(kāi)始,Docker不再是簡(jiǎn)單的通過(guò)docker dameon來(lái)啟動(dòng),而是集成許多組件,包括containerd、runc等等。
Docker client是docker的客戶端程序,用于將用戶請(qǐng)求發(fā)送給dockerd。dockerd實(shí)際調(diào)用的是containerd的api接口,containerd是dockerd和runc之間的一個(gè)中間交流組件,主要負(fù)責(zé)容器運(yùn)行、鏡像管理等。containerd向上為dockerd提供了gRPC接口,使得dockerd屏蔽下面的結(jié)構(gòu)變化,確保原有接口向下兼容;向下,通過(guò)containerd-shim與runc結(jié)合創(chuàng)建及運(yùn)行容器。更多的相關(guān)內(nèi)容,請(qǐng)參考文末鏈接4、5、6。了解清楚這些之后,我們就可以結(jié)合自身的安全經(jīng)驗(yàn),從這些組件相互間的通信方式、依賴關(guān)系等尋找能導(dǎo)致逃逸的漏洞。
下面我們以docker中的runc組件所產(chǎn)生的漏洞來(lái)說(shuō)明因容器自身的漏洞導(dǎo)致的逃逸。
CVE-2019-5736:runc – container breakout vulnerability
runc在使用文件系統(tǒng)描述符時(shí)存在漏洞,該漏洞可導(dǎo)致特權(quán)容器被利用,造成容器逃逸以及訪問(wèn)宿主機(jī)文件系統(tǒng);攻擊者也可以使用惡意鏡像,或修改運(yùn)行中的容器內(nèi)的配置來(lái)利用此漏洞。
攻擊方式1:(該途徑需要特權(quán)容器) 運(yùn)行中的容器被入侵,系統(tǒng)文件被惡意篡改 ==> 宿主機(jī)運(yùn)行 docker exec命令 在該容器中創(chuàng)建新進(jìn)程 ==> 宿主機(jī)runc被替換為惡意程序 ==> 宿主機(jī)執(zhí)行 docker run/exec 命令時(shí)觸發(fā)執(zhí)行惡意程序;
攻擊方式2:(該途徑無(wú)需特權(quán)容器) docker run 命令啟動(dòng)了被惡意修改的鏡像 ==> 宿主機(jī) runc 被替換為惡意程序 ==> 宿主機(jī)運(yùn)行 docker run/exec 命令時(shí)觸發(fā)執(zhí)行惡意程序;
當(dāng)runc在容器內(nèi)執(zhí)行新的程序時(shí),攻擊者可以欺騙它執(zhí)行惡意程序。通過(guò)使用自定義二進(jìn)制文件替換容器內(nèi)的目標(biāo)二進(jìn)制文件來(lái)實(shí)現(xiàn)指回runc二進(jìn)制文件。
例如,如果目標(biāo)二進(jìn)制文件是/bin/bash,這可以用指定解釋器的可執(zhí)行腳本替換#!/proc/self/exe;因此,在容器內(nèi)執(zhí)行/bin/bash,/proc/self/exe的目標(biāo)將被執(zhí)行,將目標(biāo)指向runc二進(jìn)制文件。
然后攻擊者可以繼續(xù)寫(xiě)入/proc/self/exe目標(biāo),嘗試覆蓋主機(jī)上的runc二進(jìn)制文件。這里需要使用O_PATH flag打開(kāi)/proc/self/exe文件描述符,然后以O(shè)_WRONLY flag 通過(guò)/proc/self/fd/
三、不安全部署(配置)
在實(shí)際中,經(jīng)常會(huì)遇到這種狀況:不同的業(yè)務(wù)會(huì)根據(jù)自身業(yè)務(wù)需求有自己的一套配置,而這套配置并未得到有效的管控審計(jì),使得內(nèi)部環(huán)境變的復(fù)雜多樣,無(wú)形之中又增加了許多風(fēng)險(xiǎn)點(diǎn)。譬如,最常見(jiàn)的:
1.特權(quán)容器或者以root權(quán)限運(yùn)行容器。
2.不合理的Capability配置(權(quán)限過(guò)大的Capability)。
面對(duì)特權(quán)容器,在容器內(nèi)簡(jiǎn)單的執(zhí)行一下命令就可以輕松的在宿主機(jī)上留下后門。
在美團(tuán)內(nèi)部已經(jīng)有效的收斂了特權(quán)容器問(wèn)題。
這部分業(yè)界已經(jīng)給出了最佳實(shí)踐,從宿主機(jī)配置、Dockerd配置、容器鏡像、Dockerfile、容器運(yùn)行時(shí)等方面保障安全,更多細(xì)節(jié)請(qǐng)參考文末鏈接10,同時(shí)Docker官方已經(jīng)將其實(shí)現(xiàn)成自動(dòng)化工具(見(jiàn)文末鏈接11)。
安全實(shí)踐
為解決上述部分所闡述的容器逃逸問(wèn)題,下文將重點(diǎn)從隔離(安全容器)與加固(安全內(nèi)核)兩個(gè)角度去討論。
一、安全容器
安全容器的技術(shù)本質(zhì)其實(shí)就是隔離。gVisor和Kata Container是比較具有代表性的實(shí)現(xiàn)方式,當(dāng)然目前學(xué)術(shù)界有在探索基于Intel SGX的安全容器。
簡(jiǎn)單的說(shuō),gVisor是在用戶態(tài)和內(nèi)核態(tài)之間抽象出一層,封裝成API,有點(diǎn)像user-mode kernel,以此實(shí)現(xiàn)隔離;Kata Container是采用輕量級(jí)虛擬機(jī)隔離,與傳統(tǒng)的VM比較類似,但是它實(shí)現(xiàn)了無(wú)縫集成當(dāng)前的Kubernetes加Docker架構(gòu)。我們接著來(lái)看gVisor與Kata Container的異同。
Case 1: gVisor
gVisor是用Golang編寫(xiě)的用戶態(tài)內(nèi)核,或者說(shuō)是沙箱技術(shù),它主要實(shí)現(xiàn)了大部分的system call。它運(yùn)行在應(yīng)用程序和內(nèi)核之間,為它們提供隔離。gVisor被使用在Google云計(jì)算平臺(tái)的App Engine、Cloud Functions和Cloud ML中。gVisor運(yùn)行時(shí),是由多個(gè)沙箱組成,這些沙箱進(jìn)程共同覆蓋了一個(gè)或多個(gè)容器。通過(guò)攔截從應(yīng)用程序到主機(jī)內(nèi)核的所有系統(tǒng)調(diào)用并使用用戶空間中的Sentry處理它們,gVisor充當(dāng)guest kernel的角色,且無(wú)需通過(guò)虛擬化硬件轉(zhuǎn)換,可以將他看做vmm與guest kernel的**,或是seccomp的增強(qiáng)版。
gVisor架構(gòu)圖(圖片來(lái)自網(wǎng)絡(luò)如有侵權(quán)聯(lián)系刪除)
Case 2: Kata Container
Kata Container的Container Runtime 是用 hypervisor ,是用 hardware virtualization 實(shí)現(xiàn)的,如同虛擬機(jī)。所以每一個(gè)像這樣的 Kata Container 的 Pod,都是一個(gè)輕量級(jí)虛擬機(jī),它是擁有完整的 Linux 內(nèi)核。所以 Kata Container 與 VM 一樣能提供強(qiáng)隔離性,但由于它的優(yōu)化和性能設(shè)計(jì),它擁有與容器相媲美的敏捷性。
Kata Container 架構(gòu)圖(圖片來(lái)自網(wǎng)絡(luò)如有侵權(quán)聯(lián)系刪除)
Kata Container在主機(jī)上有一個(gè)kata-runtime來(lái)啟動(dòng)和配置新容器。對(duì)于Kata VM中的每個(gè)容器,主機(jī)上都有相應(yīng)的Kata Shim。Kata Shim接收來(lái)自客戶端的API請(qǐng)求(例如:docker或kubectl),并通過(guò)VSock將請(qǐng)求轉(zhuǎn)發(fā)給Kata VM內(nèi)的代理。Kata容器進(jìn)一步優(yōu)化以減少VM啟動(dòng)時(shí)間。使用QEMU的輕量級(jí)版本NEMU,刪除了約80%的設(shè)備和包。VM-Templating創(chuàng)建運(yùn)行Kata VM實(shí)例的克隆,并與其他新創(chuàng)建的Kata VM共享,這樣減少了啟動(dòng)時(shí)間和Guest VM內(nèi)存消耗。Hotplug功能允許VM使用最少的資源(例如:CPU,內(nèi)存,virtio塊)進(jìn)行引導(dǎo),并在以后請(qǐng)求時(shí)添加其他資源。
gVisor VS Kata Container
在二者之間筆者更愿選擇gVisor,因?yàn)間Visor設(shè)計(jì)上相比與Kata Container更加“輕”量級(jí),但gVisor的性能問(wèn)題始終是一道暫時(shí)無(wú)法逾越的檻。綜合二者的優(yōu)劣,Kata Container目前來(lái)看會(huì)更適合企業(yè)內(nèi)部。總體而言,安全容器技術(shù)還需做諸多探索,以解決不同企業(yè)內(nèi)部基礎(chǔ)架構(gòu)上面臨的挑戰(zhàn)。
二、安全內(nèi)核
眾所周知,Android由于不同廠商都維護(hù)著自己的Android版本,又因?yàn)锳ndroid 內(nèi)核態(tài)代碼來(lái)自于Linux kernel upstrem,當(dāng)一個(gè)漏洞產(chǎn)生在upstrem內(nèi)核,安全補(bǔ)丁推送到Google,再?gòu)腉oogle下發(fā)到各大廠商,最終到終端用戶。Android 生態(tài)的碎片化,補(bǔ)丁周期非常之長(zhǎng),使得終端用戶的安全,在這過(guò)程中始終處于“空窗期”。把目光重新聚焦在Linux上,它也同樣存在類似的問(wèn)題。
1.內(nèi)核面臨的問(wèn)題
漏洞生命周期(The Vulnerability Life Cycle)
內(nèi)核補(bǔ)丁
當(dāng)一個(gè)安全漏洞被披露,通常是由漏洞發(fā)現(xiàn)者通過(guò)Redhat、OpenSuse、Debian等社區(qū)反饋或直接提交至上游相關(guān)子系統(tǒng)maintainer。在企業(yè)內(nèi)部面臨多個(gè)不同內(nèi)核大版本、內(nèi)核定制化,針對(duì)不同版本從上游代碼backport相關(guān)補(bǔ)丁及制作相關(guān)熱補(bǔ)丁,定制內(nèi)核還需對(duì)補(bǔ)丁進(jìn)行二次開(kāi)發(fā),再升級(jí)生產(chǎn)環(huán)境內(nèi)核或hotfix內(nèi)核。不僅修復(fù)周期過(guò)長(zhǎng),而且推進(jìn)修復(fù)過(guò)程人員溝通也存在成本,拉長(zhǎng)了漏洞危險(xiǎn)期。在危險(xiǎn)期間對(duì)于漏洞是毫無(wú)防護(hù)能力的。
內(nèi)核版本碎片化
內(nèi)核版本碎片化在任意具備一定規(guī)模的公司都是無(wú)法避免的問(wèn)題。隨著技術(shù)日新月異,不斷迭代,基礎(chǔ)架構(gòu)上的技術(shù)棧需要較新版本的內(nèi)核功能去支持,久而久之產(chǎn)生內(nèi)核版本碎片化。碎片化問(wèn)題的存在,使得在安全補(bǔ)丁的推送方面,遭遇了很大的挑戰(zhàn)。本身補(bǔ)丁還需要做針對(duì)性的適配,包括不同版本的內(nèi)核,并進(jìn)行測(cè)試驗(yàn)證,碎片化使得維護(hù)成本也十分高昂。最重要的是,由于維護(hù)工作量大,必然拉長(zhǎng)了測(cè)試補(bǔ)丁的時(shí)間線。也就是說(shuō),暴露在攻擊者面前的危險(xiǎn)期變得更長(zhǎng),被攻擊的可能性大大增加。
內(nèi)核版本定制化
同樣,因不同公司的基礎(chǔ)架構(gòu)不同、需求不同,導(dǎo)致的定制化內(nèi)核問(wèn)題。對(duì)于定制化內(nèi)核,無(wú)法簡(jiǎn)單的通過(guò)從上游內(nèi)核合并補(bǔ)丁,還需對(duì)補(bǔ)丁做一些本地化來(lái)適配定制化內(nèi)核。這又拉長(zhǎng)了危險(xiǎn)期。
解決之道
我們使用安全特性去針對(duì)某一類漏洞或是針對(duì)某一類利用方式做防御與檢測(cè)。比如SLAB_FREELIST_HARDENED,針對(duì)double free類型漏洞做實(shí)時(shí)檢測(cè),且防御overwrite freelist鏈表,性能損耗僅0.07%(參考upstrem內(nèi)核源碼,commit id: 2482ddec)。
當(dāng)完成所有全部安全特性,漏洞在被反饋之前和漏洞補(bǔ)丁被及時(shí)推送至生產(chǎn)環(huán)境前,無(wú)需關(guān)心漏洞的細(xì)節(jié),就能防御。當(dāng)然,安全補(bǔ)丁該打還是得打的,這里我們主要解決在安全補(bǔ)丁最終落在生產(chǎn)環(huán)境過(guò)程中“空窗期”對(duì)于漏洞與利用毫無(wú)防御能力的問(wèn)題,同時(shí)也可以對(duì)0day有一定的檢測(cè)及防御能力。
實(shí)施策略
1. 已經(jīng)合并進(jìn)Linux主線版本的安全特性,如果公司的內(nèi)核支持該特性,選擇開(kāi)啟配置,對(duì)開(kāi)啟前后內(nèi)核做性能測(cè)試,分析安全特性原理,行業(yè)數(shù)據(jù),給出real world攻擊案例(自己寫(xiě)exploit去證明),將報(bào)告結(jié)論反饋給內(nèi)核團(tuán)隊(duì),內(nèi)核團(tuán)隊(duì)再做評(píng)估,結(jié)合安全團(tuán)隊(duì)與內(nèi)核團(tuán)隊(duì)雙方意見(jiàn),最終評(píng)估落地。
2. 已經(jīng)合并進(jìn)Linux主線版本但未被合并進(jìn)Redhat的安全特性,可選擇從Linux內(nèi)核主線版本中移植,這點(diǎn)上代碼質(zhì)量上得到了保障,同時(shí)社區(qū)也做了性能測(cè)試,將其合并到公司的內(nèi)核再做復(fù)測(cè)。
3. 未被合并進(jìn)Linux內(nèi)核主線版本,從Grsecurity/PaX中做移植,在Grsecurity/PaX的諸多安全特性中,評(píng)估選擇,選取代碼改動(dòng)少的,收益高的安全特性優(yōu)先移植,比如改動(dòng)較少的內(nèi)核代碼又能有效解決某一類的漏洞,再打個(gè)比方,dirty cow的全量修復(fù)可能需要花費(fèi)1-2年,加了某個(gè)安全特性,即使未修復(fù)也能防御。
內(nèi)核后話
最后,分享一下筆者眼中較為理想中的狀況。當(dāng)然,我們得根據(jù)實(shí)際情況“因地制宜”,在不同階段做出不同的取舍與選擇。
將內(nèi)核團(tuán)隊(duì)看成社區(qū),我們向他們提交代碼,如同Linux內(nèi)核社區(qū)有RFC(Request for Comment)、patch review等,無(wú)爭(zhēng)議后合并進(jìn)公司內(nèi)核。
先挑選實(shí)用的安全特性且代碼量少的,去移植,去實(shí)現(xiàn),并落地。代碼量少意味著,對(duì)內(nèi)核代碼改動(dòng)少,出問(wèn)題的可能性越小,穩(wěn)定性越高,性能損耗越低。
一年完成幾個(gè)安全特性,不需要多,1~2個(gè)即可,對(duì)于內(nèi)核態(tài)的加固,慎重慎重再慎重,譬如國(guó)外G家公司數(shù)據(jù)中心的內(nèi)核發(fā)版前大概需要6~7個(gè)月時(shí)間做性能、穩(wěn)定性測(cè)試。
需要做到加固某個(gè)安全特性后,使用0day或Nday去驗(yàn)證防御效果,且基于該內(nèi)核跑業(yè)務(wù)是穩(wěn)定,性能損耗在可接受范圍之內(nèi)或者可控。每個(gè)安全特性需要技術(shù)評(píng)審。為保障代碼質(zhì)量的問(wèn)題,找實(shí)際的高吞吐以及高并發(fā)低延遲的服務(wù)器小范圍灰度測(cè)試,無(wú)爭(zhēng)議后,推送給內(nèi)核團(tuán)隊(duì)。
最后,還可以通過(guò)將安全特性的代碼直接提交給Linux內(nèi)核社區(qū),如果代碼有不足的地方也可以和社區(qū)協(xié)同解決,合并進(jìn)Linux內(nèi)核主線代碼,從而側(cè)面推動(dòng)落地。