From: Roy Marples Date: Sun, 20 Sep 2020 18:09:08 +0000 (+0100) Subject: privsep: sandbox the launcher process X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8b204c618386a2d8fe4a44514824da6f6a462985;p=people%2Fms%2Fdhcpcd.git privsep: sandbox the launcher process --- diff --git a/src/dhcpcd.c b/src/dhcpcd.c index 8fbb6212..83161471 100644 --- a/src/dhcpcd.c +++ b/src/dhcpcd.c @@ -1417,16 +1417,7 @@ dhcpcd_signal_cb(int sig, void *arg) } if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) { - if (sig == SIGHUP) - return; - - pid_t pid = pidfile_read(ctx->pidfile); - if (pid == -1) { - if (errno != ENOENT) - logerr("%s: pidfile_read",__func__); - } else if (pid == 0) - logerr("%s: pid cannot be zero", __func__); - else if (kill(pid, sig) == -1) + if (sig != SIGHUP && kill(ctx->fork_pid, sig) == -1) logerr("%s: kill", __func__); return; } @@ -1769,9 +1760,16 @@ dhcpcd_fork_cb(void *arg) { struct dhcpcd_ctx *ctx = arg; int exit_code; + bool do_exit; ssize_t len; - len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); + if (ctx->fork_pid == 0) { + do_exit = false; + len = read(ctx->fork_fd, &ctx->fork_pid, sizeof(ctx->fork_pid)); + } else { + do_exit = true; + len = read(ctx->fork_fd, &exit_code, sizeof(exit_code)); + } if (len == -1) { logerr(__func__); exit_code = EXIT_FAILURE; @@ -1780,7 +1778,8 @@ dhcpcd_fork_cb(void *arg) __func__, len, sizeof(exit_code)); exit_code = EXIT_FAILURE; } - eloop_exit(ctx->eloop, exit_code); + if (do_exit) + eloop_exit(ctx->eloop, exit_code); } static void @@ -2156,7 +2155,7 @@ printpidfile: { ctx.options |= DHCPCD_FORKED; /* pretend child process */ #ifdef PRIVSEP - if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) goto exit_failure; #endif ifp = calloc(1, sizeof(*ifp)); @@ -2208,12 +2207,9 @@ printpidfile: ctx.options & DHCPCD_DUMPLEASE); if (ctx.control_fd != -1) { #ifdef PRIVSEP - ctx.options &= ~DHCPCD_FORKED; - if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) { - ctx.options |= DHCPCD_FORKED; + if (IN_PRIVSEP(&ctx) && + ps_mastersandbox(&ctx, NULL) == -1) goto exit_failure; - } - ctx.options |= DHCPCD_FORKED; #endif if (!(ctx.options & DHCPCD_DUMPLEASE)) loginfox("sending commands to dhcpcd process"); @@ -2316,6 +2312,9 @@ printpidfile: logerr("fork"); goto exit_failure; case 0: + /* Inform the launcher of our pid as it's chrooted */ + pid = getpid(); + write(ctx.fork_fd, &pid, sizeof(pid)); break; default: ctx.options |= DHCPCD_FORKED; /* A lie */ @@ -2324,8 +2323,8 @@ printpidfile: } break; default: - ctx.options |= DHCPCD_FORKED; /* A lie */ setproctitle("[launcher]"); + ctx.options |= DHCPCD_FORKED; /* A lie */ ctx.fork_fd = fork_fd[0]; close(fork_fd[1]); #ifdef PRIVSEP_RIGHTS @@ -2351,6 +2350,11 @@ printpidfile: eloop_event_add(ctx.eloop, ctx.stderr_fd, dhcpcd_stderr_cb, &ctx); } +#ifdef PRIVSEP + if (IN_PRIVSEP(&ctx) && + ps_mastersandbox(&ctx, "stdio proc") == -1) + goto exit_failure; +#endif goto run_loop; } @@ -2428,7 +2432,7 @@ printpidfile: eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); #ifdef PRIVSEP - if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1) goto exit_failure; #endif diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 03449e58..a3a54b06 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -122,6 +122,7 @@ struct dhcpcd_ctx { bool stderr_valid; int stderr_fd; /* FD for logging to stderr */ int fork_fd; /* FD for the fork init signal pipe */ + pid_t fork_pid; const char *cffile; unsigned long long options; char *logfile; diff --git a/src/privsep.c b/src/privsep.c index ffaa303a..2c161e15 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -118,7 +118,8 @@ ps_dropprivs(struct dhcpcd_ctx *ctx) if (!(ctx->options & DHCPCD_FORKED)) logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name); - if (chroot(pw->pw_dir) == -1) + if (chroot(pw->pw_dir) == -1 && + (errno != EPERM || ctx->options & DHCPCD_FORKED)) logerr("%s: chroot `%s'", __func__, pw->pw_dir); if (chdir("/") == -1) logerr("%s: chdir `/'", __func__); @@ -517,11 +518,18 @@ ps_entersandbox(const char *_pledge, const char **sandbox) } int -ps_mastersandbox(struct dhcpcd_ctx *ctx) +ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) { const char *sandbox = NULL; - - if (ps_dropprivs(ctx) == -1) { + bool forked; + int dropped; + + forked = ctx->options & DHCPCD_FORKED; + ctx->options &= ~DHCPCD_FORKED; + dropped = ps_dropprivs(ctx); + if (forked) + ctx->options |= DHCPCD_FORKED; + if (dropped == -1) { logerr("%s: ps_dropprivs", __func__); return -1; } @@ -537,7 +545,9 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx) } #endif - if (ps_entersandbox("stdio route", &sandbox) == -1) { + if (_pledge == NULL) + _pledge = "stdio"; + if (ps_entersandbox(_pledge, &sandbox) == -1) { if (errno == ENOSYS) { if (sandbox != NULL) logwarnx("sandbox unavailable: %s", sandbox); diff --git a/src/privsep.h b/src/privsep.h index 260c3fda..93f7965e 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -175,7 +175,7 @@ int ps_init(struct dhcpcd_ctx *); int ps_start(struct dhcpcd_ctx *); int ps_stop(struct dhcpcd_ctx *); int ps_entersandbox(const char *, const char **); -int ps_mastersandbox(struct dhcpcd_ctx *); +int ps_mastersandbox(struct dhcpcd_ctx *, const char *); int ps_unrollmsg(struct msghdr *, struct ps_msghdr *, const void *, size_t); ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,