Skip to content

Commit 5272125

Browse files
committed
BSD: don't send uninitialised memory using ps_root_indirectioctl
This will affect FreeBSD and OpenBSD. Use sendmsg to send the length of the interface name, then the interface name and then the data rather than just sending IFNAMSIZ which may have uninitialised bytes at the end. Opimise ps_sendcmdmsg while here. Hopefully helps #565 but I'm not hopeful.
1 parent 288eb43 commit 5272125

File tree

3 files changed

+45
-66
lines changed

3 files changed

+45
-66
lines changed

src/privsep-bsd.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,26 @@ ps_root_doindirectioctl(struct dhcpcd_ctx *ctx,
149149
{
150150
char *p = data;
151151
struct ifreq ifr = { .ifr_flags = 0 };
152+
size_t ifnamelen;
152153

153154
/* ioctl filtering is done in ps_root_doioctldom */
154155

155-
if (len < IFNAMSIZ + 1) {
156+
if (len < sizeof(ifnamelen)) {
156157
errno = EINVAL;
157158
return -1;
158159
}
160+
memcpy(&ifnamelen, p, sizeof(ifnamelen));
159161

160-
strlcpy(ifr.ifr_name, p, IFNAMSIZ);
161-
len -= IFNAMSIZ;
162-
memmove(data, p + IFNAMSIZ, len);
162+
if (len < ifnamelen || len > sizeof(ifr.ifr_name)) {
163+
errno = EINVAL;
164+
return -1;
165+
}
166+
167+
memcpy(ifr.ifr_name, p, ifnamelen);
168+
len -= ifnamelen;
169+
170+
/* Ensure data is now aligned */
171+
memmove(data, p + ifnamelen, len);
163172
ifr.ifr_data = data;
164173

165174
return ps_root_doioctldom(ctx, PF_INET, req, &ifr, sizeof(ifr));
@@ -337,17 +346,29 @@ ssize_t
337346
ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
338347
const char *ifname, void *data, size_t len)
339348
{
340-
char buf[PS_BUFLEN];
341-
342-
if (IFNAMSIZ + len > sizeof(buf)) {
343-
errno = ENOBUFS;
344-
return -1;
345-
}
346-
347-
strlcpy(buf, ifname, IFNAMSIZ);
348-
memcpy(buf + IFNAMSIZ, data, len);
349-
if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT,
350-
request, buf, IFNAMSIZ + len) == -1)
349+
size_t ifnamelen = strlen(ifname + 1);
350+
351+
struct iovec iov[] = {
352+
{
353+
.iov_base = &ifnamelen,
354+
.iov_len = sizeof(ifnamelen),
355+
},
356+
{
357+
.iov_base = UNCONST(ifname),
358+
.iov_len = ifnamelen,
359+
},
360+
{
361+
.iov_base = data,
362+
.iov_len = len,
363+
}
364+
};
365+
struct msghdr msg = {
366+
.msg_iov = iov,
367+
.msg_iovlen = __arraycount(iov),
368+
};
369+
370+
if (ps_sendcmdmsg(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT,
371+
request, &msg) == -1)
351372
return -1;
352373
return ps_root_readerror(ctx, data, len);
353374
}

src/privsep.c

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd,
914914

915915
len = sendmsg(fd, &m, MSG_EOR);
916916

917-
if (len == -1) {
917+
if (len == -1 && ctx != NULL) {
918918
if (ctx->options & DHCPCD_FORKED &&
919919
!(ctx->options & DHCPCD_PRIVSEPROOT))
920920
eloop_exit(ctx->eloop, EXIT_FAILURE);
@@ -998,57 +998,13 @@ ps_sendcmd(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, unsigned long flags,
998998
return ps_sendpsmmsg(ctx, fd, &psm, &msg);
999999
}
10001000

1001-
static ssize_t
1002-
ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg)
1001+
ssize_t
1002+
ps_sendcmdmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd,
1003+
unsigned long flags, const struct msghdr *msg)
10031004
{
1004-
struct ps_msghdr psm = { .ps_cmd = cmd };
1005-
uint8_t data[PS_BUFLEN], *p = data;
1006-
struct iovec iov[] = {
1007-
{ .iov_base = &psm, .iov_len = sizeof(psm) },
1008-
{ .iov_base = data, .iov_len = 0 },
1009-
};
1010-
struct msghdr m = { .msg_iov = iov, .msg_iovlen = __arraycount(iov) };
1011-
size_t dl = sizeof(data);
1012-
socklen_t cmsg_padlen =
1013-
CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen);
1014-
1015-
if (msg->msg_namelen != 0) {
1016-
if (msg->msg_namelen > dl)
1017-
goto nobufs;
1018-
psm.ps_namelen = msg->msg_namelen;
1019-
memcpy(p, msg->msg_name, msg->msg_namelen);
1020-
p += msg->msg_namelen;
1021-
dl -= msg->msg_namelen;
1022-
}
1023-
1024-
if (msg->msg_controllen != 0) {
1025-
if (msg->msg_controllen + cmsg_padlen > dl)
1026-
goto nobufs;
1027-
if (cmsg_padlen != 0) {
1028-
memset(p, 0, cmsg_padlen);
1029-
p += cmsg_padlen;
1030-
dl -= cmsg_padlen;
1031-
}
1032-
psm.ps_controllen = (socklen_t)msg->msg_controllen;
1033-
memcpy(p, msg->msg_control, msg->msg_controllen);
1034-
p += msg->msg_controllen;
1035-
dl -= msg->msg_controllen;
1036-
}
1037-
1038-
psm.ps_datalen = msg->msg_iov[0].iov_len;
1039-
if (psm.ps_datalen > dl)
1040-
goto nobufs;
1041-
1042-
iov[1].iov_len =
1043-
psm.ps_namelen + psm.ps_controllen + psm.ps_datalen + cmsg_padlen;
1044-
if (psm.ps_datalen != 0)
1045-
memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen);
1005+
struct ps_msghdr psm = { .ps_cmd = cmd, .ps_flags = flags };
10461006

1047-
return sendmsg(fd, &m, MSG_EOR);
1048-
1049-
nobufs:
1050-
errno = ENOBUFS;
1051-
return -1;
1007+
return ps_sendpsmmsg(ctx, fd, &psm, msg);
10521008
}
10531009

10541010
ssize_t
@@ -1077,7 +1033,7 @@ ps_recvmsg(int rfd, unsigned short events, uint16_t cmd, int wfd)
10771033
}
10781034

10791035
iov[0].iov_len = (size_t)len;
1080-
len = ps_sendcmdmsg(wfd, cmd, &msg);
1036+
len = ps_sendcmdmsg(NULL, wfd, cmd, 0, &msg);
10811037
if (len == -1)
10821038
logerr("%s: ps_sendcmdmsg", __func__);
10831039
return len;

src/privsep.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ ssize_t ps_sendmsg(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
222222
const struct msghdr *);
223223
ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long,
224224
const void *data, size_t len);
225+
ssize_t ps_sendcmdmsg(struct dhcpcd_ctx *, int fd, uint16_t cmd,
226+
unsigned long flags, const struct msghdr *msg);
225227
ssize_t ps_recvmsg(int, unsigned short, uint16_t, int);
226228
ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, unsigned short,
227229
ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *);

0 commit comments

Comments
 (0)