]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Remove PS_BUFLEN
authorRoy Marples <roy@marples.name>
Thu, 18 Jun 2026 14:39:22 +0000 (15:39 +0100)
committerGitHub <noreply@github.com>
Thu, 18 Jun 2026 14:39:22 +0000 (15:39 +0100)
We always send a header with the expected lengths.
So use malloced buffers to send and receive using this
knowledge.

15 files changed:
src/common.c
src/common.h
src/dhcp-common.c
src/dhcp-common.h
src/dhcp.c
src/dhcp6.c
src/dhcpcd.c
src/dhcpcd.h
src/if-linux.c
src/if-options.c
src/privsep-bsd.c
src/privsep-root.c
src/privsep-root.h
src/privsep.c
src/privsep.h

index 764209cbe21d8e4852344c7f5105869c5c099810..953db6f6a04e3f7a40659847279593ea812cf572 100644 (file)
@@ -111,21 +111,35 @@ hwaddr_aton(uint8_t *buffer, const char *addr)
 }
 
 ssize_t
-readfile(const char *file, void *data, size_t len)
+readfile(const char *file, void **data, size_t *len)
 {
        int fd;
-       ssize_t bytes;
+       ssize_t bytes = -1;
+       struct stat st;
+       size_t nlen;
+       char *buf;
 
        fd = open(file, O_RDONLY);
        if (fd == -1)
                return -1;
-       bytes = read(fd, data, len);
+       if (fstat(fd, &st) == -1)
+               goto out;
+       nlen = (size_t)st.st_size + 1;
+       if (nlen > *len) {
+               void *ndata = realloc(*data, nlen);
+               if (ndata == NULL)
+                       goto out;
+               *data = ndata;
+               *len = nlen;
+       }
+       bytes = read(fd, *data, *len);
+out:
        close(fd);
-       if ((size_t)bytes == len) {
-               errno = ENOBUFS;
+       if (bytes == -1)
                return -1;
-       }
-       return bytes;
+       buf = *data;
+       buf[bytes] = '\0';
+       return bytes + 1;
 }
 
 ssize_t
@@ -158,7 +172,7 @@ filemtime(const char *file, time_t *time)
  * We strip leading space and avoid comment lines, making the code that calls
  * us smaller. */
 char *
-get_line(char **__restrict buf, ssize_t *__restrict buflen)
+get_line(char **__restrict buf, size_t *__restrict buflen)
 {
        char *p, *c;
        bool quoted;
@@ -167,16 +181,16 @@ get_line(char **__restrict buf, ssize_t *__restrict buflen)
                p = *buf;
                if (*buf == NULL)
                        return NULL;
-               c = memchr(*buf, '\n', (size_t)*buflen);
+               c = memchr(*buf, '\n', *buflen);
                if (c == NULL) {
-                       c = memchr(*buf, '\0', (size_t)*buflen);
+                       c = memchr(*buf, '\0', *buflen);
                        if (c == NULL)
                                return NULL;
-                       *buflen = c - *buf;
+                       *buflen = (size_t)(c - *buf);
                        *buf = NULL;
                } else {
                        *c++ = '\0';
-                       *buflen -= c - *buf;
+                       *buflen -= (size_t)(c - *buf);
                        *buf = c;
                }
                for (; *p == ' ' || *p == '\t'; p++)
index 042766151d336316847af93d045e3c0886740f2f..577afc4da88a7a91008acf65be931628186f44c5 100644 (file)
 
 const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
 size_t hwaddr_aton(uint8_t *, const char *);
-ssize_t readfile(const char *, void *, size_t);
+ssize_t readfile(const char *, void **, size_t *);
 ssize_t writefile(const char *, mode_t, const void *, size_t);
 int filemtime(const char *, time_t *);
-char *get_line(char **__restrict, ssize_t *__restrict);
+char *get_line(char **__restrict, size_t *__restrict);
 int is_root_local(void);
 uint32_t lifetime_left(uint32_t, const struct timespec *, struct timespec *);
 #endif
index c428b7ceff002217cef0d5262bb09d5ff034b26e..04970b04084352419c61033b6be3ee436018dccf 100644 (file)
@@ -1009,10 +1009,44 @@ dhcp_zero_index(struct dhcp_opt *opt)
 }
 
 ssize_t
-dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len)
+dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void **data,
+    size_t *len)
 {
+       size_t rlen = 0;
+
+       if (len == NULL)
+               len = &rlen;
+
+       if (file == NULL || *file == '\0') {
+               uint8_t *p = *data;
+               size_t needed = BUFSIZ, bytes = 0, left;
+               ssize_t nread;
+
+               for (;;) {
+                       if (*len < needed) {
+                               void *nbuf = realloc(*data, needed);
+                               if (nbuf == NULL)
+                                       return -1;
+                               p = *data = nbuf;
+                               p += bytes;
+                               *len = needed;
+                       }
+
+                       left = *len - bytes;
+                       nread = read(fileno(stdin), p, left);
+                       if (nread == -1)
+                               return -1;
+                       bytes += (size_t)nread;
+                       if ((size_t)nread < left || nread == 0)
+                               return (ssize_t)bytes;
+
+                       /* We need a bigger buffer */
+                       needed += BUFSIZ;
+               }
+       }
+
 #ifdef PRIVSEP
-       if (ctx->options & DHCPCD_PRIVSEP &&
+       if (file != NULL && ctx->options & DHCPCD_PRIVSEP &&
            !(ctx->options & DHCPCD_PRIVSEPROOT))
                return ps_root_readfile(ctx, file, data, len);
 #else
@@ -1068,21 +1102,18 @@ dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file)
 size_t
 dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file)
 {
-       char buf[BUFSIZ];
        ssize_t bytes;
        size_t len;
 
-       bytes = dhcp_readfile(ctx, file, buf, sizeof(buf));
-       if (bytes == -1 || bytes == sizeof(buf))
+       bytes = dhcp_readfile(ctx, file, &ctx->io_buf, &ctx->io_buflen);
+       if (bytes == -1)
                return 0;
-
-       bytes[buf] = '\0';
-       len = hwaddr_aton(NULL, buf);
+       len = hwaddr_aton(NULL, ctx->io_buf);
        if (len == 0)
                return 0;
        *data = malloc(len);
        if (*data == NULL)
                return 0;
-       hwaddr_aton(*data, buf);
+       hwaddr_aton(*data, ctx->io_buf);
        return len;
 }
index 49c831f9ca721d9d377bbfb9fc17938a92682f41..cdc5dded99736cc50613029db8f8681adde79063 100644 (file)
@@ -132,7 +132,7 @@ void dhcp_envoption(struct dhcpcd_ctx *, FILE *, const char *, const char *,
     const uint8_t *od, size_t ol);
 void dhcp_zero_index(struct dhcp_opt *);
 
-ssize_t dhcp_readfile(struct dhcpcd_ctx *, const char *, void *, size_t);
+ssize_t dhcp_readfile(struct dhcpcd_ctx *, const char *, void **, size_t *);
 ssize_t dhcp_writefile(struct dhcpcd_ctx *, const char *, mode_t, const void *,
     size_t);
 int dhcp_filemtime(struct dhcpcd_ctx *, const char *, time_t *);
index d22a99b1ddb0a48865496c9147b301f4b7a5ac33..799a74665ec6bbac0612007733778191a847cf78 100644 (file)
@@ -1232,10 +1232,6 @@ toobig:
 static size_t
 read_lease(struct interface *ifp, struct bootp **bootp)
 {
-       union {
-               struct bootp bootp;
-               uint8_t buf[FRAMELEN_MAX];
-       } buf;
        struct dhcp_state *state = D_STATE(ifp);
        ssize_t sbytes;
        size_t bytes;
@@ -1248,14 +1244,13 @@ read_lease(struct interface *ifp, struct bootp **bootp)
        /* Safety */
        *bootp = NULL;
 
-       if (state->leasefile[0] == '\0') {
+       if (state->leasefile[0] == '\0')
                logdebugx("reading standard input");
-               sbytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
-       } else {
+       else
                logdebugx("%s: reading lease: %s", ifp->name, state->leasefile);
-               sbytes = dhcp_readfile(ifp->ctx, state->leasefile, buf.buf,
-                   sizeof(buf.buf));
-       }
+       *bootp = NULL;
+       sbytes = dhcp_readfile(ifp->ctx, state->leasefile, (void **)bootp,
+           NULL);
        if (sbytes == -1) {
                if (errno != ENOENT)
                        logerr("%s: %s", ifp->name, state->leasefile);
@@ -1277,17 +1272,17 @@ read_lease(struct interface *ifp, struct bootp **bootp)
                goto out;
 
        /* We may have found a BOOTP server */
-       if (get_option_uint8(ifp->ctx, &type, &buf.bootp, bytes,
-               DHO_MESSAGETYPE) == -1)
+       if (get_option_uint8(ifp->ctx, &type, *bootp, bytes, DHO_MESSAGETYPE) ==
+           -1)
                type = 0;
 
 #ifdef AUTH
        /* Authenticate the message */
-       auth = get_option(ifp->ctx, &buf.bootp, bytes, DHO_AUTHENTICATION,
+       auth = get_option(ifp->ctx, *bootp, bytes, DHO_AUTHENTICATION,
            &auth_len);
        if (auth) {
                if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
-                       &buf.bootp, bytes, 4, type, auth, auth_len) == NULL) {
+                       *bootp, bytes, 4, type, auth, auth_len) == NULL) {
                        logerr("%s: authentication failed", ifp->name);
                        return 0;
                }
@@ -1304,12 +1299,6 @@ read_lease(struct interface *ifp, struct bootp **bootp)
 #endif
 
 out:
-       *bootp = malloc(bytes);
-       if (*bootp == NULL) {
-               logerr(__func__);
-               return 0;
-       }
-       memcpy(*bootp, buf.buf, bytes);
        return bytes;
 }
 
index 0193967a08d05da57b7f55173939055f8d074f57..97737675714ddecfa8ab7fded367ce6ad95aae13 100644 (file)
@@ -2672,10 +2672,7 @@ dhcp6_validatelease(struct interface *ifp, struct dhcp6_message *m, size_t len,
 static ssize_t
 dhcp6_readlease(struct interface *ifp, int validate)
 {
-       union {
-               struct dhcp6_message dhcp6;
-               uint8_t buf[UDPLEN_MAX];
-       } buf;
+       struct dhcp6_message *dhcp6;
        struct dhcp6_state *state;
        ssize_t bytes;
        int fd;
@@ -2686,14 +2683,12 @@ dhcp6_readlease(struct interface *ifp, int validate)
 #endif
 
        state = D6_STATE(ifp);
-       if (state->leasefile[0] == '\0') {
+       if (state->leasefile[0] == '\0')
                logdebugx("reading standard input");
-               bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf));
-       } else {
+       else
                logdebugx("%s: reading lease: %s", ifp->name, state->leasefile);
-               bytes = dhcp_readfile(ifp->ctx, state->leasefile, buf.buf,
-                   sizeof(buf.buf));
-       }
+       bytes = dhcp_readfile(ifp->ctx, state->leasefile, (void **)&dhcp6,
+           NULL);
        if (bytes == -1)
                goto ex;
 
@@ -2716,7 +2711,7 @@ dhcp6_readlease(struct interface *ifp, int validate)
        state->acquired.tv_sec -= now - mtime;
 
        /* Check to see if the lease is still valid */
-       fd = dhcp6_validatelease(ifp, &buf.dhcp6, (size_t)bytes, NULL,
+       fd = dhcp6_validatelease(ifp, dhcp6, (size_t)bytes, NULL,
            &state->acquired);
        if (fd == -1) {
                bytes = 0; /* We have already reported the error */
@@ -2733,11 +2728,10 @@ dhcp6_readlease(struct interface *ifp, int validate)
 auth:
 #ifdef AUTH
        /* Authenticate the message */
-       o = dhcp6_findmoption(&buf.dhcp6, (size_t)bytes, D6_OPTION_AUTH, &ol);
+       o = dhcp6_findmoption(dhcp6, (size_t)bytes, D6_OPTION_AUTH, &ol);
        if (o) {
-               if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
-                       buf.buf, (size_t)bytes, 6, buf.dhcp6.type, o,
-                       ol) == NULL) {
+               if (dhcp_auth_validate(&state->auth, &ifp->options->auth, dhcp6,
+                       (size_t)bytes, 6, dhcp6->type, o, ol) == NULL) {
                        logerr("%s: authentication failed", ifp->name);
                        bytes = 0;
                        goto ex;
@@ -2756,13 +2750,7 @@ auth:
 
 out:
        free(state->new);
-       state->new = malloc((size_t)bytes);
-       if (state->new == NULL) {
-               logerr(__func__);
-               goto ex;
-       }
-
-       memcpy(state->new, buf.buf, (size_t)bytes);
+       state->new = dhcp6;
        state->new_len = (size_t)bytes;
        return bytes;
 
index cb7ebadb67f9620367924160b0a0eef2079e0847..36ee0e3bdd6fd5181d271e622bd485747c341349 100644 (file)
@@ -2808,6 +2808,7 @@ exit1:
 #endif
        free(ctx.script_buf);
        free(ctx.script_env);
+       free(ctx.io_buf);
        rt_dispose(&ctx);
        free(ctx.duid);
        if_closesockets(&ctx);
index d2fae30b5e8d48ed2648a658082e06c2de2ffb26..cb2a93030f59506c6b98d37df1ebb6fc13f22baf 100644 (file)
@@ -170,6 +170,8 @@ struct dhcpcd_ctx {
        size_t script_buflen;
        char **script_env;
        size_t script_envlen;
+       void *io_buf;
+       size_t io_buflen;
 
        int control_fd;
        int control_unpriv_fd;
@@ -202,6 +204,8 @@ struct dhcpcd_ctx {
        int ps_log_root_fd;                /* outside chroot log reader */
        struct fd_list *ps_control;        /* Queue for the above */
        struct fd_list *ps_control_client; /* Queue for the above */
+       void *ps_buf;                      /* IPC buffer */
+       size_t ps_buflen;                  /* IPC buffer length */
 #endif
 
 #ifdef INET
index c5278a52288684a0b37e149f886272608f6e4004..0359d1b293092b229e24246c7b6bbdd07b77a7dd 100644 (file)
@@ -256,12 +256,11 @@ if_machinearch(char *str, size_t len)
 static int
 check_proc_int(struct dhcpcd_ctx *ctx, const char *path)
 {
-       char buf[64];
        int error, i;
 
-       if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1)
+       if (dhcp_readfile(ctx, path, &ctx->io_buf, &ctx->io_buflen) == -1)
                return -1;
-       i = (int)strtoi(buf, NULL, 0, INT_MIN, INT_MAX, &error);
+       i = (int)strtoi(ctx->io_buf, NULL, 0, INT_MIN, INT_MAX, &error);
        if (error != 0 && error != ENOTSUP) {
                errno = error;
                return -1;
@@ -272,12 +271,11 @@ check_proc_int(struct dhcpcd_ctx *ctx, const char *path)
 static int
 check_proc_uint(struct dhcpcd_ctx *ctx, const char *path, unsigned int *u)
 {
-       char buf[64];
        int error;
 
-       if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1)
+       if (dhcp_readfile(ctx, path, &ctx->io_buf, &ctx->io_buflen) == -1)
                return -1;
-       *u = (unsigned int)strtou(buf, NULL, 0, 0, UINT_MAX, &error);
+       *u = (unsigned int)strtou(ctx->io_buf, NULL, 0, 0, UINT_MAX, &error);
        if (error != 0 && error != ENOTSUP) {
                errno = error;
                return error;
@@ -365,10 +363,10 @@ if_conf(struct interface *ifp)
 static bool
 if_bridge(struct dhcpcd_ctx *ctx, const char *ifname)
 {
-       char path[sizeof(SYS_BRIDGE) + IF_NAMESIZE], buf[64];
+       char path[sizeof(SYS_BRIDGE) + IF_NAMESIZE];
 
        snprintf(path, sizeof(path), SYS_BRIDGE, ifname);
-       if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1)
+       if (dhcp_readfile(ctx, path, &ctx->io_buf, &ctx->io_buflen) == -1)
                return false;
        return true;
 }
index d7b9ffb13941afbfa594cd04b54a2407d3271dbc..03aae3d5cde6d10396cf71d0619f6184f51956da 100644 (file)
@@ -2661,10 +2661,9 @@ read_config(struct dhcpcd_ctx *ctx, const char *ifname, const char *ssid,
     const char *profile)
 {
        struct if_options *ifo;
-       char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
-       char *line, *option, *p;
-       ssize_t buflen;
-       size_t vlen;
+       char *bp, *line, *option, *p;
+       ssize_t nread;
+       size_t buflen, vlen;
        int skip, have_profile, new_block, had_block;
 #if !defined(INET) || !defined(INET6)
        size_t i;
@@ -2741,26 +2740,28 @@ read_config(struct dhcpcd_ctx *ctx, const char *ifname, const char *ssid,
 
                /* Now load our embedded config */
 #ifdef EMBEDDED_CONFIG
-               buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
-               if (buflen == -1) {
+               nread = dhcp_readfile(ctx, EMBEDDED_CONFIG, &ctx->io_buf,
+                   &ctx->io_buflen);
+               if (nread == -1) {
                        logerr("%s: %s", __func__, EMBEDDED_CONFIG);
                        return ifo;
                }
-               if (buf[buflen - 1] != '\0') {
-                       if ((size_t)buflen < sizeof(buf) - 1)
-                               buflen++;
-                       buf[buflen - 1] = '\0';
-               }
+               buflen = (size_t)nread;
 #else
-               buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf,
-                   sizeof(buf));
-               if ((size_t)buflen >= sizeof(buf)) {
-                       logerrx("%s: embedded config too big", __func__);
-                       return ifo;
-               }
-               /* Our embedded config is NULL terminated */
+               buflen = strlen(dhcpcd_embedded_conf) + 1;
+               if (ctx->io_buflen < buflen) {
+                       void *nbuf = realloc(ctx->io_buf, buflen);
+                       if (nbuf == NULL) {
+                               logerr("%s: realloc", __func__);
+                               return ifo;
+                       }
+                       ctx->io_buf = nbuf;
+                       ctx->io_buflen = buflen;
+               }
+               buflen = strlcpy(ctx->io_buf, dhcpcd_embedded_conf,
+                   ctx->io_buflen);
 #endif
-               bp = buf;
+               bp = ctx->io_buf;
                while ((line = get_line(&bp, &buflen)) != NULL) {
                        option = strsep(&line, " \t");
                        if (line)
@@ -2817,24 +2818,20 @@ read_config(struct dhcpcd_ctx *ctx, const char *ifname, const char *ssid,
        }
 
        /* Parse our options file */
-       buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
-       if (buflen == -1) {
+       nread = dhcp_readfile(ctx, ctx->cffile, &ctx->io_buf, &ctx->io_buflen);
+       if (nread == -1) {
                /* dhcpcd can continue without it, but no DNS options
                 * would be requested ... */
                logerr("%s: %s", __func__, ctx->cffile);
                return ifo;
        }
-       if (buf[buflen - 1] != '\0') {
-               if ((size_t)buflen < sizeof(buf) - 1)
-                       buflen++;
-               buf[buflen - 1] = '\0';
-       }
+       buflen = (size_t)nread;
        dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
 
        ldop = edop = NULL;
        skip = have_profile = new_block = 0;
        had_block = ifname == NULL ? 1 : 0;
-       bp = buf;
+       bp = ctx->io_buf;
        while ((line = get_line(&bp, &buflen)) != NULL) {
                option = strsep(&line, " \t");
                if (line)
index 42bc45eba25c091f7d5529979fea423c438f4949..4cca33a4a379c1905b9a0cda918ab28729f741e9 100644 (file)
@@ -389,21 +389,20 @@ ssize_t
 ps_root_sysctl(struct dhcpcd_ctx *ctx, const int *name, unsigned int namelen,
     void *oldp, size_t *oldlenp, const void *newp, size_t newlen)
 {
-       char buf[PS_BUFLEN], *p = buf;
+       char *p;
        unsigned long flags = 0;
        size_t olen = (oldp && oldlenp) ? *oldlenp : 0, nolen;
+       size_t buflen = sizeof(namelen) + (sizeof(*name) * namelen) +
+           sizeof(oldlenp) + sizeof(newlen) + newlen;
 
-       if (sizeof(namelen) + (sizeof(*name) * namelen) + sizeof(oldlenp) +
-               sizeof(newlen) + newlen >
-           sizeof(buf)) {
-               errno = ENOBUFS;
+       if (ps_bufalloc(ctx, buflen) == -1)
                return -1;
-       }
 
        if (oldlenp)
                flags |= PS_SYSCTL_OLEN;
        if (oldp)
                flags |= PS_SYSCTL_ODATA;
+       p = ctx->ps_buf;
        memcpy(p, &namelen, sizeof(namelen));
        p += sizeof(namelen);
        memcpy(p, name, sizeof(*name) * namelen);
@@ -417,14 +416,14 @@ ps_root_sysctl(struct dhcpcd_ctx *ctx, const int *name, unsigned int namelen,
                p += newlen;
        }
 
-       if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_SYSCTL, flags, buf,
-               (size_t)(p - buf)) == -1)
+       if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_SYSCTL, flags, ctx->ps_buf,
+               (size_t)(p - (char *)ctx->ps_buf)) == -1)
                return -1;
 
-       if (ps_root_readerror(ctx, buf, sizeof(buf)) == -1)
+       if (ps_root_readerror(ctx, ctx->ps_buf, ctx->ps_buflen) == -1)
                return -1;
 
-       p = buf;
+       p = ctx->ps_buf;
        memcpy(&nolen, p, sizeof(nolen));
        p += sizeof(nolen);
        if (oldlenp) {
index 558fad92f789f96388b5c4462b147bee53b9a11d..032c71d348c7b4992ee17366c2efe74a61e4099f 100644 (file)
@@ -102,9 +102,14 @@ ps_root_readerrorcb(struct psr_ctx *pc)
                return len;
 
        if (pc->psr_mallocdata) {
-               pc->psr_data = malloc(psr_error->psr_datalen);
-               if (pc->psr_data == NULL)
-                       PSR_ERROR(errno);
+               if (psr_error->psr_datalen > pc->psr_datalen) {
+                       void *nbuf = realloc(pc->psr_data,
+                           psr_error->psr_datalen);
+                       if (nbuf == NULL)
+                               PSR_ERROR(errno);
+                       pc->psr_data = nbuf;
+                       pc->psr_datalen = psr_error->psr_datalen;
+               }
        } else if (psr_error->psr_datalen > pc->psr_datalen)
                PSR_ERROR(EMSGSIZE);
 
@@ -122,10 +127,6 @@ ps_root_readerrorcb(struct psr_ctx *pc)
 
 error:
        psr_error->psr_result = -1;
-       if (pc->psr_mallocdata && pc->psr_data != NULL) {
-               free(pc->psr_data);
-               pc->psr_data = NULL;
-       }
        return -1;
 }
 
@@ -147,16 +148,18 @@ ssize_t
 ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len)
 {
        struct psr_ctx pc = { .psr_ctx = ctx,
-               .psr_data = NULL,
-               .psr_datalen = 0,
+               .psr_data = *data,
+               .psr_datalen = *len,
                .psr_mallocdata = true };
 
        ps_root_readerrorcb(&pc);
 
        errno = pc.psr_error.psr_errno;
        *data = pc.psr_data;
-       *len = pc.psr_error.psr_datalen;
-       return pc.psr_error.psr_result;
+       *len = pc.psr_datalen;
+       if (pc.psr_error.psr_result == -1)
+               return -1;
+       return (ssize_t)pc.psr_error.psr_datalen;
 }
 
 static ssize_t
@@ -438,7 +441,6 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
        struct iovec *iov = msg->msg_iov;
        void *data = iov->iov_base, *rdata = NULL;
        size_t len = iov->iov_len, rlen = 0;
-       uint8_t buf[PS_BUFLEN];
        time_t mtime;
        ssize_t err;
        bool free_rdata = false;
@@ -534,9 +536,9 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
                        err = -1;
                        break;
                }
-               err = readfile(data, buf, sizeof(buf));
+               err = readfile(data, &ctx->ps_buf, &ctx->ps_buflen);
                if (err != -1) {
-                       rdata = buf;
+                       rdata = ctx->ps_buf;
                        rlen = (size_t)err;
                }
                break;
@@ -565,10 +567,13 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 #endif
 #ifdef PRIVSEP_GETHOSTNAME
        case PS_GETHOSTNAME:
-               err = gethostname((char *)buf, sizeof(buf));
+               err = ps_bufalloc(ctx, _POSIX_HOST_NAME_MAX + 1);
+               if (err == -1)
+                       break;
+               err = gethostname((char *)ctx->ps_buf, ctx->ps_buflen);
                if (err != -1) {
-                       rdata = buf;
-                       rlen = strlen((char *)buf) + 1;
+                       rdata = ctx->ps_buf;
+                       rlen = strlen((char *)ctx->ps_buf) + 1;
                }
                break;
 #endif
@@ -858,8 +863,6 @@ ps_root_start(struct dhcpcd_ctx *ctx)
        if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, datafd) == -1)
                return -1;
 
-       if (ps_setbuf_fdpair(datafd) == -1)
-               return -1;
 #ifdef PRIVSEP_RIGHTS
        if (ps_rights_limit_fdpair(datafd) == -1)
                return -1;
@@ -969,6 +972,8 @@ ps_root_stop(struct dhcpcd_ctx *ctx)
                ctx->ps_data_fd = -1;
        }
 
+       free(ctx->ps_buf);
+
        /* Only the manager process gets past this point. */
        if (ctx->options & DHCPCD_FORKED) {
                err = 0;
@@ -1042,33 +1047,38 @@ ps_root_unlink(struct dhcpcd_ctx *ctx, const char *file)
 }
 
 ssize_t
-ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data,
-    size_t len)
+ps_root_readfile(struct dhcpcd_ctx *ctx, const char *file, void **data,
+    size_t *len)
 {
        if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_READFILE, 0, file,
                strlen(file) + 1) == -1)
                return -1;
-       return ps_root_readerror(ctx, data, len);
+
+       return ps_root_mreaderror(ctx, data, len);
 }
 
 ssize_t
 ps_root_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
     const void *data, size_t len)
 {
-       char buf[PS_BUFLEN];
-       size_t flen;
+       struct iovec iov[] = {
+               {
+                   .iov_base = UNCONST(file),
+                   .iov_len = strlen(file) + 1,
+               },
+               {
+                   .iov_base = UNCONST(data),
+                   .iov_len = len,
+               },
+       };
+       struct msghdr msg = {
+               .msg_iov = iov,
+               .msg_iovlen = __arraycount(iov),
+       };
 
-       flen = strlcpy(buf, file, sizeof(buf));
-       flen += 1;
-       if (flen > sizeof(buf) || flen + len > sizeof(buf)) {
-               errno = ENOBUFS;
+       if (ps_sendcmdmsg(ctx, PS_ROOT_FD(ctx), PS_WRITEFILE, mode, &msg) == -1)
                return -1;
-       }
-       memcpy(buf + flen, data, len);
 
-       if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_WRITEFILE, mode, buf,
-               flen + len) == -1)
-               return -1;
        return ps_root_readerror(ctx, NULL, 0);
 }
 
@@ -1107,7 +1117,7 @@ ps_root_getifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifahead)
        void *buf = NULL;
        char *bp, *sap;
        socklen_t salen;
-       size_t len;
+       size_t len = 0;
        ssize_t err;
 
        if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_GETIFADDRS, 0, NULL, 0) == -1)
index 3901ef4f4a4404e3d419ac9426e8ba013032ad65..58fe8da890eca64108fe50020fb64dfbedb1ec48 100644 (file)
@@ -46,7 +46,7 @@ ssize_t ps_root_mreaderror(struct dhcpcd_ctx *, void **, size_t *);
 ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
 ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *);
 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_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_logreopen(struct dhcpcd_ctx *);
index 4ecad2d9481c61e88c67ed78ab898ec4005329b2..a0806994b7c8465b3bcbc324e175faacb7583d02 100644 (file)
@@ -186,48 +186,6 @@ ps_dropprivs(struct dhcpcd_ctx *ctx)
        return 0;
 }
 
-static int
-ps_setbuf0(int fd, int ctl, int minlen)
-{
-       int len;
-       socklen_t slen;
-
-       slen = sizeof(len);
-       if (getsockopt(fd, SOL_SOCKET, ctl, &len, &slen) == -1)
-               return -1;
-
-#ifdef __linux__
-       len /= 2;
-#endif
-       if (len >= minlen)
-               return 0;
-
-       return setsockopt(fd, SOL_SOCKET, ctl, &minlen, sizeof(minlen));
-}
-
-static int
-ps_setbuf(int fd)
-{
-       /* Ensure we can receive a fully sized privsep message.
-        * Double the send buffer. */
-       int minlen = (int)sizeof(struct ps_msg);
-
-       if (ps_setbuf0(fd, SO_RCVBUF, minlen) == -1 ||
-           ps_setbuf0(fd, SO_SNDBUF, minlen * 2) == -1) {
-               logerr(__func__);
-               return -1;
-       }
-       return 0;
-}
-
-int
-ps_setbuf_fdpair(int fd[])
-{
-       if (ps_setbuf(fd[0]) == -1 || ps_setbuf(fd[1]) == -1)
-               return -1;
-       return 0;
-}
-
 #ifdef PRIVSEP_RIGHTS
 int
 ps_rights_limit_ioctl(int fd)
@@ -348,10 +306,7 @@ ps_startprocess(struct ps_process *psp,
                logerr("%s: socketpair", __func__);
                return -1;
        }
-       if (ps_setbuf_fdpair(fd) == -1) {
-               logerr("%s: ps_setbuf_fdpair", __func__);
-               return -1;
-       }
+
 #ifdef PRIVSEP_RIGHTS
        if (ps_rights_limit_fdpair(fd) == -1) {
                logerr("%s: ps_rights_limit_fdpair", __func__);
@@ -522,6 +477,23 @@ ps_stopprocess(struct ps_process *psp)
        return err;
 }
 
+int
+ps_bufalloc(struct dhcpcd_ctx *ctx, size_t len)
+{
+       void *nbuf;
+
+       if (ctx->ps_buflen >= len)
+               return 0;
+
+       nbuf = realloc(ctx->ps_buf, len);
+       if (nbuf == NULL)
+               return -1;
+
+       ctx->ps_buf = nbuf;
+       ctx->ps_buflen = len;
+       return 0;
+}
+
 int
 ps_start(struct dhcpcd_ctx *ctx)
 {
@@ -529,6 +501,11 @@ ps_start(struct dhcpcd_ctx *ctx)
        uint32_t rnd;
 
        TAILQ_INIT(&ctx->ps_processes);
+       /* Alloc a reasonable buffer up front */
+       if (ps_bufalloc(ctx, BUFSIZ) == -1) {
+               logerr("%s: ps_bufalloc", __func__);
+               return -1;
+       }
 
        switch (pid = ps_root_start(ctx)) {
        case -1:
@@ -1073,7 +1050,6 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
     void *cbctx)
 {
        struct ps_msghdr psm;
-       uint8_t ps_data[PS_BUFLEN];
        ssize_t len;
        size_t dlen;
        struct iovec iov[1];
@@ -1126,18 +1102,16 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd, unsigned short events,
        dlen = psm.ps_namelen + psm.ps_controllen + cmsg_padlen +
            psm.ps_datalen;
        if (dlen != 0) {
-               if (dlen > sizeof(ps_data)) {
-                       errno = EMSGSIZE;
+               if (ps_bufalloc(ctx, dlen) == -1)
                        goto stop;
-               }
-               len = recv(fd, ps_data, dlen, MSG_WAITALL);
+               len = recv(fd, ctx->ps_buf, dlen, MSG_WAITALL);
                if ((size_t)len != dlen) {
                        errno = EINVAL;
                        goto stop;
                }
        }
 
-       if (ps_unrollmsg(&msg, &psm, ps_data, dlen) == -1)
+       if (ps_unrollmsg(&msg, &psm, ctx->ps_buf, dlen) == -1)
                return -1;
 
        if (callback == NULL)
index 2141acd0228189bf9c97d0fcee4f189fc426ccb1..8c6ec05463a98496ee2a63a57b39f89e2da382fd 100644 (file)
 #define PS_SYSCTL_ODATA 0x0002
 
 /* Process commands */
-#define PS_START 0x4000
-#define PS_STOP         0x8000
-
-#ifdef INET6
-#define PS_BUFLEN6 CMSG_SPACE(sizeof(struct in6_pktinfo) + sizeof(int))
-#else
-#define PS_BUFLEN6 0
-#endif
-
-/* Max INET message size + meta data for IPC */
-#define PS_BUFLEN                                                         \
-       ((64 * 1024) + sizeof(struct ps_msghdr) + sizeof(struct msghdr) + \
-           PS_BUFLEN6)
+#define PS_START     0x4000
+#define PS_STOP             0x8000
 
 #define PSP_NAMESIZE 16 + INET_MAX_ADDRSTRLEN
 
@@ -169,11 +158,6 @@ struct ps_msghdr {
        size_t ps_datalen;
 };
 
-struct ps_msg {
-       struct ps_msghdr psm_hdr;
-       uint8_t psm_data[PS_BUFLEN];
-};
-
 struct bpf;
 
 struct ps_process {
@@ -209,6 +193,7 @@ TAILQ_HEAD(ps_process_head, ps_process);
 #include "privsep-bpf.h"
 #endif
 
+int ps_bufalloc(struct dhcpcd_ctx *, size_t);
 int ps_init(struct dhcpcd_ctx *);
 int ps_start(struct dhcpcd_ctx *);
 int ps_stop(struct dhcpcd_ctx *);
@@ -232,9 +217,6 @@ ssize_t ps_recvmsg(int, unsigned short, uint16_t, int);
 ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, unsigned short,
     ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *);
 
-/* Internal privsep functions. */
-int ps_setbuf_fdpair(int[]);
-
 #ifdef PRIVSEP_RIGHTS
 int ps_rights_limit_ioctl(int);
 int ps_rights_limit_fd_fctnl(int);