avoid logging in signal handler by converting mainloop to ppoll()
authordjm <djm@openbsd.org>
Sat, 9 Mar 2024 05:12:13 +0000 (05:12 +0000)
committerdjm <djm@openbsd.org>
Sat, 9 Mar 2024 05:12:13 +0000 (05:12 +0000)
bz3670, reported by Ben Hamilton; ok dtucker@

usr.bin/ssh/ssh-agent.c

index 9b7754e..1b4c965 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.305 2024/03/06 00:31:04 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.306 2024/03/09 05:12:13 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -149,6 +149,8 @@ int max_fd = 0;
 pid_t parent_pid = -1;
 time_t parent_alive_interval = 0;
 
+sig_atomic_t signalled = 0;
+
 /* pid of process for which cleanup_socket is applicable */
 pid_t cleanup_pid = 0;
 
@@ -2049,7 +2051,7 @@ after_poll(struct pollfd *pfd, size_t npfd, u_int maxfds)
 }
 
 static int
-prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
+prepare_poll(struct pollfd **pfdp, size_t *npfdp, struct timespec *timeoutp, u_int maxfds)
 {
        struct pollfd *pfd = *pfdp;
        size_t i, j, npfd = 0;
@@ -2115,14 +2117,8 @@ prepare_poll(struct pollfd **pfdp, size_t *npfdp, int *timeoutp, u_int maxfds)
        if (parent_alive_interval != 0)
                deadline = (deadline == 0) ? parent_alive_interval :
                    MINIMUM(deadline, parent_alive_interval);
-       if (deadline == 0) {
-               *timeoutp = -1; /* INFTIM */
-       } else {
-               if (deadline > INT_MAX / 1000)
-                       *timeoutp = INT_MAX / 1000;
-               else
-                       *timeoutp = deadline * 1000;
-       }
+       if (deadline != 0)
+               ptimeout_deadline_sec(timeoutp, deadline);
        return (1);
 }
 
@@ -2142,17 +2138,16 @@ void
 cleanup_exit(int i)
 {
        cleanup_socket();
+#ifdef ENABLE_PKCS11
+       pkcs11_terminate();
+#endif
        _exit(i);
 }
 
 static void
 cleanup_handler(int sig)
 {
-       cleanup_socket();
-#ifdef ENABLE_PKCS11
-       pkcs11_terminate();
-#endif
-       _exit(2);
+       signalled = sig;
 }
 
 static void
@@ -2194,10 +2189,11 @@ main(int ac, char **av)
        char pidstrbuf[1 + 3 * sizeof pid];
        size_t len;
        mode_t prev_mask;
-       int timeout = -1; /* INFTIM */
+       struct timespec timeout;
        struct pollfd *pfd = NULL;
        size_t npfd = 0;
        u_int maxfds;
+       sigset_t nsigset, osigset;
 
        /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
        sanitise_stdfd();
@@ -2428,12 +2424,24 @@ skip:
        ssh_signal(SIGHUP, cleanup_handler);
        ssh_signal(SIGTERM, cleanup_handler);
 
+       sigemptyset(&nsigset);
+       sigaddset(&nsigset, SIGINT);
+       sigaddset(&nsigset, SIGHUP);
+       sigaddset(&nsigset, SIGTERM);
+
        if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1)
                fatal("%s: pledge: %s", __progname, strerror(errno));
 
        while (1) {
+               sigprocmask(SIG_BLOCK, &nsigset, &osigset);
+               if (signalled != 0) {
+                       logit("exiting on signal %d", (int)signalled);
+                       cleanup_exit(2);
+               }
+               ptimeout_init(&timeout);
                prepare_poll(&pfd, &npfd, &timeout, maxfds);
-               result = poll(pfd, npfd, timeout);
+               result = ppoll(pfd, npfd, ptimeout_get_tsp(&timeout), &osigset);
+               sigprocmask(SIG_SETMASK, &osigset, NULL);
                saved_errno = errno;
                if (parent_alive_interval != 0)
                        check_parent_exists();