由Linux核心bug引起SSH登入緩慢問題的排查與解決

程式猿DD發表於2022-12-06

今年7月,有一位使用者反饋,使用該映象建立出的快傑雲主機每次啟動時,第一次SSH登入會很慢,有時候需幾十秒甚至幾分鐘才能登入成功,影響了使用體驗。

經過排查,定位到是Linux核心隨機數熵池初始化慢的原因,且在多個條件組合下才會觸發。更深入調查則發現因為核心bug,凡使用了libssl 1.1.1的程式(如開啟了https的nginx)都有類似問題,會對系統安全產生不少潛在影響。
最終我們透過升級自主維護的核心,很快妥善修復了該問題,保證了快傑雲主機的體驗和安全性。

由Linux核心bug引起SSH登入緩慢問題的排查與解決



本文對排查過程加以梳理。

1

初步排查

該問題只在單個使用者上出現過,且隻影響啟動後的首次SSH登入,一旦登入成功便恢復正常。現場捕獲不易,不過我們設法將其復現。

ssh -v
開啟ssh使用者端的冗餘日誌模式嘗試登入問題主機,發現總是會卡在"debug1: pledge: network"處,根據提示,sshd已經完成了使用者的身份認證過程。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

可以看出,問題應當是發生在身份鑑定剛完成後,由此判斷,問題有較大可能是發生在 /etc/pam.d/sshd 定義的PAM過程中。

motd
檢視/etc/pam.d/sshd檔案,根據現象以及直覺,決定嘗試先遮蔽幾段配置,其中就包括motd行,motd(message of the day)是Ubuntu登入後呈現給使用者看到的部分banner內容。隨後重啟主機,發現ssh登入變快,不再卡住。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

查閱資料可知,motd機制下,pam_motd.so會依次執行 /etc/update-motd.d/ 目錄下的全部指令碼,而這些指令碼的輸出則會被拼湊輸出到檔案/run/motd.dynamic中,最終呈現在banner中。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

因此,懷疑是這些指令碼的執行過程中產生的卡頓,閱讀這些指令碼,執行斷點echo 除錯,最後發現,位於”50-landscape-sysinfo"指令碼中的“/usr/bin/landscape-sysinfo"命令執行時就會造成卡頓。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

landscape-sysinfo
該命令僅僅是一個用來蒐集顯示banner中系統資源使用情況的工具,出現此問題有點難以置信,可實際上登入進入後多次執行此命令也沒有出現卡頓。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

嘗試進一步追蹤此命令的執行,使用strace追蹤此命令的執行,並記錄日誌。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

分析日誌可以發現,啟動時,該命令被卡在了getrandom系統呼叫上,解除阻塞時間點為 23:10:48。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

getrandom
getrandom封裝了對 /dev/urandom 字元裝置檔案的讀取操作,用於獲取高質量的隨機數,/dev/urandom 會以/dev/random 的值做為seed參考,/dev/random 值則來自硬體執行的噪音(隨機質量很高)。這種機制也決定了/dev/urandom在作業系統剛啟動時生成的隨機數質量不高(剛啟動,/dev/random中噪音不足,生成慢,隨機性差,容易被預測,間接導致了/dev/urandom的起始seed質量低下),所以 /dev/urandom 內部對其質量設定了三種狀態:
  • 0=未初始化,但是/dev/urandom已經可用;

  • 1=快速初始化,使用了少量熵數進行了快速初始化,在剛啟動時就儘快可以被用起來,質量還行,但是仍然不被建議用於加密場景,通常發生在作業系統啟動後的幾秒內;

  • 2=完全初始化,隨機數的質量達到最高,可以用於加密場景,作業系統啟動後約幾十秒-幾分鐘的時間才能達到。

在預設情況下,getrandom讀取/dev/urandom前會去檢測 /dev/urandom 的質量狀態,如果尚未完全初始化,則會阻塞,直到其完全初始化,以此來保障透過此介面獲得到的隨機數質量高且速度快,為安全領域提供可靠的依賴。

瞭解了getrandom介面的作用和表現後,再去翻看核心的啟動日誌,找到了時間相關性極高的點。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

可以看到,23:10:48時 /dev/urandom 完全初始化後,隨即getrandom的呼叫阻塞也被解除了,再多次重複驗證後,關聯性被確認。此時的結論以及建議解決辦法為:
原因:作業系統初始化隨機數熵池速度較慢,導致ssh登入時使用到隨機數的一條命令時被阻塞。
建議:禁用motd或者刪除landscape-sysinfo來達到加速ssh登入的目的。

2

深入調查

初步調查的結論有點違反常理,禁用或者刪除的措施也需謹慎。為此,我決定找出更多的證據,此外,也需要解釋為什麼舊版本的Ubuntu並沒有此現象。

嘗試檢視錶現正常的主機上 landscape-sysinfo 的 strace 表現,查閱日誌後注意到,此環境下的strace記錄與問題主機中strace記錄在呼叫模式上存在不同,表現正常的主機上landscape-sysinfo中沒有這樣的呼叫“getrandom("xxx", 32, 0) ”,注意第三個flag引數值,此flag用於表明使用getrandom的預設行為,即/dev/urandom未完全初始化時則阻塞。所有getrandom的地方都使用了flag GRND_NONBLOCK,即如果沒有初始化完成不要阻塞,返回錯誤就好。
至此,懷疑是landscape-sysinfo版本問題。
landscape-sysinfo
對比兩臺主機上的landscape-sysinfo版本,發現版本號確實不同,有問題的版本號較高,沒問題的版本號較低。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

由Linux核心bug引起SSH登入緩慢問題的排查與解決

將沒問題的主機執行apt-get update & apt-get upgrade,升級後發現問題果然重現。得出臨時結論:landscape-sysinfo新版本使用了getrandom的阻塞模式獲取隨機數,不要升級landscape-sysinfo的版本即可。
開始嘗試在其它主機上進行復現和驗證,卻發現,在另一個高核心版本的映象中,低版本的landscape-sysinfo也能復現此問題,strace追蹤呼叫,發現其呼叫行為與高版本的landscape-sysinfo表現相似,鑑於此命令實際上是python3指令碼,懷疑是其依賴的庫升級導致。檢查apt-get upgrade升級的package,找出與隨機數關聯度較大的幾個包,幾次排除嘗試後,定位發現,其實是由於libssl1.1這個庫的升級導致的問題,getrandom的呼叫也是源自於libssl1.1。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

由Linux核心bug引起SSH登入緩慢問題的排查與解決

libssl1.1
翻閱 。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

可以看到,的確,libssl1.1.1的升級,重寫了內部隨機數的生成器,也符合前面的表現,更新為使用getrandom讀取更加安全的隨機數(代價是剛開機時使用就容易被阻塞)。
繼續嘗試在其它主機上進行復現和驗證,又發現,在某個低核心版本的Ubuntu主機上,安裝的正是libssl1.1.1,卻不能復現問題。按照預期,libssl1.1.1的升級就是為了更安全,而如果一開機就能立刻得到隨機數,這根本就違背的getrandom介面的設計初衷,此時傾向於懷疑核心可能存在bug。
核心bug
以libssl呼叫getrandom被阻塞為關鍵主題查閱資料,最終找到相關性較強的資料,其中CRNG指密碼學強度的隨機數發生器。
根據此資料,證實了核心bug的猜測,核心在4.16時修正過這樣一個bug:getrandom在快速初始化完成後就不再阻塞,這與getrandom的介面設計違背,容易造成安全問題(CVE-2018-1108)

由Linux核心bug引起SSH登入緩慢問題的排查與解決

驗證主機的核心版本為4.15.0,與此情況符合,即很有可能是bug沒有被修復,此時,開始嘗試升級低核心版本主機的核心版本,如果此猜測正確,那麼升級到高版本後應當同樣會發生卡頓問題。
在apt源上挑選了一個5.0版本的核心,升級後發現,居然也沒有問題。
翻閱核心日誌,發現了一個新的現象,此前看到對於/dev/urandom的初始化,一般是會有一條“fast init done”日誌,較長時間後會跟隨一個“crng init done”日誌,正好對應著/dev/urandom的兩種質量狀態。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

由Linux核心bug引起SSH登入緩慢問題的排查與解決

而此核心版本下,則是在剛啟動就立即出現了“crng done (trusting CPU's manufacturer) ”的日誌,明顯表明熵池被極速的初始化了,自然不會出現卡頓問題。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

查詢此現象相關資料,找到了一個核心編譯選項:CONFIG_RANDOM_TRUST_CPU。

CONFIG_RANDOM_TRUST_CPU
此選項透過參考x86指令集中的RDRAND來初始化隨機數熵池,以此達到讓getrandom不再blocking的目的,前提是需要操作者信任CPU製造商。RDRAND指令由Intel在IVB世代中首次引入x86中,AMD在2015年6月時跟進,由於此指令並非標準指令,因此作業系統使用前需要做額外的功能檢測。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

首次出現於4.19版本:
檢查高版本核心的兩臺主機,的確,有問題的主機此flag並沒有enable,無問題的主機此flag顯式的enable了。

由Linux核心bug引起SSH登入緩慢問題的排查與解決

由Linux核心bug引起SSH登入緩慢問題的排查與解決

而有問題主機使用的核心版本,取自於Ubuntu官方的最新主線分支編譯,預設沒有啟動此flag做最佳化。
結論
此問題的出現需要同時滿足以下幾個條件:
1. linux核心版本在4.17及以上
2. linux核心編譯選項 CONFIG_RANDOM_TRUST_CPU is not set,或者CPU非IVB及以上的x86
3. linux核心bug未被社群revert(4.x的最新社群版本幾乎都被revert,5.x沒有
4. libssl版本在1.1.1及以上
影響面
事實上,SSH登入卡頓僅僅是一種表象,這個問題的真實影響範圍,可以擴充套件得非常大。凡是使用了libssl1.1.1來生成隨機數的程式全都會受影響,導致重啟後3-5分鐘內會被隨機數block。比如,伺服器上跑著nginx(開啟https),一般認為機器啟動後,nginx馬上啟動就能提供服務了,但是受此問題影響,nginx會被卡住三五分鐘。就是說,前三五分鐘內的使用者https請求全部會出現訪問失敗的現象。
問題修復

為了做到效能與安全兼顧,在編譯4.19及更高版本的核心時,啟用CONFIG_RANDOM_TRUST_CPU選項,我們採用此方法,enable選項並確保虛擬機器可以訪問RDRAND指令集,很快重新發布了雲主機映象。如果使用者使用自定義核心,應儘量避開4.17-4.19之間的版本,或者妥善處理好CVE-2018-1108。

3

總結

提起雲主機,首先會想到計算、儲存、網路,甚少有人關注核心。然而,核心構建也是雲主機的核心工作,對效能和穩定性至關重要。

SSH登入緩慢起初是單一使用者的反饋,且限於Ubuntu啟動後的首次登入,但透過堅持排查和順藤摸瓜,我們發現了潛在的影響面並予以修復,防患於未然。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69908602/viewspace-2667345/,如需轉載,請註明出處,否則將追究法律責任。

相關文章