Download raw body.
sshd: mask SIGTERM/SIGQUIT across SIGHUP restart
Hi,
This is https://bugzilla.mindrot.org/show_bug.cgi?id=3981
sshd restarts on SIGHUP by re-executing itself. If a SIGTERM/SIGQUIT
comes after this has begun then the termination signal can be lost.
The bug contains a description of the sequence:
> 1. SIGHUP is received.
> 2. listener loop checks received_sigterm first; it is not set.
> 3. listener loop enters received_sighup handling.
> 4. listener restores osigset, unblocking SIGTERM.
> 5. SIGTERM arrives.
> 6. sigterm_handler() sets received_sigterm.
> 7. sighup_restart() continues to execv().
> 8. received_sigterm is lost across exec.
> 9. new sshd continues running.
This patch keeps SIGTERM/SIGQUIT masked across such a restart.
The first thing in sshd.c:main() is a sigprocmask(2) call with an
empty signal set, so one of these signals will be delivered then.
ok?
Another alternative might be to reset the handlers for these signals
to SIGDFL, but this seems simpler.
commit 01b5ab90cd89a91dc41a493a017439f0501a8e64
Author: Damien Miller <djm@mindrot.org>
Date: Tue Sep 15 17:49:11 2026 +1000
keep SIGTERM/SIGQUIT masked across SIGHUP restart
Keep these signals masked so they don't get lost across a sshd restart
initiated by SIGHUP. bz3981
Note, the first thing sshd does in main() is clear the sigprocmask.
diff --git a/sshd.c b/sshd.c
index a568091..65d21fb 100644
--- a/sshd.c
+++ b/sshd.c
@@ -964,6 +964,12 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
lameduck = 1;
}
if (listening <= 0) {
+ /*
+ * Leave termination signals blocked, so
+ * they don't get lost across a restart.
+ */
+ sigdelset(&nsigset, SIGTERM);
+ sigdelset(&nsigset, SIGQUIT);
sigprocmask(SIG_SETMASK, &osigset, NULL);
sighup_restart();
}
sshd: mask SIGTERM/SIGQUIT across SIGHUP restart