From: Marian Cingel Date: Tue, 31 Aug 2021 12:33:20 +0000 (+0100) Subject: privsep: Enforce proper alignment of serialized struct cmsghdr X-Git-Tag: v9.4.1~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3edf2b11831fde2253867414b75690a9b292b67d;p=thirdparty%2Fdhcpcd.git privsep: Enforce proper alignment of serialized struct cmsghdr Fixes #43. --- diff --git a/src/privsep.c b/src/privsep.c index e939fb50..d574a2bc 100644 --- a/src/privsep.c +++ b/src/privsep.c @@ -81,6 +81,15 @@ #include #endif +/* CMSG_ALIGN is a Linux extension */ +#ifndef CMSG_ALIGN +#define CMSG_ALIGN(n) (CMSG_SPACE((n)) - CMSG_SPACE(0)) +#endif + +/* Calculate number of padding bytes to achieve 'struct cmsghdr' alignment */ +#define CALC_CMSG_PADLEN(has_cmsg, pos) \ + ((has_cmsg) ? (socklen_t)(CMSG_ALIGN((pos)) - (pos)) : 0) + int ps_init(struct dhcpcd_ctx *ctx) { @@ -655,9 +664,11 @@ ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, const void *data, size_t len) { uint8_t *datap, *namep, *controlp; + socklen_t cmsg_padlen = + CALC_CMSG_PADLEN(psm->ps_controllen, psm->ps_namelen); namep = UNCONST(data); - controlp = namep + psm->ps_namelen; + controlp = namep + psm->ps_namelen + cmsg_padlen; datap = controlp + psm->ps_controllen; if (psm->ps_namelen != 0) { @@ -677,7 +688,7 @@ ps_unrollmsg(struct msghdr *msg, struct ps_msghdr *psm, return -1; } msg->msg_control = controlp; - len -= psm->ps_controllen; + len -= psm->ps_controllen + cmsg_padlen; } else msg->msg_control = NULL; msg->msg_controllen = psm->ps_controllen; @@ -698,9 +709,11 @@ ssize_t ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, struct ps_msghdr *psm, const struct msghdr *msg) { + long padding[1] = { 0 }; struct iovec iov[] = { { .iov_base = UNCONST(psm), .iov_len = sizeof(*psm) }, { .iov_base = NULL, }, /* name */ + { .iov_base = NULL, }, /* control padding */ { .iov_base = NULL, }, /* control */ { .iov_base = NULL, }, /* payload 1 */ { .iov_base = NULL, }, /* payload 2 */ @@ -712,6 +725,7 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, if (msg != NULL) { struct iovec *iovp = &iov[1]; int i; + socklen_t cmsg_padlen; psm->ps_namelen = msg->msg_namelen; psm->ps_controllen = (socklen_t)msg->msg_controllen; @@ -719,9 +733,17 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, iovp->iov_base = msg->msg_name; iovp->iov_len = msg->msg_namelen; iovp++; + + cmsg_padlen = + CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); + assert(cmsg_padlen <= sizeof(padding)); + iovp->iov_len = cmsg_padlen; + iovp->iov_base = cmsg_padlen != 0 ? padding : NULL; + iovp++; + iovp->iov_base = msg->msg_control; iovp->iov_len = msg->msg_controllen; - iovlen = 3; + iovlen = 4; for (i = 0; i < (int)msg->msg_iovlen; i++) { if ((size_t)(iovlen + i) > __arraycount(iov)) { @@ -832,6 +854,8 @@ ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) { .iov_base = data, .iov_len = 0 }, }; size_t dl = sizeof(data); + socklen_t cmsg_padlen = + CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); if (msg->msg_namelen != 0) { if (msg->msg_namelen > dl) @@ -843,8 +867,13 @@ ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) } if (msg->msg_controllen != 0) { - if (msg->msg_controllen > dl) + if (msg->msg_controllen + cmsg_padlen > dl) goto nobufs; + if (cmsg_padlen != 0) { + memset(p, 0, cmsg_padlen); + p += cmsg_padlen; + dl -= cmsg_padlen; + } psm.ps_controllen = (socklen_t)msg->msg_controllen; memcpy(p, msg->msg_control, msg->msg_controllen); p += msg->msg_controllen; @@ -855,7 +884,8 @@ ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) if (psm.ps_datalen > dl) goto nobufs; - iov[1].iov_len = psm.ps_namelen + psm.ps_controllen + psm.ps_datalen; + iov[1].iov_len = + psm.ps_namelen + psm.ps_controllen + psm.ps_datalen + cmsg_padlen; if (psm.ps_datalen != 0) memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); return writev(fd, iov, __arraycount(iov));