]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: harden process handling
authorRoy Marples <roy@marples.name>
Tue, 2 Jun 2020 14:50:17 +0000 (15:50 +0100)
committerRoy Marples <roy@marples.name>
Tue, 2 Jun 2020 14:50:17 +0000 (15:50 +0100)
If eloop is exited, only allow explicit re-entry.
Only exit on read/write error if a forked process and not root.
If the root process fails to read/write to a sub-process,
stop the sub-process.

src/eloop.c
src/eloop.h
src/privsep-root.c
src/privsep.c

index dfa794966e415d7e7e7d9e64bbf80287732bae50..2a67982ef1db9d6fc17c5ce1cf17c5883cf5967b 100644 (file)
@@ -727,6 +727,13 @@ eloop_exit(struct eloop *eloop, int code)
        eloop->exitnow = 1;
 }
 
+void
+eloop_enter(struct eloop *eloop)
+{
+
+       eloop->exitnow = 0;
+}
+
 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
 static int
 eloop_open(struct eloop *eloop)
@@ -1010,7 +1017,6 @@ eloop_start(struct eloop *eloop, sigset_t *signals)
 
        assert(eloop != NULL);
 
-       eloop->exitnow = 0;
        for (;;) {
                if (eloop->exitnow)
                        break;
index e5d881a1670d97e908e3108ebab56d6155196830..40a1b2ffc18550eb50ec12cb4d55fbb4eaf96b13 100644 (file)
@@ -92,6 +92,7 @@ int eloop_requeue(struct eloop *);
 void eloop_clear(struct eloop *);
 void eloop_free(struct eloop *);
 void eloop_exit(struct eloop *, int);
+void eloop_enter(struct eloop *);
 int eloop_start(struct eloop *, sigset_t *);
 
 #endif
index 04e197423856e869bc08fd68eb02c77340925712..4f963d3170830c9b6d3897205a03c3f053597db3 100644 (file)
@@ -124,6 +124,7 @@ ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len)
            ps_root_readerrorcb, &psr_ctx) == -1)
                return -1;
 
+       eloop_enter(ctx->ps_eloop);
        eloop_start(ctx->ps_eloop, &ctx->sigset);
 
        errno = psr_ctx.psr_error.psr_errno;
@@ -181,6 +182,7 @@ ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
            ps_root_mreaderrorcb, &psr_ctx) == -1)
                return -1;
 
+       eloop_enter(ctx->ps_eloop);
        eloop_start(ctx->ps_eloop, &ctx->sigset);
 
        errno = psr_ctx.psr_error.psr_errno;
@@ -446,9 +448,21 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 
                        ps_freeprocess(psp);
                        return ret;
-               } else if (!(psm->ps_cmd & PS_START))
-                       return ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
-               /* Process has already started .... */
+               } else if (psm->ps_cmd & PS_START) {
+                       /* Process has already started .... */
+                       return 0;
+               }
+
+               err = ps_sendpsmmsg(ctx, psp->psp_fd, psm, msg);
+               if (err == -1) {
+                       logerr("%s: failed to send message to pid %d",
+                           __func__, psp->psp_pid);
+                       shutdown(psp->psp_fd, SHUT_RDWR);
+                       close(psp->psp_fd);
+                       psp->psp_fd = -1;
+                       ps_dostop(ctx, &psp->psp_pid, &psp->psp_fd);
+                       ps_freeprocess(psp);
+               }
                return 0;
        }
 
index d35b2be0e99b74f066eb01eea681b00fe03cd159..d4fdac1ef112ef3cb49cf0a4161042f036907e5e 100644 (file)
@@ -288,6 +288,7 @@ errexit:
                (void)ps_sendcmd(ctx, *priv_fd, PS_STOP, 0, NULL, 0);
        shutdown(*priv_fd, SHUT_RDWR);
        *priv_fd = -1;
+       eloop_exit(ctx->eloop, EXIT_FAILURE);
        return -1;
 }
 
@@ -301,6 +302,9 @@ ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd)
 #endif
        if (*pid == 0)
                return 0;
+       if (*fd == -1)
+               goto wait;
+
        eloop_event_delete(ctx->eloop, *fd);
        if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1 &&
            errno != ECONNRESET)
@@ -309,11 +313,8 @@ ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd)
                logerr(__func__);
        close(*fd);
        *fd = -1;
-       /* We won't have permission for all processes .... */
-#if 0
-       if (kill(*pid, SIGTERM) == -1)
-               logerr(__func__);
-#endif
+
+wait:
        status = 0;
 
 #ifdef HAVE_CAPSICUM
@@ -544,7 +545,8 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd,
 #ifdef PRIVSEP_DEBUG
        logdebugx("%s: %zd", __func__, len);
 #endif
-       if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED)
+       if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED &&
+           !(ctx->options & DHCPCD_PRIVSEPROOT))
                eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
        return len;
 }
@@ -687,8 +689,12 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
 #ifdef PRIVSEP_DEBUG
        logdebugx("%s: recv fd %d, %zd bytes", __func__, rfd, len);
 #endif
-       if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED) {
-               eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+
+       if (len == -1 || len == 0) {
+               if (ctx->options & DHCPCD_FORKED &&
+                   !(ctx->options & DHCPCD_PRIVSEPROOT))
+                       eloop_exit(ctx->eloop,
+                           len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
                return len;
        }
 
@@ -697,7 +703,8 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd)
 #ifdef PRIVSEP_DEBUG
        logdebugx("%s: send fd %d, %zu bytes", __func__, wfd, len);
 #endif
-       if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED)
+       if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED &&
+           !(ctx->options & DHCPCD_PRIVSEPROOT))
                eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
        return len;
 }