]> granicus.if.org Git - sudo/commitdiff
Activate the sigevents inside the signal pipe callback itself
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 12 May 2017 16:02:17 +0000 (10:02 -0600)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 12 May 2017 16:02:17 +0000 (10:02 -0600)
and call signal_pipe_cb() directly if the backend returns EINTR
and the signal_caught flag is set.  This has the side effect of
processing signal events in the current pass of the event loop
instead of the next one.

lib/util/event.c

index aa89d6f681cf729a2554fbbf05fb35aac854ec59..7e7add75f9fae6478a35df10b841a15f9100d6bc 100644 (file)
@@ -86,20 +86,15 @@ sudo_ev_deactivate_all(struct sudo_event_base *base)
 /*
  * Activate all signal events for which the corresponding signal_pending[]
  * flag is set.
- * Returns true if at least one sigevent has been activated.
  */
-static bool
+static void
 sudo_ev_activate_sigevents(struct sudo_event_base *base)
 {
     struct sudo_event *ev;
     sigset_t set, oset;
-    bool ret = false;
     int i;
     debug_decl(sudo_ev_activate_sigevents, SUDO_DEBUG_EVENT)
 
-    if (base->signal_caught == 0)
-       debug_return_bool(false);
-
     /*
      * We treat this as a critical section since the signal handler
      * could modify the siginfo[] entry.
@@ -126,12 +121,11 @@ sudo_ev_activate_sigevents(struct sudo_event_base *base)
            ev->revents = ev->events & (SUDO_EV_SIGNAL|SUDO_EV_SIGINFO);
            TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
            SET(ev->flags, SUDO_EVQ_ACTIVE);
-           ret = true;
        }
     }
     sigprocmask(SIG_SETMASK, &oset, NULL);
 
-    debug_return_bool(ret);
+    debug_return;
 }
 
 /*
@@ -140,15 +134,29 @@ sudo_ev_activate_sigevents(struct sudo_event_base *base)
 static void
 signal_pipe_cb(int fd, int what, void *v)
 {
+    struct sudo_event_base *base = v;
     unsigned char ch;
+    ssize_t nread;
+    debug_decl(signal_pipe_cb, SUDO_DEBUG_EVENT)
 
     /*
      * Drain signal_pipe, the signal handler updated base->signals_pending.
      * Actual processing of signal events is done when poll/select is
      * interrupted by a signal.
      */
-    while (read(fd, &ch, 1) > 0)
-       continue;
+    while ((nread = read(fd, &ch, 1)) > 0) {
+       sudo_debug_printf(SUDO_DEBUG_INFO,
+           "%s: received signal %d", __func__, (int)ch);
+    }
+    if (nread == -1 && errno != EAGAIN) {
+       sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
+           "%s: error reading from signal pipe", __func__);
+    }
+
+    /* Activate signal events. */
+    sudo_ev_activate_sigevents(base);
+
+    debug_return;
 }
 
 struct sudo_event_base *
@@ -179,7 +187,7 @@ sudo_ev_base_alloc_v1(void)
        goto bad;
     }
     sudo_ev_init(&base->signal_event, base->signal_pipe[1],
-       SUDO_EV_READ|SUDO_EV_PERSIST, signal_pipe_cb, NULL);
+       SUDO_EV_READ|SUDO_EV_PERSIST, signal_pipe_cb, base);
 
     debug_return_ptr(base);
 bad:
@@ -306,10 +314,7 @@ sudo_ev_handler(int signo, siginfo_t *info, void *context)
        signal_base->signal_caught = 1;
 
        /* Wake up the other end of the pipe. */
-       while (write(signal_base->signal_pipe[0], &ch, 1) == -1) {
-           if (errno != EINTR)
-               break;
-       }
+       ignore_result(write(signal_base->signal_pipe[0], &ch, 1));
     }
 }
 
@@ -586,8 +591,10 @@ rescan:
                continue;
            if (errno == EINTR) {
                /* Interrupted by signal, check for sigevents. */
-               if (sudo_ev_activate_sigevents(base))
+               if (base->signal_caught) {
+                   signal_pipe_cb(base->signal_pipe[1], SUDO_EV_READ, base);
                    break;
+               }
                continue;
            }
            rc = -1;
@@ -617,9 +624,6 @@ rescan:
            break;
        }
 
-       /* Activate signal events, if any. */
-       sudo_ev_activate_sigevents(base);
-
        /*
         * Service each event in the active queue.
         * We store the current event pointer in the base so that