]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: sandbox the launcher process
authorRoy Marples <roy@marples.name>
Sun, 20 Sep 2020 18:09:08 +0000 (19:09 +0100)
committerRoy Marples <roy@marples.name>
Sun, 20 Sep 2020 18:09:08 +0000 (19:09 +0100)
src/dhcpcd.c
src/dhcpcd.h
src/privsep.c
src/privsep.h

index 8fbb6212191a4d67b8a5c2a3c3c3843bfa0a928e..83161471e073dfcadecedbdec9f401ea9e977d3d 100644 (file)
@@ -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
 
index 03449e5846053d3255087762420ad14c2aa75d70..a3a54b0655567e9375c0b5dfb8ccfa8e270b3154 100644 (file)
@@ -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;
index ffaa303ad16c9b7030d6a35c5d584500a0981856..2c161e15f89200a03509ee9b0ad446309fc585ff 100644 (file)
@@ -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);
index 260c3fdabcadf73dde251715d0473ba6172769e2..93f7965e10b988468a5b885b046e38dc97b395fd 100644 (file)
@@ -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,