]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Notify processes when dhcpcd has daemonised
authorRoy Marples <roy@marples.name>
Thu, 19 Oct 2023 10:11:05 +0000 (11:11 +0100)
committerRoy Marples <roy@marples.name>
Thu, 19 Oct 2023 10:14:57 +0000 (11:14 +0100)
This allows us to dup stdout and stderr onto stdin which is
guaranteed to be dupped to /dev/null.
This in turn avoids SIGPIPE when the privileged proccess launches
the script and it wants to write to stdout/stderr or stupidly
read from stdin.

src/dhcpcd.c
src/dhcpcd.h
src/privsep-control.c
src/privsep.c
src/privsep.h

index 53d5de4421e7310f686bf1d481746a100eff70dd..52ff1dbb2c0221d3c19060a3788dcfbae809bc2d 100644 (file)
@@ -329,6 +329,36 @@ dhcpcd_ipwaited(struct dhcpcd_ctx *ctx)
        return 1;
 }
 
+#ifndef THERE_IS_NO_FORK
+void
+dhcpcd_daemonised(struct dhcpcd_ctx *ctx)
+{
+       unsigned int logopts = loggetopts();
+
+       /*
+        * Stop writing to stderr.
+        * On the happy path, only the manager process writes to stderr,
+        * so this just stops wasting fprintf calls to nowhere.
+        * All other calls - ie errors in privsep processes or script output,
+        * will error when printing.
+        * If we *really* want to fix that, then we need to suck
+        * stderr/stdout in the manager process and either discard it or pass
+        * it to the launcher process and then to stderr.
+        */
+       logopts &= ~LOGERR_ERR;
+       logsetopts(logopts);
+
+       /*
+        * We need to do something with stdout/stderr to avoid SIGPIPE
+        * We know that stdin is already mapped to /dev/null
+        */
+       dup2(STDIN_FILENO, STDOUT_FILENO);
+       dup2(STDIN_FILENO, STDERR_FILENO);
+
+       ctx->options |= DHCPCD_DAEMONISED;
+}
+#endif
+
 /* Returns the pid of the child, otherwise 0. */
 void
 dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
@@ -363,6 +393,13 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
        if (!(logopts & LOGERR_QUIET) && ctx->stderr_valid)
                (void)fprintf(stderr,
                    "forked to background, child pid %d\n", getpid());
+
+#ifdef PRIVSEP
+       ps_daemonised(ctx);
+#else
+       dhcpcd_daemonised(ctx);
+#endif
+
        i = EXIT_SUCCESS;
        if (write(ctx->fork_fd, &i, sizeof(i)) == -1)
                logerr("write");
@@ -370,19 +407,6 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
        eloop_event_delete(ctx->eloop, ctx->fork_fd);
        close(ctx->fork_fd);
        ctx->fork_fd = -1;
-
-       /*
-        * Stop writing to stderr.
-        * On the happy path, only the manager process writes to stderr,
-        * so this just stops wasting fprintf calls to nowhere.
-        * All other calls - ie errors in privsep processes or script output,
-        * will error when printing.
-        * If we *really* want to fix that, then we need to suck
-        * stderr/stdout in the manager process and either disacrd it or pass
-        * it to the launcher process and then to stderr.
-        */
-       logopts &= ~LOGERR_ERR;
-       logsetopts(logopts);
 #endif
 }
 
@@ -1871,17 +1895,17 @@ dhcpcd_pidfile_timeout(void *arg)
 
 static int dup_null(int fd)
 {
+       int fd_null = open(_PATH_DEVNULL, O_WRONLY);
        int err;
-       int fd_null = open(_PATH_DEVNULL, O_RDONLY);
 
        if (fd_null == -1) {
                logwarn("open %s", _PATH_DEVNULL);
                return -1;
        }
 
-       if ((err = dup2(fd, fd_null)) == -1)
+       if ((err = dup2(fd_null, fd)) == -1)
                logwarn("dup2 %d", fd);
-       close(fd);
+       close(fd_null);
        return err;
 }
 
@@ -1988,6 +2012,15 @@ main(int argc, char **argv, char **envp)
        ctx.stdout_valid = fcntl(STDOUT_FILENO, F_GETFD) != -1;
        ctx.stderr_valid = fcntl(STDERR_FILENO, F_GETFD) != -1;
 
+       /* Even we if we don't have input/outputs, we need to
+        * ensure they are setup for shells. */
+       if (!ctx.stdin_valid)
+               dup_null(STDIN_FILENO);
+       if (!ctx.stdout_valid)
+               dup_null(STDOUT_FILENO);
+       if (!ctx.stderr_valid)
+               dup_null(STDERR_FILENO);
+
        logopts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID;
        if (ctx.stderr_valid)
                logopts |= LOGERR_ERR;
index cdb0e135968d4b75fb0ae656571c34e99e25c977..918dc687e4513a2463632938adf6413d6b9e249e 100644 (file)
@@ -265,6 +265,7 @@ extern const char *dhcpcd_default_script;
 
 int dhcpcd_ifafwaiting(const struct interface *);
 int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
+void dhcpcd_daemonised(struct dhcpcd_ctx *);
 void dhcpcd_daemonise(struct dhcpcd_ctx *);
 
 void dhcpcd_signal_cb(int, void *);
index 38f18c4ec163517f402b992211826d8073a68723..40bfb16469e7477d808beda9891b5af1d55411ba 100644 (file)
@@ -69,8 +69,7 @@ ps_ctl_recvmsg(void *arg, unsigned short events)
 {
        struct ps_process *psp = arg;
 
-       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events,
-           NULL, psp->psp_ctx) == -1)
+       if (ps_recvpsmsg(psp->psp_ctx, psp->psp_fd, events, NULL, NULL) == -1)
                logerr(__func__);
 }
 
index ecc517ec38bf41207c66cff91a8d94b13f43a5fa..03f4be9151d467c812433de944b823b900b74307 100644 (file)
@@ -1099,6 +1099,26 @@ ps_recvmsg(int rfd, unsigned short events, uint16_t cmd, int wfd)
        return len;
 }
 
+ssize_t
+ps_daemonised(struct dhcpcd_ctx *ctx)
+{
+       struct ps_process *psp;
+       ssize_t err = 0;
+
+       dhcpcd_daemonised(ctx);
+
+       /* Echo the message to all processes */
+       TAILQ_FOREACH(psp, &ctx->ps_processes, next) {
+               if (psp->psp_pid == getpid())
+                       continue;
+               if (ps_sendcmd(psp->psp_ctx, psp->psp_fd, PS_DAEMONISED,
+                   0, NULL, 0) == -1)
+                       err = -1;
+       }
+
+       return err;
+}
+
 ssize_t
 ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
     ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *),
@@ -1131,6 +1151,9 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
                if (psm.psm_hdr.ps_cmd == PS_STOP) {
                        stop = true;
                        len = 0;
+               } else if (psm.psm_hdr.ps_cmd == PS_DAEMONISED) {
+                       ps_daemonised(ctx);
+                       return 0;
                }
        }
 
index 00e8fc4f10ae518ec472a35d86c30c0585ce00fa..cab17550357238088afe584778cbd0540d009d45 100644 (file)
@@ -55,6 +55,7 @@
 #define        PS_CTL_EOF              0x0019
 #define        PS_LOGREOPEN            0x0020
 #define        PS_STOPPROCS            0x0021
+#define        PS_DAEMONISED           0x0022
 
 /* Domains */
 #define        PS_ROOT                 0x0101
@@ -203,6 +204,7 @@ int ps_stop(struct dhcpcd_ctx *);
 int ps_stopwait(struct dhcpcd_ctx *);
 int ps_entersandbox(const char *, const char **);
 int ps_managersandbox(struct dhcpcd_ctx *, const char *);
+ssize_t ps_daemonised(struct dhcpcd_ctx *);
 
 int ps_unrollmsg(struct msghdr *, struct ps_msghdr *, const void *, size_t);
 ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *, int,