“我第一次給 Linux 內核做貢獻,不僅被剝奪了,還遭到了維護者的輕視...”

導讀 原標題:“我第一次給 Linux 內核做貢獻,不僅被剝奪了,還遭到了維護者的輕視...”編譯 | 蘇宓出品 | CSDN(ID:CSDNnews)一個 Bu...

原標題:“我第一次給 Linux 內核做貢獻,不僅被剝奪了,還遭到了維護者的輕視...”

編譯 | 蘇宓

出品 | CSDN(ID:CSDNnews)

一個 Bug 引發的“連鎖反應”

事情要從一年半前開始說起,Ariel 曾向他以前的公司申請時間來解決一個影響項目調試能力的問題——gdbserver 無法調試在 PowerPC32 架構上運行的多線程應用程序。與 gdbserver 的連接斷開了,它無法再控制調試會話。

這里的 gdbserver(GDB Server),是一個用于調試程序的工具,特別是針對嵌入式系統和遠程目標的調試。它允許開發人員使用 GNU 調試器(GDB)與運行在另一個計算機或設備上的程序進行交互式調試。

事實上,在此之前,也有很多人遇到了同樣的問題,但就是不能確定問題究竟出現在了哪個軟件組件上,也許是工具鏈、gdbserver、Linux 內核或 Ariel 團隊在內核樹上應用的自定義補丁。

雖然有大致方向,但是仍然沒有具體的頭緒,這也導致 Ariel 團隊一時之間也找不到問題的根本原因和解決方案。

深挖 Bug 源頭,尋找修復方式

正如上文所述,行業內也有很多人在遇到同樣的問題時展開調查,而Ariel 結合了他們現有分析并使用 Google 搜索查閱大量資料之后,取得了第一個突破。

Ariel 在網絡上找到了一封 2016 年的郵件列表,此列表中不僅描述了與他遇到問題的相同癥狀,還指出了引入問題的確切提交。

具體而言,引入錯誤的補丁將 thread_struct thread 的定義從 task_struct 的中間移動到了末尾,這是一個看似無害的改變。

但是當時一位名為 Holger Brunck 開發者在調試問題后發現:

我看到 gdbserver 為每個線程發送一個 SIGSTOP 信號給內核并等待響應。內核確實接收到了所有信號,但只在錯誤情況下對其中一些信號作出響應。

這與我的“ps”輸出相匹配,因為我看到有些線程不處于 pthread_stop 狀態,然后 gdbserver 被掛起。

這是一個低級問題,因為在與 gdbserver 交互后,某些線程處于錯誤的進程狀態,gdbserver 無法再控制它們。

為此,Ariel 花了 3-4 天時間去詳細地了解閱讀與 PowerPC 架構相關的提交描述以及關于 task_struct 的更改,試圖弄清楚這個問題是否在后續的內核版本中得到解決(這里劇透下:其實并沒有解決)。

于是,Ariel 排查了 thread_struct thread 以確定何時出現問題,并使用了一系列輔助工具,如 pahole 檢查 task_struct 的布局;ftrace 來確定被調試進程的線程何時被調度等等。

直到這時,Ariel 突然意識到這可能是一個內存損壞問題,因為不像其他線程那樣,被卡住的線程只被調度一次。

起初,Ariel 忽略了這可能是一個內存損壞問題,因為在原始線程中提到:

緩沖區的內容總是零,不會更改。所以至少沒有人向緩沖區寫入非零值。

在這個過程中,Ariel 犯下了一個錯誤,他沒有驗證結構是否被零字節覆蓋,這里也警醒很多開發者,要學會不斷驗證你的假設。

在進一步查找解決方案過程中,憑借多年的軟件工程師經驗,Ariel 記得 x86 架構有可以用來觸發數據寫入斷點的調試寄存器。果然,PowerPC 也通過 DABR 寄存器實現了類似的功能。

在此基礎上,Ariel 調查了如何在 Linux 上使用硬件斷點,最終他在參考程序員問答社區 StackOverflow 上的一個答案(https://stackoverflow.com/a/19755213)實現了新的 Linux 內核模塊。該模塊能夠在 __state 字段上放置硬件斷點,以找出是誰在寫入它。

詳細來看,Ariel 通過自定義內核模塊顯示了寫入 task_struct 的 __state 字段的地方的堆棧跟蹤。此時,Ariel 注意到一個異常值,揭示了 ptrace_put_fpr(POKEUSER API 使用的函數)中的緩沖區溢出。這導致了 task_struct 的重要字段被覆蓋,例如 __state,該字段存儲進程的狀態,并且內核還用它來跟蹤哪些進程被調試器停止了。

溢出的原因是什么?將一個應用于 32 位元素數組的索引用于 64 位元素數組。共有 64 個索引用于 FPR,因此可尋址的內存總共是 64 * 8 = 512 字節。但 fp_state.fpr 數組中只有 32 個條目,這意味著可用內存只有 32 * 8 = 256 字節。這允許用戶(也就是 gdbserver)在數組末尾之后寫入多達 256 字節。

發送補丁至上游,“挫折”也由此出現

找到了問題的根源也有了解決方案,Ariel 基于安全方面考慮,他認為這個可能導致進程狀態內存被覆蓋的內存損壞問題可能具有安全影響,于是他很興奮地向 Linux 內核安全團隊(security@kernel.org)發送了一個補丁。

不幸的是,這個郵件列表是私人的,所以他無法鏈接到自己發送的原始補丁。

后來 Linux 內核安全團隊安排了 PowerPC 的維護者 Michael Ellerman 來進行了跟進,并告訴 Ariel 會私下聯系他來解決這個問題。

此時,Ariel 已經給 Michael Ellerman 發送了兩個修復問題的補丁,根據其描述:

然而,Michael Ellerman 沒有接受這兩個補丁,而是實施了他自己的修復版本。

在這一操作背后,Ariel 曾與 Michael Ellerman 溝通過,“如果能接受我的補丁,我會非常感激,這樣我就可以因修復這個問題而得到認可,并成為內核貢獻者。我也愿意與他合作,解決他的反饋,并發送后續版本的補丁。”

萬萬沒想到的是,Michael Ellerman 回復稱(意譯):

對不起,我更喜歡我的版本。如果你想成為 Linux 內核貢獻者,這里有一個問題可以讓你來解決。

對于這樣的答復,Ariel 覺得困惑和侮辱。Ariel 認為,“他并不是想讓我為修復問題而受到認可,而是想讓我多做更多工作。我和我的公司應該得到適當的榮譽,因為我們花了很多心血來解決這個問題。”

最終,Ariel 只得到一個“Reported-by”的標簽,這也讓他感覺真的很不公平。

Reported-by 標簽是給予那些發現錯誤并報告的人以榮譽,并希望激勵他們將來再次幫助我們。

Ariel 表示,「我絕對沒有感到受到鼓舞,再次參與內核社區。相反,我感到被輕視,對我的工作沒有得到適當的認可感到憤怒」。

Ariel :我的第一個內核貢獻經歷非常令人沮喪

在 Ariel 看來,自己花了大量的時間和精力進行根本原因分析,然后去修復錯誤、測試和調試 Bug,與此同時,也從公司的其他工程師那里獲得反饋,將最新的修復去適應最新的內核版本,并向 PowerPC 維護者 Michael Ellerman 發送了兩個不同的補丁。

遺憾的是,Michael Ellerman 沒有接受 Ariel 的補丁,也沒有引導他找到更好的解決方案,而是自行實施了他自己的修復版本,只給 Ariel 報告問題的榮譽(而這個問題其實在六年前就已經被其他人披露出來了)。

「我的第一個內核貢獻經歷非常令人沮喪和令人泄氣,因為要與那些認為得不到適當認可并不重要的人打交道」,Ariel 在自己的長文最后寫道。

寫在最后

歡迎參與 CSDN 重磅發起的《2023 AI 開發者生態調查問卷》,分享您真實的 AI 使用體驗,更有精美好禮等你拿!

免責聲明:本文由用戶上傳,如有侵權請聯系刪除!