]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
dhcpcd: Move the script file from per interface to global context
authorRoy Marples <roy@marples.name>
Thu, 21 May 2020 17:28:27 +0000 (18:28 +0100)
committerRoy Marples <roy@marples.name>
Thu, 21 May 2020 17:28:27 +0000 (18:28 +0100)
This *should* affect no-one, but you never know.
The primary motivation for this is to ensure that nothing arbitary
can be executed by the root process if anyone breaks into the
chrooted unprivileged master process.

It also makes for smaller code.

src/dhcpcd.c
src/dhcpcd.h
src/if-options.c
src/if-options.h
src/privsep-root.c
src/privsep-root.h
src/script.c
src/script.h

index d9056f50e0d5eda95df7ae221517a49214b3fa94..46c6d8ed6b0b07f6cba90b1fa3cc20a9dcaeb33a 100644 (file)
@@ -98,6 +98,8 @@ const size_t dhcpcd_signals_ignore_len = __arraycount(dhcpcd_signals_ignore);
 #define IF_UPANDRUNNING(a) \
        (((a)->flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
 
+const char *dhcpcd_default_script = SCRIPT;
+
 static void
 usage(void)
 {
@@ -1837,6 +1839,7 @@ main(int argc, char **argv)
 
        ifo = NULL;
        ctx.cffile = CONFIG;
+       ctx.script = UNCONST(dhcpcd_default_script);
        ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1;
        ctx.pf_inet_fd = -1;
 
@@ -2172,7 +2175,7 @@ printpidfile:
 
 #ifdef PRIVSEP
        if (ps_init(&ctx) == 0)
-               script_runchroot(&ctx, ifo->script);
+               script_runchroot(&ctx);
 #endif
 
 #ifdef USE_SIGNALS
@@ -2456,6 +2459,8 @@ exit1:
        eloop_free(ctx.ps_eloop);
 #endif
        eloop_free(ctx.eloop);
+       if (ctx.script != dhcpcd_default_script)
+               free(ctx.script);
        if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
                loginfox(PACKAGE " exited");
        logclose();
index 1eda2dcda4231acbe3272f5f748404578ec13bcb..f3ce6c4b5cb578a71e4b7205d286f39534c8c01e 100644 (file)
@@ -164,6 +164,7 @@ struct dhcpcd_ctx {
 #endif
        struct eloop *eloop;
 
+       char *script;
 #ifdef HAVE_OPEN_MEMSTREAM
        FILE *script_fp;
 #endif
@@ -253,6 +254,8 @@ extern const int dhcpcd_signals_ignore[];
 extern const size_t dhcpcd_signals_ignore_len;
 #endif
 
+extern const char *dhcpcd_default_script;
+
 int dhcpcd_ifafwaiting(const struct interface *);
 int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
 void dhcpcd_daemonise(struct dhcpcd_ctx *);
index e4b8c49f887715fd840566caee21bdf083cf6f0c..ca0216ae89f7663e5a85ee17c8769164fc8aaa09 100644 (file)
@@ -161,8 +161,6 @@ const struct option cf_options[] = {
        {NULL,              0,                 NULL, '\0'}
 };
 
-static const char *default_script = SCRIPT;
-
 static char *
 add_environ(char ***array, const char *value, int uniq)
 {
@@ -675,26 +673,32 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                break;
        case 'c':
                ARG_REQUIRED;
-               if (ifo->script != default_script)
-                       free(ifo->script);
+               if (ifname != NULL) {
+                       logerrx("%s: per interface scripts"
+                           " are no longer supported",
+                           ifname);
+                       return -1;
+               }
+               if (ctx->script != dhcpcd_default_script)
+                       free(ctx->script);
                s = parse_nstring(NULL, 0, arg);
                if (s == 0) {
-                       ifo->script = NULL;
+                       ctx->script = NULL;
                        break;
                }
                dl = (size_t)s;
-               if (s == -1 || (ifo->script = malloc(dl)) == NULL) {
-                       ifo->script = NULL;
+               if (s == -1 || (ctx->script = malloc(dl)) == NULL) {
+                       ctx->script = NULL;
                        logerr(__func__);
                        return -1;
                }
-               s = parse_nstring(ifo->script, dl, arg);
+               s = parse_nstring(ctx->script, dl, arg);
                if (s == -1 ||
-                   ifo->script[0] == '\0' ||
-                   strcmp(ifo->script, "/dev/null") == 0)
+                   ctx->script[0] == '\0' ||
+                   strcmp(ctx->script, "/dev/null") == 0)
                {
-                       free(ifo->script);
-                       ifo->script = NULL;
+                       free(ctx->script);
+                       ctx->script = NULL;
                }
                break;
        case 'd':
@@ -2315,7 +2319,6 @@ default_config(struct dhcpcd_ctx *ctx)
        ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
        ifo->timeout = DEFAULT_TIMEOUT;
        ifo->reboot = DEFAULT_REBOOT;
-       ifo->script = UNCONST(default_script);
        ifo->metric = -1;
        ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
        rb_tree_init(&ifo->routes, &rt_compare_list_ops);
@@ -2667,8 +2670,6 @@ free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
 #endif
        rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
 
-       if (ifo->script != default_script)
-               free(ifo->script);
        free(ifo->arping);
        free(ifo->blacklist);
        free(ifo->fallback);
index 1d9e3343d5005edd8ab72f9e826da19d646a8681..870eabf67064fccec8fd886902df7e1ec2355859 100644 (file)
@@ -243,7 +243,6 @@ struct if_options {
        char **config;
 
        char **environ;
-       char *script;
 
        char hostname[HOSTNAME_MAX_LEN + 1]; /* We don't store the length */
        uint8_t fqdn;
index 36e1ec1a0fdb31321df24455708b29e4b47dbd52..716a55c414409f5c2105d39c034726914fb6066b 100644 (file)
@@ -259,34 +259,13 @@ static ssize_t
 ps_root_run_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
 {
        const char *envbuf = data;
-       char * const argv[] = { UNCONST(data), NULL };
+       char * const argv[] = { ctx->script, NULL };
        pid_t pid;
        int status;
 
-#ifdef PRIVSEP_DEBUG
-       logdebugx("%s: IN %zu", __func__, len);
-#endif
-
        if (len == 0)
                return 0;
 
-       /* Script is the first one, find the environment buffer. */
-       while (*envbuf != '\0') {
-               if (len == 0)
-                       return EINVAL;
-               envbuf++;
-               len--;
-       }
-
-       if (len != 0) {
-               envbuf++;
-               len--;
-       }
-
-#ifdef PRIVSEP_DEBUG
-       logdebugx("%s: run script: %s", __func__, argv[0]);
-#endif
-
        if (script_buftoenv(ctx, UNCONST(envbuf), len) == NULL)
                return -1;
 
@@ -678,39 +657,12 @@ ps_root_stop(struct dhcpcd_ctx *ctx)
 }
 
 ssize_t
-ps_root_script(const struct interface *ifp, const void *data, size_t len)
+ps_root_script(struct dhcpcd_ctx *ctx, const void *data, size_t len)
 {
-       char buf[PS_BUFLEN], *p = buf;
-       size_t blen = PS_BUFLEN, slen = strlen(ifp->options->script) + 1;
-
-#ifdef PRIVSEP_DEBUG
-       logdebugx("%s: sending script: %zu %s len %zu",
-           __func__, slen, ifp->options->script, len);
-#endif
 
-       if (slen > blen) {
-               errno = ENOBUFS;
+       if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_SCRIPT, 0, data, len) == -1)
                return -1;
-       }
-       memcpy(p, ifp->options->script, slen);
-       p += slen;
-       blen -= slen;
-
-       if (len > blen) {
-               errno = ENOBUFS;
-               return -1;
-       }
-       memcpy(p, data, len);
-
-#ifdef PRIVSEP_DEBUG
-       logdebugx("%s: sending script data: %zu", __func__, slen + len);
-#endif
-
-       if (ps_sendcmd(ifp->ctx, ifp->ctx->ps_root_fd, PS_SCRIPT, 0,
-           buf, slen + len) == -1)
-               return -1;
-
-       return ps_root_readerror(ifp->ctx, NULL, 0);
+       return ps_root_readerror(ctx, NULL, 0);
 }
 
 ssize_t
index f4768a6c1a2bf07dd2279ed03bc321bab9494b54..bf02bb5fc53b49aa8cdd95db0478b94337ef9e9c 100644 (file)
@@ -42,7 +42,7 @@ ssize_t ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
 ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
 ssize_t ps_root_writefile(struct dhcpcd_ctx *, const char *, mode_t,
     const void *, size_t);
-ssize_t ps_root_script(const struct interface *, const void *, size_t);
+ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t);
 int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **);
 
 ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *);
index 56f6cad3b89045b4c425f02d8546ce812b3612e0..bd4bc94c3b063aeb0275d632ad0fc6dd01c9c764 100644 (file)
@@ -691,7 +691,7 @@ script_runreason(const struct interface *ifp, const char *reason)
        int status = 0;
        struct fd_list *fd;
 
-       if (ifp->options->script == NULL &&
+       if (ctx->script == NULL &&
            TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
                return 0;
 
@@ -701,16 +701,16 @@ script_runreason(const struct interface *ifp, const char *reason)
                return -1;
        }
 
-       if (ifp->options->script == NULL)
+       if (ctx->script == NULL)
                goto send_listeners;
 
-       argv[0] = ifp->options->script;
+       argv[0] = ctx->script;
        argv[1] = NULL;
        logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
 
 #ifdef PRIVSEP
        if (ctx->options & DHCPCD_PRIVSEP) {
-               if (ps_root_script(ifp,
+               if (ps_root_script(ctx,
                    ctx->script_buf, ctx->script_buflen) == -1)
                        logerr(__func__);
                goto send_listeners;
@@ -737,7 +737,7 @@ send_listeners:
 
 #ifdef PRIVSEP
 int
-script_runchroot(struct dhcpcd_ctx *ctx, char *script)
+script_runchroot(struct dhcpcd_ctx *ctx)
 {
        char *argv[2];
 
@@ -747,7 +747,7 @@ script_runchroot(struct dhcpcd_ctx *ctx, char *script)
                return -1;
        }
 
-       argv[0] = script;
+       argv[0] = ctx->script;
        argv[1] = NULL;
        logdebugx("executing `%s' %s", argv[0], "CHROOT");
 
index 769f3787df9187013f0e34f10fd2719aac8f4210..8e49f7fd09716cba7732746d9944f184a584e4b7 100644 (file)
@@ -37,5 +37,5 @@ char ** script_buftoenv(struct dhcpcd_ctx *, char *, size_t);
 pid_t script_exec(char *const *, char *const *);
 int send_interface(struct fd_list *, const struct interface *, int);
 int script_runreason(const struct interface *, const char *);
-int script_runchroot(struct dhcpcd_ctx *, char *);
+int script_runchroot(struct dhcpcd_ctx *);
 #endif