From 06e534fdd20f9f12aeee02406aa7021d80f1236a Mon Sep 17 00:00:00 2001 From: "peijiankang@kylinos.cn" Date: Wed, 28 Oct 2026 15:58:47 +0800 Subject: [PATCH] Fix timeout race condition in read_from_emacs (CWE-362) The do-while EINTR retry loop in read_from_emacs does not check the timed_out flag. When alarm() fires SIGALRM, catchsig sets timed_out=1, recv() is interrupted returning EINTR, but the do-while retries recv() unconditionally. Since alarm() is a one-shot timer, no further SIGALRM is generated, and recv() blocks forever, making the timeout mechanism completely ineffective. Adding !timed_out to the do-while condition allows distinguishing SIGWINCH (should retry) from SIGALRM (should stop). Also return GPG_ERR_TIMEOUT instead of GPG_ERR_ASS_GENERAL when timed_out is set. Reproduced on openEuler 20.03 LTS-SP4 with /usr/bin/pinentry-emacs: - Before fix: process hangs forever after 60s timeout (recv blocks) - After fix: process returns ERR Timeout after 60s Signed-off-by: peijiankang@kylinos.cn --- pinentry/pinentry-emacs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pinentry/pinentry-emacs.c b/pinentry/pinentry-emacs.c index 7cac4a5..dae55e8 100644 --- a/pinentry/pinentry-emacs.c +++ b/pinentry/pinentry-emacs.c @@ -352,10 +352,12 @@ read_from_emacs (int s, int timeout, char *buffer, size_t capacity) } /* If we receive a signal (e.g. SIGWINCH, which we pass through to Emacs), on some OSes we get EINTR and must retry. */ - while (rl < 0 && errno == EINTR); + while (rl < 0 && errno == EINTR && !timed_out); if (rl < 0) { + if (timed_out) + return gpg_error (GPG_ERR_TIMEOUT); perror ("recv"); return gpg_error (GPG_ERR_ASS_GENERAL);; } -- 2.25.1