From: Roy Marples Date: Thu, 4 Jun 2020 10:25:11 +0000 (+0100) Subject: privsep: Fix returning indirect ioctl data X-Git-Tag: v9.1.1~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35f1d12310266ac17a24643ac9eefba13a103899;p=thirdparty%2Fdhcpcd.git privsep: Fix returning indirect ioctl data --- diff --git a/src/privsep-bsd.c b/src/privsep-bsd.c index aa63bcd4..28b74354 100644 --- a/src/privsep-bsd.c +++ b/src/privsep-bsd.c @@ -55,6 +55,12 @@ ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len) /* Only allow these ioctls */ switch(req) { +#ifdef SIOCG80211NWID + case SIOCG80211NWID: /* FALLTHROUGH */ +#endif +#ifdef SIOCGETVLAN + case SIOCGETVLAN: /* FALLTHROUGH */ +#endif #ifdef SIOCIFAFATTACH case SIOCIFAFATTACH: /* FALLTHROUGH */ #endif @@ -78,7 +84,7 @@ ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len) case SIOCSIFINFO_IN6: /* FALLTHROUGH */ #endif case SIOCAIFADDR_IN6: /* FALLTHROUGH */ - case SIOCDIFADDR_IN6: /* FALLTHROUGH */ + case SIOCDIFADDR_IN6: break; default: errno = EPERM; @@ -115,53 +121,56 @@ ps_root_doindirectioctl(unsigned long req, void *data, size_t len) { char *p = data; struct ifreq ifr = { .ifr_flags = 0 }; - ssize_t err; - switch(req) { - case SIOCG80211NWID: /* FALLTHROUGH */ - case SIOCGETVLAN: - break; - default: - errno = EPERM; - return -1; - } + /* ioctl filtering is done in ps_root_doioctldom */ - if (len < IFNAMSIZ) { + if (len < IFNAMSIZ + 1) { errno = EINVAL; return -1; } strlcpy(ifr.ifr_name, p, IFNAMSIZ); - ifr.ifr_data = p + IFNAMSIZ; - err = ps_root_doioctldom(PF_INET, req, &ifr, sizeof(ifr)); - if (err != -1) - memmove(data, ifr.ifr_data, len - IFNAMSIZ); - return err; + len -= IFNAMSIZ; + memmove(data, p + IFNAMSIZ, len); + ifr.ifr_data = data; + + return ps_root_doioctldom(PF_INET, req, &ifr, sizeof(ifr)); } #endif ssize_t -ps_root_os(struct ps_msghdr *psm, struct msghdr *msg) +ps_root_os(struct ps_msghdr *psm, struct msghdr *msg, + void **rdata, size_t *rlen) { struct iovec *iov = msg->msg_iov; void *data = iov->iov_base; size_t len = iov->iov_len; + ssize_t err; switch (psm->ps_cmd) { case PS_IOCTLLINK: - return ps_root_doioctldom(PF_LINK, psm->ps_flags, data, len); + err = ps_root_doioctldom(PF_LINK, psm->ps_flags, data, len); + break; case PS_IOCTL6: - return ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len); + err = ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len); + break; case PS_ROUTE: return ps_root_doroute(data, len); #ifdef HAVE_PLEDGE case PS_IOCTLINDIRECT: - return ps_root_doindirectioctl(psm->ps_flags, data, len); + err = ps_root_doindirectioctl(psm->ps_flags, data, len); + break; #endif default: errno = ENOTSUP; return -1; } + + if (err != -1) { + *rdata = data; + *rlen = len; + } + return err; } static ssize_t @@ -207,6 +216,11 @@ ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request, { char buf[PS_BUFLEN]; + if (IFNAMSIZ + len > sizeof(buf)) { + errno = ENOBUFS; + return -1; + } + strlcpy(buf, ifname, IFNAMSIZ); memcpy(buf + IFNAMSIZ, data, len); if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTLINDIRECT, diff --git a/src/privsep-linux.c b/src/privsep-linux.c index 1cfd3efd..203bc177 100644 --- a/src/privsep-linux.c +++ b/src/privsep-linux.c @@ -65,7 +65,8 @@ out: } ssize_t -ps_root_os(struct ps_msghdr *psm, struct msghdr *msg) +ps_root_os(struct ps_msghdr *psm, struct msghdr *msg, + void **rdata, size_t *rlen) { switch (psm->ps_cmd) { diff --git a/src/privsep-root.c b/src/privsep-root.c index 93cb8a29..5c91b4a8 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -580,7 +580,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) break; #endif default: - err = ps_root_os(psm, msg); + err = ps_root_os(psm, msg, &rdata, &rlen); break; } diff --git a/src/privsep-root.h b/src/privsep-root.h index 683e5654..a8e34227 100644 --- a/src/privsep-root.h +++ b/src/privsep-root.h @@ -47,7 +47,7 @@ ssize_t ps_root_script(struct dhcpcd_ctx *, const void *, size_t); int ps_root_getauthrdm(struct dhcpcd_ctx *, uint64_t *); int ps_root_getifaddrs(struct dhcpcd_ctx *, struct ifaddrs **); -ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *); +ssize_t ps_root_os(struct ps_msghdr *, struct msghdr *, void **, size_t *); #if defined(BSD) || defined(__sun) ssize_t ps_root_route(struct dhcpcd_ctx *, void *, size_t); ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t); diff --git a/src/privsep-sun.c b/src/privsep-sun.c index ed6e5d3a..f406f4ee 100644 --- a/src/privsep-sun.c +++ b/src/privsep-sun.c @@ -74,21 +74,29 @@ ps_root_doroute(void *data, size_t len) } ssize_t -ps_root_os(struct ps_msghdr *psm, struct msghdr *msg) +ps_root_os(struct ps_msghdr *psm, struct msghdr *msg, + void **rdata, size_t *rlen) { struct iovec *iov = msg->msg_iov; void *data = iov->iov_base; size_t len = iov->iov_len; + ssize_t err; switch (psm->ps_cmd) { case PS_IOCTL6: - return ps_root_doioctl6(psm->ps_flags, data, len); + err = ps_root_doioctl6(psm->ps_flags, data, len); case PS_ROUTE: return ps_root_doroute(data, len); default: errno = ENOTSUP; return -1; } + + if (err != -1) { + *rdata = data; + *rlen = len; + } + return err; } ssize_t