]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Avoid a potential malloc when handling signals.
authorRoy Marples <roy@marples.name>
Tue, 26 Mar 2013 08:51:34 +0000 (08:51 +0000)
committerRoy Marples <roy@marples.name>
Tue, 26 Mar 2013 08:51:34 +0000 (08:51 +0000)
dhcpcd.c
eloop.c
eloop.h

index b4724c2041c5fb9840fe6d4e6bd3530a9ebb92bb..f7f782d3fa75a219c6acb5bb3653b2be61cb1f2c 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -666,6 +666,16 @@ sig_reboot(_unused void *arg)
        reconf_reboot(1, ifc, ifv, 0);
 }
 
+static void
+sig_reconf(_unused void *arg)
+{
+       struct interface *ifp;
+
+       TAILQ_FOREACH(ifp, ifaces, next) {
+               ipv4_applyaddr(ifp);
+       }
+}
+
 void
 handle_signal(int sig)
 {
@@ -685,7 +695,7 @@ handle_signal(int sig)
                /* We shouldn't modify any variables in the signal
                 * handler, so simply add reboot function to the queue
                 * for an immediate callout. */
-               eloop_timeout_add_sec(0, sig_reboot, NULL);
+               eloop_timeout_add_now(sig_reboot, NULL);
                return;
        case SIGHUP:
                syslog(LOG_INFO, "received SIGHUP, releasing");
@@ -693,9 +703,7 @@ handle_signal(int sig)
                break;
        case SIGUSR1:
                syslog(LOG_INFO, "received SIGUSR, reconfiguring");
-               TAILQ_FOREACH(ifp, ifaces, next) {
-                       ipv4_applyaddr(ifp);
-               }
+               eloop_timeout_add_now(sig_reconf, NULL);
                return;
        case SIGPIPE:
                syslog(LOG_WARNING, "received SIGPIPE");
diff --git a/eloop.c b/eloop.c
index 7b911d9dce56b609f0e0cf521ed70f26ce83b1ca..0c220533f1ed5626c55227ef10e8dbdc4bf59f3b 100644 (file)
--- a/eloop.c
+++ b/eloop.c
@@ -68,6 +68,9 @@ static TAILQ_HEAD (timeout_head, timeout) timeouts
 static struct timeout_head free_timeouts
     = TAILQ_HEAD_INITIALIZER(free_timeouts);
 
+static void (*volatile timeout0)(void *);
+static void *volatile timeout0_arg;
+
 static struct pollfd *fds;
 static size_t fds_len;
 
@@ -215,6 +218,20 @@ eloop_q_timeout_add_sec(int queue, time_t when,
        return eloop_q_timeout_add_tv(queue, &tv, callback, arg);
 }
 
+int
+eloop_timeout_add_now(void (*callback)(void *), void *arg)
+{
+
+       if (timeout0 != NULL) {
+               syslog(LOG_WARNING, "%s: timeout0 already set", __func__);
+               return eloop_q_timeout_add_sec(0, 0, callback, arg);
+       }
+
+       timeout0 = callback;
+       timeout0_arg = arg;
+       return 0;
+}
+
 /* This deletes all timeouts for the interface EXCEPT for ones with the
  * callbacks given. Handy for deleting everything apart from the expire
  * timeout. */
@@ -314,9 +331,16 @@ eloop_start(const sigset_t *sigmask)
        struct timeout *t;
        struct timeval tv;
        struct timespec ts, *tsp;
+       void (*t0)(void *);
 
        for (;;) {
                /* Run all timeouts first */
+               if (timeout0) {
+                       t0 = timeout0;
+                       timeout0 = NULL;
+                       t0(timeout0_arg);
+                       continue;
+               }
                if ((t = TAILQ_FIRST(&timeouts))) {
                        get_monotonic(&now);
                        if (timercmp(&now, &t->when, >)) {
diff --git a/eloop.h b/eloop.h
index e0cb0e44ac6a83d43aa8c210c0128e10965f0e08..8a18d9c57aed10bd5910bf9377fe204e8de3ff94 100644 (file)
--- a/eloop.h
+++ b/eloop.h
@@ -49,6 +49,7 @@ void eloop_event_delete(int fd);
 int eloop_q_timeout_add_sec(int queue, time_t, void (*)(void *), void *);
 int eloop_q_timeout_add_tv(int queue, const struct timeval *, void (*)(void *),
     void *);
+int eloop_timeout_add_now(void (*)(void *), void *);
 void eloop_q_timeout_delete(int, void (*)(void *), void *);
 void eloop_q_timeouts_delete(int, void *, void (*)(void *), ...);
 void eloop_init(void);