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