From: Damien Miller Subject: Re: sshd: mask SIGTERM/SIGQUIT across SIGHUP restart To: tech@openbsd.org Cc: openssh@openssh.com Date: Tue, 15 Sep 2026 20:59:04 +1000 On Tue, 15 Sep 2026, Damien Miller wrote: > 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 > 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); These should of course be osigset commit 17c7dca55648d955c3bf144745da08b24c54bf78 Author: Damien Miller 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..e55bec2 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(&osigset, SIGTERM); + sigdelset(&osigset, SIGQUIT); sigprocmask(SIG_SETMASK, &osigset, NULL); sighup_restart(); }