We always send a header with the expected lengths.
So use malloced buffers to send and receive using this
knowledge.
}
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
* 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;
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++)
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
}
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
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;
}
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 *);
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;
/* 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);
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;
}
#endif
out:
- *bootp = malloc(bytes);
- if (*bootp == NULL) {
- logerr(__func__);
- return 0;
- }
- memcpy(*bootp, buf.buf, bytes);
return bytes;
}
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;
#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;
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 */
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;
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;
#endif
free(ctx.script_buf);
free(ctx.script_env);
+ free(ctx.io_buf);
rt_dispose(&ctx);
free(ctx.duid);
if_closesockets(&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;
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
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;
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;
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;
}
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;
/* 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)
}
/* 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)
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);
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) {
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);
error:
psr_error->psr_result = -1;
- if (pc->psr_mallocdata && pc->psr_data != NULL) {
- free(pc->psr_data);
- pc->psr_data = NULL;
- }
return -1;
}
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
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;
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;
#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
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;
ctx->ps_data_fd = -1;
}
+ free(ctx->ps_buf);
+
/* Only the manager process gets past this point. */
if (ctx->options & DHCPCD_FORKED) {
err = 0;
}
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);
}
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)
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 *);
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)
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__);
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)
{
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:
void *cbctx)
{
struct ps_msghdr psm;
- uint8_t ps_data[PS_BUFLEN];
ssize_t len;
size_t dlen;
struct iovec iov[1];
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)
#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
size_t ps_datalen;
};
-struct ps_msg {
- struct ps_msghdr psm_hdr;
- uint8_t psm_data[PS_BUFLEN];
-};
-
struct bpf;
struct 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 *);
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);