summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-06-04 11:25:11 +0100
committerRoy Marples <roy@marples.name>2020-06-04 11:25:11 +0100
commit35f1d12310266ac17a24643ac9eefba13a103899 (patch)
tree902af2fac4f6a0a1045b6b427707375d5eed0d6c
parent2f16f1f6245649b1784da9835ff580d280ede1bf (diff)
downloaddhcpcd-35f1d12310266ac17a24643ac9eefba13a103899.tar.xz
privsep: Fix returning indirect ioctl data
-rw-r--r--src/privsep-bsd.c54
-rw-r--r--src/privsep-linux.c3
-rw-r--r--src/privsep-root.c2
-rw-r--r--src/privsep-root.h2
-rw-r--r--src/privsep-sun.c12
5 files changed, 48 insertions, 25 deletions
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