gnupg 2.1.16 塊等待熵
從 2.1.16(目前為 2.1.17)發布的gnupg僅在第一次呼叫時才阻塞等待熵。
注意:這不是嘗試生成密鑰,只是為了解密文件並啟動代理。
第一次啟動 gpg-agent 時,無論是直接使用
gpg2 file.gpg
還是使用類似的應用程序pass
,都會出現 pinentry,一旦我輸入密碼並點擊Enter
它,它就會掛起大約 15 秒。所有後續呼叫,在 default-cache-ttl 的視窗內,都會立即執行。
在
--debug-all
模式下執行,發生掛起的時間段列印1:gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120 gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120 gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120 gpg: DBG: chan_6 <- S PROGRESS need_entropy X 120 120 gpg: DBG: chan_6 <- S PROGRESS need_entropy X 30 120 ...
我安裝了rng-tools來補充熵池:
cat /proc/sys/kernel/random/entropy_avail 4094
與沒有安裝 rng-tools 或haveged的具有相同版本 gnupg 的機器相比,沒有延遲:
cat /proc/sys/kernel/random/entropy_avail 3783
因此,池中似乎有足夠的熵。這是在核心 4.8.13 和 4.9 上測試的。
gpg 是否使用不同的池?如何提供足夠的熵,或者以其他方式消除啟動代理時的 15 秒延遲?
1.完整的調試日誌。
我想我知道發生了什麼。在 gnupg 的 agent/gpg-agent.c 中,這個函式處理來自 libgcrypt 的消息。
/* This is our callback function for gcrypt progress messages. It is set once at startup and dispatches progress messages to the corresponding threads of the agent. */ static void agent_libgcrypt_progress_cb (void *data, const char *what, int printchar, int current, int total) { struct progress_dispatch_s *dispatch; npth_t mytid = npth_self (); (void)data; for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next) if (dispatch->ctrl && dispatch->tid == mytid) break; if (dispatch && dispatch->cb) dispatch->cb (dispatch->ctrl, what, printchar, current, total); /* Libgcrypt < 1.8 does not know about nPth and thus when it reads * from /dev/random this will block the process. To mitigate this * problem we take a short nap when Libgcrypt tells us that it needs * more entropy. This way other threads have chance to run. */ #if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */ if (what && !strcmp (what, "need_entropy")) npth_usleep (100000); /* 100ms */ #endif }
帶有 npth_usleep 的最後一部分是在 2.1.15 和 2.1.17 之間添加的。由於如果 libgcrypt 早於 1.8.0,這是有條件的編譯,直接的修復將是針對 libgcrypt 1.8.0 或更高版本重新編譯 gnupg……不幸的是,該版本似乎還不存在。
奇怪的是,關於 libgcrypt 讀取 /dev/random 的評論是不正確的。跟踪代理顯示它正在從 /dev/urandom 讀取並使用新的 getrandom(2) 系統呼叫,沒有阻塞。然而,它確實發送了許多 need_entropy 消息,導致 npth_usleep 阻塞。刪除這些行可以解決問題。
我應該提一下,npth 似乎是某種協作多任務庫,而 npth_usleep 可能是它的屈服方式,因此最好顯著減少延遲,以防萬一 libgcrypt 決定有一天阻塞。(1ms 不明顯)