LWN: kernel中GCC plugin的未來命運!
關(guān)注了就能看到更多這么棒的文章哦~
The future of GCC plugins in the kernel
April 1, 2021
This article was contributed by Marta Rybczyńska
DeepL assisted translation
https://lwn.net/Articles/851090/
內(nèi)核加固(kernel hardening)的流程可以在多方面受益于編譯器支持。近年來,內(nèi)核自我保護項目(Kernel Self Protection Project)將 grsecurity/PaX 中的一些 patch set 以 GCC plugin 的形式來給 kernel 提供了更多支持。LWN 早在 2017 年就報道過這個流程。最近的一次討論中重點講述了這樣一個事實:使用 GCC plugin 方式也帶來了一些缺點,一些開發(fā)者希望能看到后續(xù)用其他方式取代這些插件。
討論來源于 Josh Poimboeuf 的報告,他在啟用 GCC 插件編譯 kernel tree 之外的 module 時遇到一個問題。在他的場景中,只要用來編譯 module 的 GCC 版本與用來構(gòu)建 kernel 的版本稍有不同時,編譯就會失敗。他附上了一個 patch,用來將 error 改為 warning,并禁用了受影響的 GCC 插件。稍后,Justin Forbes 解釋了一下這個導(dǎo)致問題的環(huán)境是如何產(chǎn)生的:這發(fā)生于 Fedora 的持續(xù)集成系統(tǒng)中,該系統(tǒng)會先從建立一個當(dāng)前的 toolchain snapshot 來開始。然后用新的 toolchain 來編譯 kernel tree 之外的 module,而不會重新編譯 kernel 本身。自從 GCC plugin 被啟用后,所有帶有 kernel tre 之外 module 的編譯 job 都會失敗。
將 error 改為 warning 的想法,在內(nèi)核構(gòu)建系統(tǒng)維護者 Masahiro Yamada 看來不是很贊同,他說:"我們有一個假設(shè),就是 kernel tree 之內(nèi)和之外的代碼都應(yīng)該是用同一個編譯器編譯的"。Poimboeuf 回應(yīng)說,現(xiàn)實世界中的的情況并不是這樣的。不過,其他內(nèi)核開發(fā)者也同意 Yamada 的觀點。Greg Kroah-Hartman 寫道:
你難道沒有注意到 include/linux/compiler.h 以及我們?yōu)楦鞣N不同版本的 gcc/clang/intel 等編譯器所做的那些各不相同改動以及 workaround 嗎?我們從來沒有保證過用不同的編譯器所編譯出來的 kernel module 能夠工作,我認為我們現(xiàn)在也不應(yīng)該開始改變這個觀點。
此外,Yamada 指出,在以前的討論中,對內(nèi)核及其 module 的編譯會使用相同的編譯器版本,這已被接受為一種潛在規(guī)定。由于內(nèi)核開發(fā)者明確表示了不同意,所以討論似乎已經(jīng)結(jié)束。
The dislike for GCC plugins
然而,Poimboeuf 幾天后帶著另一個可以解決他的問題的方案回來時,討論又重新開始了,這個方案是:每當(dāng) GCC 版本改變時,就重新編譯所有的 plugin。這被 Yamada 拒絕了,他指出 Ubuntu 并沒有 GCC 版本不匹配的問題,所以這個問題似乎是 Fedora 特有的。Linus Torvalds 也不同意這個提議,但是因為另一個原因。對他來說,當(dāng) GCC 版本改變時,并沒有什么出于技術(shù)上的限制會需要人們必須重新編譯更多的東西,但他對 GCC 插件的一些通用使用和設(shè)計方面表示了關(guān)注。在后續(xù)的郵件中,他用了比較強烈的語言解釋了他的理由:
內(nèi)核的 GCC 插件最終 會 消失。它們是一場無妄之災(zāi)。一直都是這樣。我很抱歉我曾經(jīng)合并了這些功能進 kernel。它不僅對于維護工作是個噩夢,而且它首先本身就是一個可怕的東西,帶著很不好用的 interface。這個技術(shù)簡直太糟糕了。
對于 Torvalds 來說,如果要正確實現(xiàn)這種插件,就應(yīng)該是在中間表示法(IR,intermediate representation)這一層來進行修改,但是 GCC 的插件由于一些非技術(shù)性的原因而被設(shè)計成用其他方式實現(xiàn)了(主要是擔(dān)心 non-free 插件,也就是非自由軟件的插件,LWN 在 2008 年就報道過這一點)。他說,對插件感興趣的人應(yīng)該使用 Clang,因為它有一個干凈的 IR,并且很容易允許在 IR 級別添加類似的檢查。
GCC plugins and their Clang equivalents
然而,刪除內(nèi)核里 GCC 插件這件事,似乎在近期并不可能實現(xiàn)。Kees Cook 介紹了 GCC 插件的現(xiàn)狀、它們在 Clang 中的等價功能、以及為什么其中一些插件會有個用戶社區(qū)。GCC 插件提供的一些功能還不能用 Clang 來實現(xiàn),其實無論如何,很多發(fā)行版提供商都沒有使用 Clang 來構(gòu)建內(nèi)核。
目前內(nèi)核支持以下插件(位于 scripts/gcc-plugins/):
cyc_complexity,計算函數(shù)的循環(huán)復(fù)雜性。它是兩個最初的示例插件之一,可能并沒有用戶。
latent_entropy 增加了 CPU 執(zhí)行時的熵。Cook 認為沒有什么地方用到它,特別是在增加了抖動熵機制之后。后續(xù)沒有計劃在 Clang 中支持這個。
arm32 的各個任務(wù)堆棧保護器(per-task stack protector for arm32)為 32 位 ARM 平臺提供了堆棧保護。Cook 說,目前 Clang 連 64 位系統(tǒng)都還沒有對應(yīng)的功能。
randstruct 隨機地改變內(nèi)核數(shù)據(jù)結(jié)構(gòu)中各個字段的順序,這只對那些只包含函數(shù)指針的結(jié)構(gòu)生效,或者那些明確用__randomize_layout 標(biāo)記過的結(jié)構(gòu)生效。這個插件有兩個版本:一個是完整版,一個是限制版。限制版只會改變同一 cacheline 中的多個成員之間的順序,這降低了性能開銷,但也降低了保護水平。Clang 中有一個版本已經(jīng)被提出來了,但目前被擱置。Cook 指出,有安全意識的那些最終用戶都傾向于啟用這個插件,但發(fā)行版提供商通常不啟用。
sancov(Cook 沒有提到)會通過在每個 basic block 的開始插入一個對__sanitizer_cov_trace_pc()的調(diào)用,來幫助那些 fuzzing coverage 測試,也就是用來確定哪些代碼塊真正得到了利用。
stackleak 會追蹤內(nèi)核里的堆棧深度,以便在返回用戶空間時可以用特定模式的內(nèi)容來覆蓋掉已使用過的堆棧。目前還沒有計劃支持 Clang。
structleak 初始化了那些可能會被傳遞給用戶空間的結(jié)構(gòu)。Clang 的 -ftrivial-auto-var-init=zero 選項就是類似實現(xiàn)。GCC 后續(xù)可能也會支持該選項。
最終的結(jié)果看來,這些插件還是繼續(xù)存在一段時間的。
同時,討論中也有一些積極的成果。在這個過程中我們意識到,這些插件對它們所對應(yīng)的 GCC 版本非常敏感,每當(dāng) GCC 版本發(fā)生變化時,它們并沒有被重新編譯過。顯然,自從插件第一次被添加以來就是這個情況了;盡管 Yamada 在討論中拒絕了這個想法,但他還是解決了這個問題。作為 Poimboeuf 最初問題的解決方案,開發(fā)者們最終同意在內(nèi)核和模塊之間出現(xiàn) GCC 版本不匹配時顯示一個警告。這將由用戶來決定這個差異可可以忽略的,還是需要重新編譯內(nèi)核。
GCC 版本不匹配的問題并不是 Poimboeuf 注意到的唯一一個問題;他還指出了插件構(gòu)建系統(tǒng)對一個 gcc-plugin-devel 包(可選的)的依賴關(guān)系。即使用戶的 GCC 版本與編譯內(nèi)核時使用的版本相同,但如果他們沒有這個包,插件也會被悄悄地禁用,而內(nèi)核編譯會成功完成且沒有任何警告。這個問題還沒有得到進一步解決。
Conclusions
這次討論涵蓋了 GCC 插件的一些問題。這很可能意味著開發(fā)者在啟用它們時應(yīng)該小心謹慎。Poimboeuf 最初的問題利用這個 warning 就得到了某種程度的解決,這個 warning 可能開始在一些系統(tǒng)中報告出來。如果兩個 GCC 版本很接近的話,用戶可能會選擇忽略這個 warning。在啟用插件時,開發(fā)者應(yīng)該注意先安裝 gcc-plugin-devel,否則他們的 module 可能并沒有按照你的要求來完成編譯。
內(nèi)核中的 GCC 插件的未來尚未決定。Clang 似乎是 hardening 工作的首選,這個方向也得到了 Torvalds 的鼓勵,但是現(xiàn)有的各個 GCC 插件(除了一個以外)并沒有 Clang 的對應(yīng)物。看來,它們至少還會存在一段時間。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
