摘要:在年月底時,我寫了一篇文章發(fā)布之際。為何有存在前面已經(jīng)基本介紹了相關(guān)背景,并且也基本明確了就是在正式發(fā)布之前的最后一個版本,那為什么會出現(xiàn)呢我們首先要介紹今年的一個提權(quán)漏洞。
在 18 年 11 月底時,我寫了一篇文章 《runc 1.0-rc6 發(fā)布之際》 。如果你還不了解 runc 是什么,以及如何使用它,請參考我那篇文章。本文中,不再對其概念和用法等進(jìn)行說明。
在 runc 1.0-rc6 發(fā)布之時,給版本的別名為 "For Real This Time",當(dāng)時我們原定計(jì)劃是發(fā)布 1.0 的,但是作為基礎(chǔ)依賴軟件,我們認(rèn)為當(dāng)時的版本還有幾個問題:
不夠規(guī)范;
發(fā)布周期不明確;
為了給相關(guān)的 runtime 足夠的時間進(jìn)行修正/升級,以及規(guī)范版本生命周期等,最終決定了發(fā)布 runc 1.0-rc6。
為何有 runc 1.0-rc7 存在前面已經(jīng)基本介紹了相關(guān)背景,并且也基本明確了 rc6 就是在 1.0 正式發(fā)布之前的最后一個版本,那 rc7 為什么會出現(xiàn)呢?
CVE-2019-5736我們首先要介紹今年 runc 的一個提權(quán)漏洞 CVE-2019-5736 。
2019 年 2 月 11 日在 oss-security 郵件組正式批露該漏洞,攻擊者可以利用惡意容器覆蓋主機(jī)上的 runc 文件,從而達(dá)到攻擊的目的;(具體的攻擊方式此處略過),注意不要輕易使用來源不可信的鏡像創(chuàng)建容器便可有效避免被攻擊的可能。
簡單補(bǔ)充下可能被攻擊的方式:
運(yùn)行惡意的 Docker 鏡像
在主機(jī)上執(zhí)行 docker exec 進(jìn)入容器內(nèi)
關(guān)于容器安全或者容器的運(yùn)行機(jī)制,其實(shí)涉及的點(diǎn)很多,我在去年的一次線上分享 《基于 GitLab 的 CI 實(shí)踐》 有提到過 Linux Security Modules(LSM)等相關(guān)的內(nèi)容,對容器安全感興趣的朋友可以對 LSM 多了解下。
不過本文主要看的是 runc 如何修復(fù)該漏洞的,以及后續(xù)產(chǎn)生的影響。
修復(fù)方式// 對 memfd_create 系統(tǒng)調(diào)用做了個封裝 省略部分代碼 #if !defined(SYS_memfd_create) && defined(__NR_memfd_create) # define SYS_memfd_create __NR_memfd_create #endif #ifdef SYS_memfd_create # define HAVE_MEMFD_CREATE # ifndef MFD_CLOEXEC # define MFD_CLOEXEC 0x0001U # define MFD_ALLOW_SEALING 0x0002U # endif int memfd_create(const char *name, unsigned int flags) { return syscall(SYS_memfd_create, name, flags); } // 一個簡單的只讀緩存區(qū) static char *read_file(char *path, size_t *length) { int fd; char buf[4096], *copy = NULL; if (!length) return NULL; fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) return NULL; *length = 0; for (;;) { int n; n = read(fd, buf, sizeof(buf)); if (n < 0) goto error; if (!n) break; copy = must_realloc(copy, (*length + n) * sizeof(*copy)); memcpy(copy + *length, buf, n); *length += n; } close(fd); return copy; error: close(fd); free(copy); return NULL; } // 將復(fù)制后的 fd 重賦值/執(zhí)行 static int clone_binary(void) { int binfd, memfd; ssize_t sent = 0; #ifdef HAVE_MEMFD_CREATE memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING); #else memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711); #endif if (memfd < 0) return -ENOTRECOVERABLE; binfd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC); if (binfd < 0) goto error; sent = sendfile(memfd, binfd, NULL, RUNC_SENDFILE_MAX); close(binfd); if (sent < 0) goto error; #ifdef HAVE_MEMFD_CREATE int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS); if (err < 0) goto error; #else int newfd; char *fdpath = NULL; if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0) goto error; newfd = open(fdpath, O_RDONLY | O_CLOEXEC); free(fdpath); if (newfd < 0) goto error; close(memfd); memfd = newfd; #endif return memfd; error: close(memfd); return -EIO; } int ensure_cloned_binary(void) { int execfd; char **argv = NULL, **envp = NULL; int cloned = is_self_cloned(); if (cloned > 0 || cloned == -ENOTRECOVERABLE) return cloned; if (fetchve(&argv, &envp) < 0) return -EINVAL; execfd = clone_binary(); if (execfd < 0) return -EIO; fexecve(execfd, argv, envp); return -ENOEXEC; }
省略掉了部分代碼,完整代碼可直接參考 runc 代碼倉庫 。
整個的修復(fù)邏輯我在上面的代碼中加了備注,總結(jié)來講其實(shí)就是:
創(chuàng)建了一個只存在于內(nèi)存中的 memfd ;
將原本的 runc 拷貝至這個 memfd ;
在進(jìn)入 namespace 前,通過這個 memfd 重新執(zhí)行 runc ; (這是為了確保之后即使被攻擊/替換也操作的還是內(nèi)存中的這個只讀的 runc)
經(jīng)過以上的操作,就基本修復(fù)了 CVE-2019-5736 。
影響 內(nèi)核相關(guān)在上面講完修復(fù)方式后,我們來看下會產(chǎn)生哪些影響。
涉及到了系統(tǒng)調(diào)用 memfd_create(2) 和 fcntl(2)
增加了系統(tǒng)調(diào)用,那自然就要看內(nèi)核是否支持了。實(shí)際上,這些函數(shù)是在 2015 年 2 月(距這次修復(fù)整整 4 年,也挺有趣)被加入到 Linux 3.17 內(nèi)核中的。
換句話說就是 凡是在此內(nèi)核版本之前的系統(tǒng),均無法正常使用該功能,對我們的影響就是,如果你在此版本內(nèi)核之前的機(jī)器上使用了包含上述修復(fù)代碼的 runc 或構(gòu)建在其之上的 containerd、 Docker 等都無法正常工作 。
以 Docker 舉例:安裝 docker-ce-18.09.2 或 docker-ce-18.06.3 可避免受 CVE-2019-5736 影響,但如果內(nèi)核版本較低,在運(yùn)行容器時可能會有如下情況出現(xiàn): (不同版本/內(nèi)核可能出現(xiàn)其他情況)
[tao@moelove ~]# docker run --rm my-registry/os/debian echo Hello docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:293: copying bootstrap data to pipe caused "write init-p: broken pipe"": unknown.
解決辦法
升級內(nèi)核;這是最直接的辦法,而且使用一個新版本的內(nèi)核也能省去很多不必要的麻煩:)
rancher 提供了一個 runc-cve 的 patch,可兼容部分 3.x 內(nèi)核的系統(tǒng)(我沒有測試過)
如果你不升級 runc/containerd/Docker 等版本的話,那建議你 1. 將 runc 可執(zhí)行程序放到只讀文件系統(tǒng)上,可避免被覆蓋;2. 啟動容器時,啟用 SELinux; 3. 在容器內(nèi)使用低權(quán)限用戶或者采用映射的方式,但保證用戶對主機(jī)上的 runc 程序無寫權(quán)限。
注意:
memfd_create 等相關(guān)系統(tǒng)調(diào)用,也被加入到了 Debian 3.16 和 Ubuntu 14.04 updates 中,當(dāng)然也被反向移植到了 CentOS 7.3 內(nèi)核 3.10.0-514 版本之后。 (Red Hat 給 CentOS 7.x 的 3.10 內(nèi)核上反向移植了很多特性)
內(nèi)存相關(guān)從上面的說明中,也很容易可以看到, 內(nèi)存的使用上會有所增加,不過之后已做了修復(fù)。這里不再進(jìn)行展開。
其他偶爾可能觸發(fā)一些內(nèi)核 bug 之類的(總之建議升級 :)
等待 rc8 發(fā)布上面已經(jīng)介紹了 1.0-rc7 出現(xiàn)的主要原因 CVE-2019-5736;當(dāng)然這個版本中也有一些新特性和一些 bugfix 不過不是本文的主要內(nèi)容,不再贅述。
值得一提的是這次的版本命名:runc 1.0-rc7 -- "The Eleventh Hour" 后面這個別名其實(shí)來自于一部英劇,感興趣也可以去看看。
至于下個版本是不是會是 1.0 正式版呢?目前來看應(yīng)該不是,有極大可能會發(fā)布 runc 1.0-rc8 做一些 bugfix,讓我們拭目以待。
可以通過下面二維碼訂閱我的文章公眾號【MoeLove】
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/27745.html
摘要:在年月底時,我寫了一篇文章發(fā)布之際。為何有存在前面已經(jīng)基本介紹了相關(guān)背景,并且也基本明確了就是在正式發(fā)布之前的最后一個版本,那為什么會出現(xiàn)呢我們首先要介紹今年的一個提權(quán)漏洞。 在 18 年 11 月底時,我寫了一篇文章 《runc 1.0-rc6 發(fā)布之際》 。如果你還不了解 runc 是什么,以及如何使用它,請參考我那篇文章。本文中,不再對其概念和用法等進(jìn)行說明。 在 runc 1....
摘要:生態(tài)周報(bào)內(nèi)容主要包含我所接觸到的生態(tài)相關(guān)的每周值得推薦的一些信息。在發(fā)現(xiàn)異常后官方團(tuán)隊(duì)迅速采取行動并保護(hù)網(wǎng)站免受攻擊。期待能早日解決相關(guān)問題,并迎來的正式發(fā)布。這些功能適用于,,,,,,,和編寫的應(yīng)用程序等,并將在下周放出技術(shù)預(yù)覽版本。 「K8S 生態(tài)周報(bào)」內(nèi)容主要包含我所接觸到的 K8S 生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄「k8s生態(tài)」。 Docker Hub 用戶隱...
摘要:生態(tài)周報(bào)內(nèi)容主要包含我所接觸到的生態(tài)相關(guān)的每周值得推薦的一些信息。在發(fā)現(xiàn)異常后官方團(tuán)隊(duì)迅速采取行動并保護(hù)網(wǎng)站免受攻擊。期待能早日解決相關(guān)問題,并迎來的正式發(fā)布。這些功能適用于,,,,,,,和編寫的應(yīng)用程序等,并將在下周放出技術(shù)預(yù)覽版本。 「K8S 生態(tài)周報(bào)」內(nèi)容主要包含我所接觸到的 K8S 生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄「k8s生態(tài)」。 Docker Hub 用戶隱...
摘要:生態(tài)周報(bào)內(nèi)容主要包含我所接觸到的生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄生態(tài)。正式發(fā)布是一個用于本地搭建環(huán)境的工具,使用方法可參考使用搭建本地環(huán)境。其他特性請閱讀正式發(fā)布是一個使用來為構(gòu)建的工具,現(xiàn)在是的項(xiàng)目。 「K8S 生態(tài)周報(bào)」內(nèi)容主要包含我所接觸到的 K8S 生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄「k8s生態(tài)」。 Kubernetes 1.14 正式發(fā)布 1...
摘要:生態(tài)周報(bào)內(nèi)容主要包含我所接觸到的生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄生態(tài)。正式發(fā)布是一個用于本地搭建環(huán)境的工具,使用方法可參考使用搭建本地環(huán)境。其他特性請閱讀正式發(fā)布是一個使用來為構(gòu)建的工具,現(xiàn)在是的項(xiàng)目。 「K8S 生態(tài)周報(bào)」內(nèi)容主要包含我所接觸到的 K8S 生態(tài)相關(guān)的每周值得推薦的一些信息。歡迎訂閱知乎專欄「k8s生態(tài)」。 Kubernetes 1.14 正式發(fā)布 1...
閱讀 623·2023-04-26 01:53
閱讀 2749·2021-11-17 17:00
閱讀 2880·2021-09-04 16:40
閱讀 1983·2021-09-02 15:41
閱讀 830·2019-08-26 11:34
閱讀 1222·2019-08-26 10:16
閱讀 1335·2019-08-23 17:51
閱讀 815·2019-08-23 16:50