]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Fix returning indirect ioctl data
authorRoy Marples <roy@marples.name>
Thu, 4 Jun 2020 10:25:11 +0000 (11:25 +0100)
committerRoy Marples <roy@marples.name>
Thu, 4 Jun 2020 10:25:11 +0000 (11:25 +0100)
src/privsep-bsd.c
src/privsep-linux.c
src/privsep-root.c
src/privsep-root.h
src/privsep-sun.c

index aa63bcd453a37c69bf8a388d8434aef68c224b5b..28b74354096830e91c0c699566f9e3ada5198a41 100644 (file)
@@ -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,
index 1cfd3efdea008fbe9db2d13035f3c29c7797a678..203bc17787e8a654a5bed1c0624473861865e3e1 100644 (file)
@@ -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) {
index 93cb8a290e0f3a714366f176a55ba13baaccbc81..5c91b4a82b1fe9598642203f12f3daff5826dd48 100644 (file)
@@ -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;
        }
 
index 683e56543736c5b934c7e19bede70feabbf473fd..a8e34227a2388cb84a7c580e0a331b9cebb831b9 100644 (file)
@@ -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);
index ed6e5d3a95f8168ef39b7c0c026d0768e57f4a3a..f406f4ee94a0f10a0b8d6647ec48f2611cfd2feb 100644 (file)
@@ -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