LWN:無特權(quán)的chroot() !
關(guān)注了就能看到更多這么棒的文章哦~
Unprivileged chroot()
By Jonathan Corbet
March 15, 2021
DeepL assisted translation
https://lwn.net/Articles/849125/
可以說大多數(shù) Linux 開發(fā)者都不會(huì)在應(yīng)用程序中使用 chroot()。這個(gè)系統(tǒng)調(diào)用會(huì)將調(diào)用它的進(jìn)程放入一個(gè)新的文件系統(tǒng)視角,也就是將傳入的目錄作為根目錄。它可以用來將此進(jìn)程與文件系統(tǒng)的大部分隔離開,不過這個(gè)安全優(yōu)勢(shì)還是比較有限的。調(diào)用 chroot()是一種特權(quán)操作,但是,如果 Micka?l Salaün 能成功推銷這組 patch set 的話,至少在某些情況下后面會(huì)發(fā)生變化。
chroot() 通常會(huì)被用來對(duì)網(wǎng)絡(luò)守護(hù)進(jìn)程(network daemon process)放到一個(gè)小監(jiān)獄(jail)里。如果該進(jìn)程被入侵了,那么它也只能訪問這個(gè)新設(shè)置的根目錄之內(nèi)的子目錄。由此而產(chǎn)生了安全防護(hù)的效果,盡管這種防護(hù)并不是最強(qiáng)防護(hù)(有很多方法可以突破 chroot()的限制),但它仍然可以為攻擊者增加一些麻煩。chroot()還可以用來讓各個(gè)進(jìn)程看到不同的文件系統(tǒng),比如運(yùn)行 container 的時(shí)候就需要這個(gè)能力。
這個(gè)系統(tǒng)調(diào)用并不是任何人都可以使用的,需要有 CAP_SYS_CHROOT 這個(gè) capability 才能調(diào)用 chroot()。進(jìn)行這個(gè)限制是為了防止攻擊者在精心制作的文件目錄樹中運(yùn)行 setuid 程序,從而來欺騙(和利用)這些程序。舉個(gè)簡(jiǎn)單的例子,如果 setuid 程序看到的/etc/passwd 或/etc/sudoers 文件其實(shí)是攻擊者提供出來的,那么就會(huì)產(chǎn)生嚴(yán)重的錯(cuò)誤行為。
長(zhǎng)久以來,chroot()的局限性導(dǎo)致了它很難得到應(yīng)用。近年來,它的應(yīng)用范圍更小了,因?yàn)槌霈F(xiàn)了 Mount namespace 這種更靈活的機(jī)制也可以實(shí)現(xiàn)使用新的文件目錄樹的功能,并且也更難被攻破。所以相對(duì)來說,很少有開發(fā)者認(rèn)為在今后的開發(fā)中需要使用 chroot()。
因此,當(dāng) Salaün 帶著他的 chroot()補(bǔ)丁出現(xiàn)時(shí),人們有點(diǎn)驚訝。一旦合入了這個(gè) patch,無權(quán)限的進(jìn)程也可以調(diào)用 chroot(),但前提是必須滿足幾個(gè)條件:
此進(jìn)程必須在調(diào)用 prctl()時(shí)使用 PR_SET_NO_NEW_PRIVS 選項(xiàng)。這就阻止此進(jìn)程在今后獲得任何新的特權(quán)。例如運(yùn)行 setuid 和 setgid 程序也將不再能獲得這些程序?qū)僦鞯奶貦?quán)。既然在該模式下不再會(huì)有特權(quán)程序,那么相應(yīng)地這些特權(quán)也就不會(huì)再被利用了。
此進(jìn)程不能與其他任何進(jìn)程共享它的文件系統(tǒng)上下文(也就是 struct fs_struct,其中包含了 root 目錄和當(dāng)前工作目錄這些信息),否則 chroot()調(diào)用會(huì)對(duì)這兩個(gè)進(jìn)程都生效,而另一個(gè)進(jìn)程可能不會(huì)預(yù)料到它的文件系統(tǒng)環(huán)境會(huì)突然改變。
新的 root 必須在文件系統(tǒng)層次結(jié)構(gòu)中的當(dāng)前 root 之下。這就阻止了那些可能會(huì)導(dǎo)致進(jìn)程可以跳出當(dāng)前 jail(監(jiān)牢) 或 mount space 之外的手段。
如果滿足這些條件,可以認(rèn)為,允許進(jìn)程調(diào)用 chroot() 就是安全的。
但是,為什么要這樣做呢?其中一個(gè)原因是,一個(gè)正常運(yùn)行的 chroot() 環(huán)境通常需要有一個(gè)包含了最少信息的/dev 目錄,而創(chuàng)建這些設(shè)備節(jié)點(diǎn)仍然是一個(gè)需要特權(quán)的操作。如上所述,Linux 早就已經(jīng)有了比 chroot() 更好的選擇了。但 Salaün 說,在一些使用場(chǎng)景中,某個(gè)進(jìn)程可能希望在從不受限的環(huán)境中加載到它的依賴關(guān)系(例如函數(shù)庫)之后,自己進(jìn)入沙箱,而設(shè)備文件通??赡苁怯貌坏降?。
對(duì)這個(gè) patch 的最初反應(yīng)比較冷淡。Eric Biederman 擔(dān)心無權(quán)限的 chroot()與其他機(jī)制混合使用之后會(huì)產(chǎn)生安全問題:
在建立了 sandbox、使用了 seccomp filter、并且啟用了 no_new_privs 之后,還仍然允許 chroot,這似乎是在自找麻煩,并且可能會(huì)削弱現(xiàn)有的 sandbox。
Casey Schaufler 認(rèn)為 chroot()已經(jīng)過時(shí)了,同時(shí)也擔(dān)心類似的跟其他機(jī)制混合使用的問題:"我們?nèi)匀话l(fā)現(xiàn)了一些 corner case(比如 ptrace),在這些情況下 no_new_privs 是有缺陷的"。他還指出,對(duì) chroot()的訪問已經(jīng)有了更加精細(xì)的 capability 控制,也就是 CAP_SYS_CHROOT。
CAP_SYS_CHROOT 就是針對(duì) chroot 的。它不會(huì)提供其他不需要的權(quán)限,不像 CAP_CHOWN 或 CAP_SYS_ADMIN 那樣。把 chroot 變成不需要特權(quán)的這種做法是愚蠢的,因?yàn)樗赡苁?capability 機(jī)制本來就應(yīng)該起作用的場(chǎng)景。
Salaün 并沒有回答所有這些問題,但似乎并不氣餒,在討論結(jié)束后,他發(fā)布了第二版 patch set。不過,如果沒有更有說服力的回應(yīng)的話,很難將此改動(dòng)推到 upstream。以安全為導(dǎo)向的開發(fā)者需要被說服,讓他們相信 chroot()值得改進(jìn)。對(duì)于那些與其他安全機(jī)制混用可能會(huì)出現(xiàn)意外的改動(dòng),upstream 的門檻會(huì)更高。
討論最終很可能會(huì)回到具體使用場(chǎng)景上。在 2021 年是否還真的需要不需要特權(quán)的 chroot()?如果有用戶可以從這個(gè)功能中受益,現(xiàn)在可能是他們站出來解釋為什么需要這個(gè)功能的好時(shí)機(jī)。如果沒有這些信息,那么 unprivileged chroot() 很可能就是不會(huì)成為現(xiàn)實(shí)。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長(zhǎng)按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
