LWN: kernel warning 的時候應(yīng)該怎么處理?
關(guān)注了就能看到更多這么棒的文章哦~
What to do in response to a kernel warning
By Jonathan Corbet
November 18, 2021
DeepL assisted translation
https://lwn.net/Articles/876209/
內(nèi)核內(nèi)部提供了一些宏,供代碼在出錯的時候調(diào)用從而產(chǎn)生 warning。然而,它并沒有提供多少指導(dǎo),來告訴人們在看到 warning 的時候應(yīng)該做些什么。Alexander Popov 最近發(fā)布了一組 patch,為系統(tǒng)對在發(fā)出 warning 的時候增加了一個選項。這一組 patch 似乎不太可能按它當(dāng)前的做法來被合入,但它確實成功地引起了人們關(guān)于如何處理 warning 的討論。
warning 是通過調(diào)用 WARN()和 WARN_ON_ONCE() 等宏來觸發(fā)的。默認(rèn)情況下,warning 文本被發(fā)送到 kernel log 中,然后系統(tǒng)繼續(xù)執(zhí)行,就好像 warning 沒有發(fā)生過一樣。有一個 sysctl 開關(guān) (kernel/panic_on_warn),打開的話會在每次 warning 發(fā)出時就讓系統(tǒng) panic,但對于系統(tǒng)管理員來說,要么忽略問題、要么讓系統(tǒng)完全無法繼續(xù)用,在這兩個選項之間缺乏中間地帶。
Popov 的 patch 是增加了另一個名為 kernel/pkill_on_warn 的 sysctl 開關(guān)。如果設(shè)置為非零值,那么這個參數(shù)會要求內(nèi)核在 warning 出現(xiàn)時就 kill 掉當(dāng)前正在運(yùn)行的進(jìn)程的所有線程。Popov 說,這種行為比起什么都不做來說,可以增加系統(tǒng)的 safety 和 security,同時又不像直接導(dǎo)致系統(tǒng) panic 方案那么大的破壞性。它可能會殺死當(dāng)前正在試圖攻擊系統(tǒng)的進(jìn)程,并且平時也能讓進(jìn)程避免在已知出現(xiàn)了某些錯誤的情況下繼續(xù)運(yùn)行。
有一些人反對這個方案,Linus Torvalds 是第一個。他指出,當(dāng)系統(tǒng)出現(xiàn) warning 時,當(dāng)前正在運(yùn)行的進(jìn)程可能與 warning 本身并沒有任何關(guān)系。例如,問題可能發(fā)生在一個中斷處理程序中,或者是其他一些什么情況。他說:"隨便向某個進(jìn)程發(fā)送 signal,這只能算是盲目地寫程序(voodoo programming),都有可能導(dǎo)致其他一些奇怪的故障"。
Torvalds 認(rèn)為更好的方法可能是創(chuàng)建一個新的/proc 文件,當(dāng)某個會影響整個系統(tǒng)的事件發(fā)生時(如出現(xiàn)了 warning),就可以從這個 /proc 文件獲取到相關(guān)信息。然后使用一個用戶空間的守護(hù)程序(daemon)可以保持對該文件進(jìn)行 poll 輪詢,在看到 warning 時讀取到相關(guān)信息,然后自己判斷需要殺死相關(guān)進(jìn)程的話就自己動手。Marco Elver 補(bǔ)充說,這里有一個 tracepoint 就可以提供相關(guān)的信息,只需做一點工作就好。Kees Cook 提出了一個實現(xiàn)方案,但 Popov 不太喜歡。他認(rèn)為這種方法會讓一個進(jìn)程在 warning 發(fā)生后繼續(xù)執(zhí)行,而當(dāng)用戶空間對這種情況采取行動時,可能已經(jīng)太晚了。
James Bottomley 認(rèn)為,到目前為止討論中提出的所有方法都是不對路的。他說,如果 warning 發(fā)生了,那么內(nèi)核就不再處于一個已知的正確狀態(tài),什么事情都有可能發(fā)生:
WARN 的意思是發(fā)生了一個意外狀況,這意味著內(nèi)核本身處于一個未知的狀態(tài)。你不能通過殺死和重啟某些東西來恢復(fù),而是必須要重新初始化到一個已知的狀態(tài)(也就是說需要 reset 系統(tǒng))。我們之所以用 WARN 而不是 BUG,部分原因可能是我們相信這里的狀態(tài)被破壞的問題不嚴(yán)重,如果你小心謹(jǐn)慎使用的話,系統(tǒng)可以繼續(xù)在這種稍微退化一些的狀態(tài)下繼續(xù)運(yùn)行,只要用戶愿意接受這種風(fēng)險。
因此,他說,唯一合理的策略就是繼續(xù)運(yùn)行(接受可能發(fā)生壞事的風(fēng)險)或殺死整個系統(tǒng)并重新啟動。而這些已經(jīng)是內(nèi)核現(xiàn)在就支持的了。
Popov 曾提到 ELISA 項目,該項目正在努力將 Linux 部署到安全關(guān)鍵(safety-critical)的應(yīng)用中,這個項目可能會支持增加 pkill_on_warning 開關(guān)。但為該項目工作的 Lukas Bulwahn(但他小心翼翼地表示他不代表 ELISA 的官方觀點)表示不贊同。他說,正確的解決方案是在 warning 時殺死系統(tǒng),但也要確保只有在事情真正脫離軌道的情況下才發(fā)出 warning:
應(yīng)該是只在某些東西沒有按照開發(fā)者的期望進(jìn)行配置、或者內(nèi)核被置于一個是意料之外的狀態(tài)、并且基本上只有開發(fā)者在緊密關(guān)注、測試,尚未被人們廣泛使用時,才應(yīng)該發(fā)出 warning。warning 不應(yīng)該被當(dāng)作提供信息的機(jī)制(informative),因為這些信息提供機(jī)制仍然允許內(nèi)核在正常的環(huán)境中繼續(xù)適當(dāng)?shù)剡\(yùn)行。
他補(bǔ)充說,真正的安全(truly safe)還需要確保對 panic() 的調(diào)用在無論什么情況下都能真正停止系統(tǒng)。這一點其實并不像人們想象的那么容易。例如,某次 panic() 調(diào)用中可能會在試圖獲得一個鎖時就卡住了。
Christoph Leroy 認(rèn)為,warning 應(yīng)該在內(nèi)核內(nèi)處理,這樣系統(tǒng)才能盡可能地保持良好的運(yùn)行。鑒于此,他繼續(xù)說:"pkill_on_warning 似乎很危險,而且關(guān)聯(lián)性不強(qiáng),可能比什么都不做更危險,尤其是 WARN 可能是因為與當(dāng)前在運(yùn)行的線程無關(guān)的原因而被觸發(fā)"。然而,Popov 不同意這樣的觀點,他認(rèn)為我們不可以期望所有的 warning 都能在內(nèi)核中得到正確的處理:
對于在內(nèi)核源代碼中加入 BUG*(),存在著非常強(qiáng)烈的反對力量。所以有很多情況下,使用了 WARN*() 來處理嚴(yán)重的問題,因為內(nèi)核開發(fā)者們沒有其他選擇。
確實,他的 patch 如何合入并啟用了新的選項的話,warning 的行為幾乎就跟 BUG() 調(diào)用相同了。BUG() 調(diào)用默認(rèn)就會使運(yùn)行中的進(jìn)程立即結(jié)束。正如他所指出的,開發(fā)人員在試圖使用這些 BUG() 之類的函數(shù)調(diào)用時遇到了阻力,因為人們認(rèn)為這些函數(shù)的效果太嚴(yán)重(severe)了。
目前還不清楚這種增加一個讓 warning 變得更嚴(yán)重的選項,是否是解決這個問題的最好辦法。不過,這次討論可能會產(chǎn)生一個好的結(jié)果,那就是對 warning 的含義和產(chǎn)生 warning 時應(yīng)該發(fā)生什么會繼續(xù)進(jìn)行更好地定義。跟內(nèi)核中的許多機(jī)制一樣,warning 宏是在沒有系統(tǒng)尚未進(jìn)行整體設(shè)計的情況下出現(xiàn)的。現(xiàn)在有了很多關(guān)于開發(fā)者們使用 warning 的豐富經(jīng)驗,所以現(xiàn)在開始進(jìn)行一些設(shè)計可能會使內(nèi)核整體上更加茁壯穩(wěn)定(robust)。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
