摘要:宋體快杰云主機是推出的具備優(yōu)秀性能與極高性價比的新一代主機,網(wǎng)絡(luò)最高可達(dá)萬,存儲最高可達(dá)萬。宋體最終我們通過升級自主維護的內(nèi)核,很快妥善修復(fù)了該問題,保證了快杰云主機的體驗和安全性。
快杰云主機是 UCloud 推出的具備優(yōu)秀性能與極高性價比的新一代主機,網(wǎng)絡(luò)最高可達(dá) 1000 萬 PPS,存儲最高可達(dá) 120 萬 IOPS。為了提升產(chǎn)品綜合表現(xiàn),Host 內(nèi)核、KVM 和 Guest 內(nèi)核等做了大量調(diào)優(yōu)。“高內(nèi)核 Ubuntu18.04” 鏡像就是其中一款經(jīng)優(yōu)化的云主機鏡像,集成了官方 linux 5.0.1 主線版本內(nèi)核。
今年 7 月,有一位用戶反饋,使用該鏡像創(chuàng)建出的快杰云主機每次啟動時,第一次 SSH 登錄會很慢,有時候需幾十秒甚至幾分鐘才能登錄成功,影響了使用體驗。
經(jīng)過排查,定位到是 Linux 內(nèi)核隨機數(shù)熵池初始化慢的原因,且在多個條件組合下才會觸發(fā)。更深入調(diào)查則發(fā)現(xiàn)因為內(nèi)核 bug,凡使用了 libssl 1.1.1 的進程(如開啟了 https 的 nginx)都有類似問題,會對系統(tǒng)安全產(chǎn)生不少潛在影響。
最終我們通過升級自主維護的內(nèi)核,很快妥善修復(fù)了該問題,保證了快杰云主機的體驗和安全性。
本文對排查過程加以梳理。
初步排查
該問題只在單個用戶上出現(xiàn)過,且只影響啟動后的首次 SSH 登錄,一旦登錄成功便恢復(fù)正常?,F(xiàn)場捕獲不易,不過我們設(shè)法將其復(fù)現(xiàn)。
ssh -v
打開 ssh 用戶端的冗余日志模式嘗試登錄問題主機,發(fā)現(xiàn)總是會卡在 “debug1: pledge: network” 處,根據(jù)提示,sshd 已經(jīng)完成了用戶的身份認(rèn)證過程。
可以看出,問題應(yīng)當(dāng)是發(fā)生在身份鑒定剛完成后,由此判斷,問題有較大可能是發(fā)生在 /etc/pam.d/sshd 定義的 PAM 過程中。
motd
檢視 /etc/pam.d/sshd 文件,根據(jù)現(xiàn)象以及直覺,決定嘗試先屏蔽幾段配置,其中就包括 motd 行,motd (message of the day) 是 Ubuntu 登錄后呈現(xiàn)給用戶看到的部分 banner 內(nèi)容。隨后重啟主機,發(fā)現(xiàn) ssh 登錄變快,不再卡住。
查閱資料可知,motd 機制下,pam_motd.so 會依次執(zhí)行 /etc/update-motd.d/ 目錄下的全部腳本,而這些腳本的輸出則會被拼湊輸出到文件 /run/motd.dynamic 中,最終呈現(xiàn)在 banner 中。
因此,懷疑是這些腳本的執(zhí)行過程中產(chǎn)生的卡頓,閱讀這些腳本,執(zhí)行斷點 echo 調(diào)試,最后發(fā)現(xiàn),位于”50-landscape-sysinfo”腳本中的 “/usr/bin/landscape-sysinfo” 命令執(zhí)行時就會造成卡頓。
landscape-sysinfo
該命令僅僅是一個用來搜集顯示 banner 中系統(tǒng)資源使用情況的工具,出現(xiàn)此問題有點難以置信,可實際上登錄進入后多次執(zhí)行此命令也沒有出現(xiàn)卡頓。
嘗試進一步追蹤此命令的執(zhí)行,使用 strace 追蹤此命令的執(zhí)行,并記錄日志。
分析日志可以發(fā)現(xiàn),啟動時,該命令被卡在了 getrandom 系統(tǒng)調(diào)用上,解除阻塞時間點為 23:10:48。
getrandom
點擊查看參考資料?http://man7.org/linux/man-pages/man2/getrandom.2.html
getrandom 封裝了對 /dev/urandom 字符設(shè)備文件的讀取操作,用于獲取高質(zhì)量的隨機數(shù),/dev/urandom 會以 /dev/random 的值做為 seed 參考,/dev/random 值則來自硬件運行的噪音 (隨機質(zhì)量很高)。這種機制也決定了 /dev/urandom 在操作系統(tǒng)剛啟動時生成的隨機數(shù)質(zhì)量不高(剛啟動,/dev/random 中噪音不足,生成慢,隨機性差,容易被預(yù)測,間接導(dǎo)致了 /dev/urandom 的起始 seed 質(zhì)量低下),所以 /dev/urandom 內(nèi)部對其質(zhì)量設(shè)置了三種狀態(tài):
- 0 = 未初始化,但是 /dev/urandom 已經(jīng)可用;
- 1 = 快速初始化,使用了少量熵數(shù)進行了快速初始化,在剛啟動時就盡快可以被用起來,質(zhì)量還行,但是仍然不被建議用于加密場景,通常發(fā)生在操作系統(tǒng)啟動后的幾秒內(nèi);
- 2 = 完全初始化,隨機數(shù)的質(zhì)量達(dá)到最高,可以用于加密場景,操作系統(tǒng)啟動后約幾十秒 – 幾分鐘的時間才能達(dá)到。
在默認(rèn)情況下,getrandom 讀取 /dev/urandom 前會去檢測 /dev/urandom 的質(zhì)量狀態(tài),如果尚未完全初始化,則會阻塞,直到其完全初始化,以此來保障通過此接口獲得到的隨機數(shù)質(zhì)量高且速度快,為安全領(lǐng)域提供可靠的依賴。
了解了 getrandom 接口的作用和表現(xiàn)后,再去翻看內(nèi)核的啟動日志,找到了時間相關(guān)性極高的點。
可以看到,23:10:48 時 /dev/urandom 完全初始化后,隨即 getrandom 的調(diào)用阻塞也被解除了,再多次重復(fù)驗證后,關(guān)聯(lián)性被確認(rèn)。此時的結(jié)論以及建議解決辦法為:原因:操作系統(tǒng)初始化隨機數(shù)熵池速度較慢,導(dǎo)致 ssh 登錄時使用到隨機數(shù)的一條命令時被阻塞。
建議:禁用 motd 或者刪除 landscape-sysinfo 來達(dá)到加速 ssh 登錄的目的。
深入調(diào)查
初步調(diào)查的結(jié)論有點違反常理,禁用或者刪除的措施也需謹(jǐn)慎。為此,我決定找出更多的證據(jù),此外,也需要解釋為什么舊版本的 Ubuntu 并沒有此現(xiàn)象。
嘗試查看表現(xiàn)正常的主機上 landscape-sysinfo 的 strace 表現(xiàn),查閱日志后注意到,此環(huán)境下的 strace 記錄與問題主機中 strace 記錄在調(diào)用模式上存在不同,表現(xiàn)正常的主機上 landscape-sysinfo 中沒有這樣的調(diào)用 “getrandom (“xxx”, 32, 0) ”,注意第三個 flag 參數(shù)值,此 flag 用于表明使用 getrandom 的默認(rèn)行為,即 /dev/urandom 未完全初始化時則阻塞。所有 getrandom 的地方都使用了 flag GRND_NONBLOCK,即如果沒有初始化完成不要阻塞,返回錯誤就好。
至此,懷疑是 landscape-sysinfo 版本問題。
landscape-sysinfo
對比兩臺主機上的 landscape-sysinfo 版本,發(fā)現(xiàn)版本號確實不同,有問題的版本號較高,沒問題的版本號較低。
將沒問題的主機執(zhí)行 apt-get update & apt-get upgrade,升級后發(fā)現(xiàn)問題果然重現(xiàn)。得出臨時結(jié)論:landscape-sysinfo 新版本使用了 getrandom 的阻塞模式獲取隨機數(shù),不要升級 landscape-sysinfo 的版本即可。
開始嘗試在其它主機上進行復(fù)現(xiàn)和驗證,卻發(fā)現(xiàn),在另一個高內(nèi)核版本的鏡像中,低版本的 landscape-sysinfo 也能復(fù)現(xiàn)此問題,strace 追蹤調(diào)用,發(fā)現(xiàn)其調(diào)用行為與高版本的 landscape-sysinfo 表現(xiàn)相似,鑒于此命令實際上是 python3 腳本,懷疑是其依賴的庫升級導(dǎo)致。檢查 apt-get upgrade 升級的 package,找出與隨機數(shù)關(guān)聯(lián)度較大的幾個包,幾次排除嘗試后,定位發(fā)現(xiàn),其實是由于 libssl1.1 這個庫的升級導(dǎo)致的問題,getrandom 的調(diào)用也是源自于 libssl1.1。
libssl1.1
翻閱
libssl1.1 的 release note?https://www.openssl.org/news/openssl-1.1.1-notes.html
。
可以看到,的確,libssl1.1.1 的升級,重寫了內(nèi)部隨機數(shù)的生成器,也符合前面的表現(xiàn),更新為使用 getrandom 讀取更加安全的隨機數(shù)(代價是剛開機時使用就容易被阻塞)。
繼續(xù)嘗試在其它主機上進行復(fù)現(xiàn)和驗證,又發(fā)現(xiàn),在某個低內(nèi)核版本的 Ubuntu 主機上,安裝的正是 libssl1.1.1,卻不能復(fù)現(xiàn)問題。按照預(yù)期,libssl1.1.1 的升級就是為了更安全,而如果一開機就能立刻得到隨機數(shù),這根本就違背的 getrandom 接口的設(shè)計初衷,此時傾向于懷疑內(nèi)核可能存在 bug。
內(nèi)核 bug
以 libssl 調(diào)用 getrandom 被阻塞為關(guān)鍵主題查閱資料,最終找到相關(guān)性較強的資料
點擊查看相關(guān)資料?https://unix.stackexchange.com/questions/442698/when-i-log-in-it-hangs-until-crng-init-done
,其中 CRNG 指密碼學(xué)強度的隨機數(shù)發(fā)生器。
根據(jù)此資料,證實了內(nèi)核 bug 的猜測,內(nèi)核在 4.16 時修正過這樣一個 bug:getrandom 在快速初始化完成后就不再阻塞,這與 getrandom 的接口設(shè)計違背,容易造成安全問題(CVE-2018-1108)
內(nèi)核 bug fix commit?https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=43838a23a05fbd13e47d750d3dfd77001536dd33
驗證主機的內(nèi)核版本為 4.15.0,與此情況符合,即很有可能是 bug 沒有被修復(fù),此時,開始嘗試升級低內(nèi)核版本主機的內(nèi)核版本,如果此猜測正確,那么升級到高版本后應(yīng)當(dāng)同樣會發(fā)生卡頓問題。
在 apt 源上挑選了一個 5.0 版本的內(nèi)核,升級后發(fā)現(xiàn),居然也沒有問題。
翻閱內(nèi)核日志,發(fā)現(xiàn)了一個新的現(xiàn)象,此前看到對于 /dev/urandom 的初始化,一般是會有一條 “fast init done” 日志,較長時間后會跟隨一個 “crng init done” 日志,正好對應(yīng)著 /dev/urandom 的兩種質(zhì)量狀態(tài)。
而此內(nèi)核版本下,則是在剛啟動就立即出現(xiàn)了 “crng done (trusting CPU’s manufacturer) ” 的日志,明顯表明熵池被極速的初始化了,自然不會出現(xiàn)卡頓問題。
查詢此現(xiàn)象相關(guān)資料,找到了一個內(nèi)核編譯選項:CONFIG_RANDOM_TRUST_CPU。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/117597.html