From: Roy Marples Date: Tue, 2 Jun 2020 14:50:17 +0000 (+0100) Subject: privsep: harden process handling X-Git-Tag: v9.1.1~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=828e858d3d7bbdb82bec7cd56616795426861783;p=thirdparty%2Fdhcpcd.git privsep: harden process handling 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. --- diff --git a/src/eloop.c b/src/eloop.c index dfa79496..2a67982e 100644 --- a/src/eloop.c +++ b/src/eloop.c @@ -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; diff --git a/src/eloop.h b/src/eloop.h index e5d881a1..40a1b2ff 100644 --- a/src/eloop.h +++ b/src/eloop.h @@ -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 diff --git a/src/privsep-root.c b/src/privsep-root.c index 04e19742..4f963d31 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -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; } diff --git a/src/privsep.c b/src/privsep.c index d35b2be0..d4fdac1e 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -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; }