撰稿 | 言征
Ariel Miculas,是一位開源貢獻(xiàn)者,目前在思科任職軟件工程師,最近他在自己的博客上開噴Linux內(nèi)核:“為什么我貢獻(xiàn)了問題和補(bǔ)丁代碼,最后貢獻(xiàn)者的名單里卻沒有我?”
1、自封的Linux內(nèi)核“貢獻(xiàn)者”
翻開Ariel的博客,他這樣介紹自己:“我是一位充滿激情的軟件工程師,擁有網(wǎng)絡(luò)安全碩士學(xué)位。我感興趣的領(lǐng)域是系統(tǒng)編程,包括管理程序、操作系統(tǒng),以及最近的Linux文件系統(tǒng)。我也是一個(gè)開源貢獻(xiàn)者,以下是我貢獻(xiàn)的一些項(xiàng)目:Linux內(nèi)核、capnproto-rust、squashfuse?!?/p>
可以看出,Ariel認(rèn)為自己是對(duì)Linux內(nèi)核有貢獻(xiàn)的。然而讓他氣憤地是,他的第一個(gè)內(nèi)核貢獻(xiàn)卻被內(nèi)核維護(hù)者被無情剝奪了。
2、復(fù)現(xiàn)了六年前的Linux內(nèi)核Bug,一直無解
GDB是Linux下的調(diào)試?yán)鳎鴊dbserver是配合gdb實(shí)現(xiàn)遠(yuǎn)程調(diào)試的工具。大約在一年半前,Ariel致力于解決掉一個(gè)有關(guān)gdbserver遠(yuǎn)程項(xiàng)目調(diào)試的問題:gdbserver 無法調(diào)試在 PowerPC32 架構(gòu)上運(yùn)行的多線程應(yīng)用程序。與 gdbserver 的連接已斷開,并且無法再控制調(diào)試會(huì)話。慶幸的是,很多人已經(jīng)調(diào)查過這個(gè)問題,Ariel團(tuán)隊(duì)仍然不確定問題出在哪個(gè)軟件組件上:它可能是工具鏈、gdbserver、Linux 內(nèi)核或他們應(yīng)用的自定義補(bǔ)丁內(nèi)核樹的頂層。一時(shí)間難以找到根本原因。
Ariel結(jié)合現(xiàn)有分析和谷歌搜索,對(duì)這個(gè)問題進(jìn)行了深入研究,終于取得了第一個(gè)突破:他找到了一個(gè)與其描述問題癥狀相同的電子郵件線程,而且還指出了引入它的一個(gè)關(guān)于Linux內(nèi)核的確切提交(kernel/git/torvalds/linux.git)。
圖片
引入該錯(cuò)誤的補(bǔ)丁將thread_struct thread的定義從task_struct的中間移動(dòng)到了末尾,這個(gè)更改看起來貌似無害,但會(huì)帶來一些低級(jí)問題——
我看到的是 gdbserver 為每個(gè)線程發(fā)送 SIGSTOP 到內(nèi)核并等待響應(yīng)。內(nèi)核確實(shí)接收到所有信號(hào),但僅在錯(cuò)誤情況下響應(yīng)其中的一些信號(hào)。
然后,它與我的“ps”輸出相匹配,因?yàn)槲铱吹侥承┚€程未處于 pthread_stop 狀態(tài),然后 gdbserver 被掛起。
圖片
問題在于,在與 gdbserver 交互后,某些線程處于錯(cuò)誤的進(jìn)程狀態(tài),并且 gdbserver 無法再控制它們。
3、古老的問題往往源于簡(jiǎn)單的錯(cuò)誤
Ariel 花了 3-4 天閱讀 PowerPC 架構(gòu)相關(guān)的提交描述以及task_struct的版本變化,卻發(fā)現(xiàn)這個(gè)問題并沒有在后續(xù)的內(nèi)核版本得到解決。
確定問題何時(shí)復(fù)現(xiàn)之后,Arielkaishi使用一款工具來檢查 task_struct的布局,同時(shí)用 ftrace來確定調(diào)試進(jìn)程的線程何時(shí)被調(diào)度,最后終于找到了原因:可能是內(nèi)存損壞的問題:與其他線程不同,卡住的線程僅被調(diào)度一次。然而,一開始其實(shí)他就否認(rèn)了這個(gè)問題,因?yàn)樵贚inux郵件列表里有關(guān)原始線程的描述:
緩沖區(qū)的內(nèi)容始終為零并且不會(huì)改變。所以至少?zèng)]有人向緩沖區(qū)寫入非零值。
后來,Ariel研究了如何在 Linux 上使用硬件斷點(diǎn),最終基于某個(gè) stackoverflow 的答案實(shí)現(xiàn)了一個(gè)新的 Linux 內(nèi)核模塊,該模塊可以在__state 字段上放置一個(gè)硬件斷點(diǎn) ,以找出到底是誰寫入它。
圖片
https://elixir.bootlin.com/linux/v6.5.5/source/include/linux/sched.h#L746
Ariel興奮地總結(jié)了找到這個(gè)Bug的方法:通過自定義內(nèi)核模塊顯示了寫入__state字段的位置的堆棧跟蹤。task_struct一個(gè)異常值揭示了 ptrace_put_fpr中的緩沖區(qū)溢出。
這導(dǎo)致重要字段被 task_struct覆蓋,例如__state存儲(chǔ)進(jìn)程狀態(tài)的字段,內(nèi)核還使用它來跟蹤調(diào)試器停止了哪些進(jìn)程等等。
溢出的原因也很簡(jiǎn)單:內(nèi)核需要對(duì) 64 位元素?cái)?shù)組進(jìn)行索引,但 fp_state.fpr 數(shù)組中只有 32 個(gè)。
4、向上游發(fā)送補(bǔ)丁,卻被維護(hù)者擺了一道
發(fā)現(xiàn)解決問題的過程非常極客,但發(fā)送補(bǔ)丁開始之后,卻讓Ariel感覺不爽了。
Ariel后來向 Linux 內(nèi)核安全團(tuán)隊(duì) (security@kernel.org) 提交了第一個(gè)補(bǔ)丁,不幸的是,由于這個(gè)郵件列表是私人的,所以無法鏈接到原始補(bǔ)丁。
后來PowerPC 維護(hù)者M(jìn)ichael Ellerman跟進(jìn)并告知,他將私下聯(lián)系來解決這個(gè)問題。實(shí)際上,Ariel已經(jīng)向他發(fā)送了兩個(gè)修復(fù)該問題的補(bǔ)?。喊l(fā)送到安全郵件列表的原始補(bǔ)丁和另一個(gè)版本 (與第一個(gè)完全不同),第二個(gè)版本解決了在回復(fù)最初提交的內(nèi)容時(shí)收到的一些建議。
Michael Ellerman 還是沒有接受這些建議,而是實(shí)施了他自己的修復(fù)版本。Ariel有些沮喪,表示:希望能接受自己的補(bǔ)丁,這樣就可以獲得修復(fù)此問題的榮譽(yù)并成為內(nèi)核貢獻(xiàn)者。同時(shí)也愿意與維護(hù)者合作,解決他的反饋并發(fā)送補(bǔ)丁的后續(xù)版本。
然而維護(hù)者的答復(fù)卻讓Ariel感到非常困惑和侮辱:
抱歉,我想以不同的方式修復(fù)它。如果您想成為 Linux 內(nèi)核貢獻(xiàn)者,這里有一個(gè)您可以解決的問題。
“他不想因?yàn)榻鉀Q問題而獲得認(rèn)可,而是想讓我做更多的工作。我和我的公司應(yīng)該因解決這個(gè)問題而獲得應(yīng)有的榮譽(yù),特別是考慮到我們?yōu)榇烁冻隽硕嗌倥??!?/p>
5、侮辱性極強(qiáng):貢獻(xiàn)了補(bǔ)丁,卻只被授予了“報(bào)告者”的頭銜
Ariel認(rèn)為只獲得“報(bào)告者”標(biāo)簽非常不公平。因?yàn)椤皥?bào)告者”報(bào)簽的分量遠(yuǎn)不及貢獻(xiàn)者標(biāo)簽——它是向那些發(fā)現(xiàn)錯(cuò)誤并報(bào)告錯(cuò)誤的人表示感謝,并希望能夠激勵(lì)他們將來再次幫助我們。
事后,Ariel對(duì)內(nèi)核社區(qū)的印象急轉(zhuǎn)直下。相反,他因自己的工作沒有得到適當(dāng)?shù)恼J(rèn)可而感到被貶低和憤怒。
“我花了很多時(shí)間和精力進(jìn)行根本原因分析,修復(fù)錯(cuò)誤,測(cè)試和驗(yàn)證修復(fù),從公司其他工程師那里獲取反饋,使修復(fù)適應(yīng)最新的內(nèi)核版本,并向 PowerPC 維護(hù)者 Michael Ellerman 發(fā)送兩個(gè)不同的補(bǔ)丁。他沒有接受我的補(bǔ)丁或指導(dǎo)我找到更好的解決方案,而是繼續(xù)實(shí)施自己的修復(fù)方案,只對(duì)我報(bào)告問題給予認(rèn)可(而且這個(gè)問題還是六年前已經(jīng)報(bào)告過)。”
6、Linux內(nèi)核維護(hù),對(duì)于“貢獻(xiàn)者”有些吝嗇
此事爭(zhēng)議的一個(gè)焦點(diǎn)在于,如果維護(hù)者已經(jīng)閱讀了Areil的補(bǔ)丁,之后改變了一些風(fēng)格,并自己提交這個(gè)補(bǔ)丁,那么就會(huì)存在借用補(bǔ)丁提交者的事實(shí)。
又或者即便提交者的代碼很糟糕,但也不應(yīng)該很不屑的回復(fù)一句:我想用不同的方式修復(fù)它。畢竟,如果沒有沒有原始代碼,我們連重構(gòu)修復(fù)的機(jī)會(huì)都沒有。
誠(chéng)然,出于質(zhì)量目的,維護(hù)者可以堅(jiān)持自己的引進(jìn)內(nèi)核的代碼,但很顯然,Ariel是該補(bǔ)丁的共同貢獻(xiàn)者,而不僅僅是Bug的“報(bào)告者”。
通過Reddit上用戶的評(píng)論也能看出,Linux內(nèi)核維護(hù)者對(duì)于提交補(bǔ)丁代碼者的認(rèn)可力度不足已經(jīng)不是個(gè)例:
“前幾次我向 Linux 內(nèi)核提交建議補(bǔ)?。ㄔ谕ㄟ^ LKML 半自動(dòng)提交成為可能之前),我與維護(hù)者(本例中為 Ted Tso)進(jìn)行了對(duì)話。一旦他對(duì)我的工作的正確性感到滿意,他就合并了補(bǔ)丁,一切都很好。我從未要求過,也沒有得到過任何榮譽(yù)?!?/p>
希望這樣的情況能夠得到改善,否則會(huì)讓一些開源貢獻(xiàn)者們失去對(duì)“開源”的熱愛。
參考鏈接:https://ariel-miculas.github.io/How-I-got-robbed-of-my-first-kernel-contribution/