changeset 5302:ef799c0ff5cb draft

privsep: Fix returning indirect ioctl data
author Roy Marples <roy@marples.name>
date Thu, 04 Jun 2020 11:25:11 +0100
parents e6f1372f2cf0
children 873d4c26c32a
files src/privsep-bsd.c src/privsep-linux.c src/privsep-root.c src/privsep-root.h src/privsep-sun.c
diffstat 5 files changed, 48 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/privsep-bsd.c	Wed Jun 03 23:30:08 2020 +0100
+++ b/src/privsep-bsd.c	Thu Jun 04 11:25:11 2020 +0100
@@ -55,6 +55,12 @@
 
 	/* 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 @@
 	case SIOCSIFINFO_IN6:	/* FALLTHROUGH */
 #endif
 	case SIOCAIFADDR_IN6:	/* FALLTHROUGH */
-	case SIOCDIFADDR_IN6:	/* FALLTHROUGH */
+	case SIOCDIFADDR_IN6:
 		break;
 	default:
 		errno = EPERM;
@@ -115,53 +121,56 @@
 {
 	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 @@
 {
 	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,
--- a/src/privsep-linux.c	Wed Jun 03 23:30:08 2020 +0100
+++ b/src/privsep-linux.c	Thu Jun 04 11:25:11 2020 +0100
@@ -65,7 +65,8 @@
 }
 
 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) {
--- a/src/privsep-root.c	Wed Jun 03 23:30:08 2020 +0100
+++ b/src/privsep-root.c	Thu Jun 04 11:25:11 2020 +0100
@@ -580,7 +580,7 @@
 		break;
 #endif
 	default:
-		err = ps_root_os(psm, msg);
+		err = ps_root_os(psm, msg, &rdata, &rlen);
 		break;
 	}
 
--- a/src/privsep-root.h	Wed Jun 03 23:30:08 2020 +0100
+++ b/src/privsep-root.h	Thu Jun 04 11:25:11 2020 +0100
@@ -47,7 +47,7 @@
 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);
--- a/src/privsep-sun.c	Wed Jun 03 23:30:08 2020 +0100
+++ b/src/privsep-sun.c	Thu Jun 04 11:25:11 2020 +0100
@@ -74,21 +74,29 @@
 }
 
 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