]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
privsep: Implement pledge(2) support as found on OpenBSD
authorRoy Marples <roy@marples.name>
Sun, 10 May 2020 15:09:54 +0000 (16:09 +0100)
committerRoy Marples <roy@marples.name>
Sun, 10 May 2020 15:09:54 +0000 (16:09 +0100)
14 files changed:
configure
src/dhcpcd.c
src/if-bsd.c
src/if.c
src/if.h
src/ipv6.c
src/ipv6nd.c
src/privsep-bpf.c
src/privsep-bsd.c
src/privsep-inet.c
src/privsep-root.c
src/privsep-root.h
src/privsep.c
src/privsep.h

index b38fe6c18760d6c1fdb564cae8bb4564e34c88d8..98410a8f49d8547d4f22888020e9455d5f8eeed6 100755 (executable)
--- a/configure
+++ b/configure
@@ -663,6 +663,21 @@ EOF
                echo "no"
        fi
        rm -f _capsicum.c _capsicum
+
+       printf "Testing for pledge ... "
+        cat <<EOF >_pledge.c
+#include <unistd.h>
+int main(void) {
+        return pledge("stdio", NULL);
+}
+EOF
+        if $XCC _pledge.c -o _pledge 2>&3; then
+                echo "yes"
+                echo "#define   HAVE_PLEDGE" >>$CONFIG_H
+        else
+                echo "no"
+        fi
+        rm -f _pledge.c _pledge
 fi
 
 if [ "$OS" = linux ]; then
index 4c61c6f0a54240c49b02381a5164e251b3de33ae..e17bebc01c21409b4ebc2baaf4c106ad0136381c 100644 (file)
@@ -1152,6 +1152,7 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
        logerrx("route socket overflowed (rcvbuflen %d)"
            " - learning interface state", rcvbuflen);
 
+#ifndef HAVE_PLEDGE
        /* Close the existing socket and open a new one.
         * This is easier than draining the kernel buffer of an
         * in-determinate size. */
@@ -1163,6 +1164,8 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx)
                eloop_exit(ctx->eloop, EXIT_FAILURE);
                return;
        }
+#endif
+
 #ifndef SMALL
        dhcpcd_setlinkrcvbuf(ctx);
 #endif
@@ -2235,20 +2238,6 @@ printpidfile:
            (DHCPCD_MASTER | DHCPCD_DEV))
                dev_start(&ctx);
 
-#ifdef PRIVSEP
-       if (ctx.options & DHCPCD_PRIVSEP) {
-               /*
-                * PSF_CAP_ENTER is not set because the following functions
-                * won't work in it:
-                * getifaddrs(3), gethostname(3), uname(3).
-                */
-               if (ps_dropprivs(&ctx, 0) == -1) {
-                       logerr("ps_dropprivs");
-                       goto exit_failure;
-               }
-       }
-#endif
-
        setproctitle("%s%s%s",
            ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind],
            ctx.options & DHCPCD_IPV4 ? " [ip4]" : "",
@@ -2262,6 +2251,20 @@ printpidfile:
        dhcpcd_setlinkrcvbuf(&ctx);
 #endif
 
+#ifdef PRIVSEP
+       if (ctx.options & DHCPCD_PRIVSEP) {
+               /*
+                * PSF_CAP_ENTER is not set because the following functions
+                * won't work in it:
+                * getifaddrs(3), gethostname(3), uname(3).
+                */
+               if (ps_dropprivs(&ctx, PSF_PLEDGE) == -1) {
+                       logerr("ps_dropprivs");
+                       goto exit_failure;
+               }
+       }
+#endif
+
        /* When running dhcpcd against a single interface, we need to retain
         * the old behaviour of waiting for an IP address */
        if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND))
index 15d20168db22d7fca4528edf86760de15979746e..e75952e202279c56ee558f4233e07ecfd353e144 100644 (file)
@@ -298,6 +298,9 @@ if_ignore(struct dhcpcd_ctx *ctx, const char *ifname)
                return true;
 
 #ifdef SIOCGIFGROUP
+#ifdef HAVE_PLEDGE
+#warning Fix SIOCGIFGROUP for to remove inet pledge requirement
+#endif
        struct ifgroupreq ifgr = { .ifgr_len = 0 };
        struct ifg_req *ifg;
        size_t ifg_len;
@@ -354,27 +357,25 @@ if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp)
 }
 
 #if defined(SIOCG80211NWID) || defined(SIOCGETVLAN)
-static int if_direct_ioctl(int s, const char *ifname,
-    unsigned long cmd, void *data)
+static int if_indirect_ioctl(struct dhcpcd_ctx *ctx,
+    const char *ifname, unsigned long cmd, void *data, size_t len)
 {
 
-       strlcpy(data, ifname, IFNAMSIZ);
-       return ioctl(s, cmd, data);
-}
-
-static int if_indirect_ioctl(int s, const char *ifname,
-    unsigned long cmd, void *data)
-{
-       struct ifreq ifr;
+#ifdef HAVE_PLEDGE
+       return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len);
+#else
+       struct ifreq ifr = { .ifr_flags = 0 };
 
-       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(data, ifname, IFNAMSIZ);
        ifr.ifr_data = data;
-       return if_direct_ioctl(s, ifname, cmd, &ifr);
+       UNUSED(len);
+       return ioctl(ctx->pf_inet_fd, cmd, &ifr);
+#endif
 }
 #endif
 
 static int
-if_getssid1(int s, const char *ifname, void *ssid)
+if_getssid1(struct dhcpcd_ctx *ctx, const char *ifname, void *ssid)
 {
        int retval = -1;
 #if defined(SIOCG80211NWID)
@@ -386,7 +387,9 @@ if_getssid1(int s, const char *ifname, void *ssid)
 
 #if defined(SIOCG80211NWID) /* NetBSD */
        memset(&nwid, 0, sizeof(nwid));
-       if (if_indirect_ioctl(s, ifname, SIOCG80211NWID, &nwid) == 0) {
+       if (if_indirect_ioctl(ctx, ifname, SIOCG80211NWID,
+           &nwid, sizeof(nwid)) == 0)
+       {
                if (ssid == NULL)
                        retval = nwid.i_len;
                else if (nwid.i_len > IF_SSIDLEN)
@@ -403,7 +406,7 @@ if_getssid1(int s, const char *ifname, void *ssid)
        ireq.i_val = -1;
        memset(nwid, 0, sizeof(nwid));
        ireq.i_data = &nwid;
-       if (ioctl(s, SIOCG80211, &ireq) == 0) {
+       if (ioctl(ctx->pf_inet_fd, SIOCG80211, &ireq) == 0) {
                if (ssid == NULL)
                        retval = ireq.i_len;
                else if (ireq.i_len > IF_SSIDLEN)
@@ -425,7 +428,7 @@ if_getssid(struct interface *ifp)
 {
        int r;
 
-       r = if_getssid1(ifp->ctx->pf_inet_fd, ifp->name, ifp->ssid);
+       r = if_getssid1(ifp->ctx, ifp->name, ifp->ssid);
        if (r != -1)
                ifp->ssid_len = (unsigned int)r;
        else
@@ -442,7 +445,7 @@ if_getssid(struct interface *ifp)
  * returning the SSID gives an error.
  */
 int
-if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname)
+if_vimaster(struct dhcpcd_ctx *ctx, const char *ifname)
 {
        int r;
        struct ifmediareq ifmr;
@@ -455,7 +458,7 @@ if_vimaster(const struct dhcpcd_ctx *ctx, const char *ifname)
        if (ifmr.ifm_status & IFM_AVALID &&
            IFM_TYPE(ifmr.ifm_active) == IFM_IEEE80211)
        {
-               if (if_getssid1(ctx->pf_inet_fd, ifname, NULL) == -1)
+               if (if_getssid1(ctx, ifname, NULL) == -1)
                        return 1;
        }
        return 0;
@@ -465,17 +468,15 @@ unsigned short
 if_vlanid(const struct interface *ifp)
 {
 #ifdef SIOCGETVLAN
-       struct vlanreq vlr;
+       struct vlanreq vlr = { .vlr_tag = 0 };
 
-       memset(&vlr, 0, sizeof(vlr));
-       if (if_indirect_ioctl(ifp->ctx->pf_inet_fd,
-           ifp->name, SIOCGETVLAN, &vlr) != 0)
+       if (if_indirect_ioctl(ifp->ctx, ifp->name, SIOCGETVLAN,
+           &vlr, sizeof(vlr)) != 0)
                return 0; /* 0 means no VLANID */
        return vlr.vlr_tag;
 #elif defined(SIOCGVNETID)
-       struct ifreq ifr;
+       struct ifreq ifr = { .ifr_vnetid = 0 };
 
-       memset(&ifr, 0, sizeof(ifr));
        strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
        if (ioctl(ifp->ctx->pf_inet_fd, SIOCGVNETID, &ifr) != 0)
                return 0; /* 0 means no VLANID */
@@ -1569,6 +1570,7 @@ if_machinearch(char *str, size_t len)
        char march[SYS_NMLN];
        size_t marchlen = sizeof(march);
 
+return -1;
        if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
            march, &marchlen, NULL, 0) != 0)
                return -1;
index 3fbb38f761da4bfcee432d019d2345749d571055..e479dc355b27191be3c60d0c45e0300b6f493414 100644 (file)
--- a/src/if.c
+++ b/src/if.c
@@ -617,7 +617,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
                /* Respect the interface priority */
                memset(&ifr, 0, sizeof(ifr));
                strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
-               if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
+               if (pioctl(ctx, SIOCGIFPRIORITY, &ifr, sizeof(ifr)) == 0)
                        ifp->metric = (unsigned int)ifr.ifr_metric;
                if_getssid(ifp);
 #else
@@ -771,7 +771,8 @@ if_domtu(const struct interface *ifp, short int mtu)
        if (mtu != 0)
                r = if_ioctl(ifp->ctx, SIOCSIFMTU, &ifr, sizeof(ifr));
        else
-               r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMTU, &ifr);
+               r = pioctl(ifp->ctx, SIOCGIFMTU, &ifr, sizeof(ifr));
+
        if (r == -1)
                return -1;
        return ifr.ifr_mtu;
index 0a2fc6cb3a26a3af41ea47eeeca16b6a298a14b4..f58b3028fec05d8455bdaee03c93ba996a3892c3 100644 (file)
--- a/src/if.h
+++ b/src/if.h
@@ -126,6 +126,11 @@ int if_getsubnet(struct dhcpcd_ctx *, const char *, int, void *, size_t);
 #endif
 
 int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t);
+#ifdef HAVE_PLEDGE
+#define        pioctl(ctx, req, data, len) if_ioctl((ctx), (req), (data), (len))
+#else
+#define        pioctl(ctx, req, data, len) ioctl((ctx)->pf_inet_fd, (req),(data),(len))
+#endif
 int if_getflags(struct interface *);
 int if_setflag(struct interface *, short, short);
 #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING), 0)
@@ -171,7 +176,7 @@ int if_conf(struct interface *);
 int if_init(struct interface *);
 int if_getssid(struct interface *);
 bool if_ignore(struct dhcpcd_ctx *, const char *);
-int if_vimaster(const struct dhcpcd_ctx *ctx, const char *);
+int if_vimaster(struct dhcpcd_ctx *ctx, const char *);
 unsigned short if_vlanid(const struct interface *);
 int if_opensockets(struct dhcpcd_ctx *);
 int if_opensockets_os(struct dhcpcd_ctx *);
index 4ea6101957ba0b5d7dfe957bc50c41e3ec493354..18d890ef1d7f6227eb85c3092c66c0137510e059 100644 (file)
@@ -69,6 +69,7 @@
 #include "ipv6.h"
 #include "ipv6nd.h"
 #include "logerr.h"
+#include "privsep.h"
 #include "sa.h"
 #include "script.h"
 
@@ -1094,10 +1095,25 @@ ipv6_anyglobal(struct interface *sifp)
        struct interface *ifp;
        struct ipv6_state *state;
        struct ipv6_addr *ia;
+#ifdef BSD
+       bool forwarding;
+
+#ifdef HAVE_PLEDGE
+       forwarding = ps_root_ip6forwarding(sifp->ctx) == 1;
+#else
+       forwarding = ip6_forwarding(NULL) == 1;
+#endif
+#endif
+
 
        TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
+#ifdef BSD
+               if (ifp != sifp && !forwarding)
+                       continue;
+#else
                if (ifp != sifp && ip6_forwarding(ifp->name) != 1)
                        continue;
+#endif
 
                state = IPV6_STATE(ifp);
                if (state == NULL)
index ae267c7acae9dfb1c2ce6c0ce9330319385fa03d..09595bc2c6c3b4f48664a33183b39c07604cda38 100644 (file)
@@ -524,7 +524,11 @@ ipv6nd_advertise(struct ipv6_addr *ia)
 
        na->nd_na_type = ND_NEIGHBOR_ADVERT;
        na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
+#ifdef HAVE_PLEDGE
+       if (ps_root_ip6_forwarding(ctx) == 1)
+#else
        if (ip6_forwarding(ifp->name) == 1)
+#endif
                na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
        na->nd_na_target = ia->addr;
 
index b1ed821d2923c84bb2e22404c0e12580987d0d20..fd76576cc305253622562a67951f69516610d702 100644 (file)
@@ -203,6 +203,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
        struct iovec *iov = msg->msg_iov;
        struct interface *ifp;
        struct ipv4_state *istate;
+       unsigned int flags = PSF_DROPPRIVS | PSF_CAP_ENTER;
 
        cmd = (uint8_t)(psm->ps_cmd & ~(PS_START | PS_STOP));
        psp = ps_findprocess(ctx, &psm->ps_id);
@@ -256,12 +257,19 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
                psp->psp_proto = ETHERTYPE_ARP;
                psp->psp_protostr = "ARP";
                psp->psp_filter = bpf_arp;
+               /*
+                * Pledge is currently useless for BPF ARP because we cannot
+                * change the filter:
+                * http://openbsd-archive.7691.n7.nabble.com/ \
+                *        pledge-bpf-32bit-arch-unbreak-td299901.html
+                */
                break;
 #endif
        case PS_BPF_BOOTP:
                psp->psp_proto = ETHERTYPE_IP;
                psp->psp_protostr = "BOOTP";
                psp->psp_filter = bpf_bootp;
+               flags |= PSF_PLEDGE;
                break;
        }
 
@@ -269,7 +277,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
            &psp->psp_pid, &psp->psp_fd,
            ps_bpf_recvmsg, NULL, psp,
            ps_bpf_start_bpf, ps_bpf_signal_bpfcb,
-           PSF_DROPPRIVS | PSF_CAP_ENTER);
+           flags);
        switch (start) {
        case -1:
                ps_freeprocess(psp);
index 1a105b63a620820117a41940efd1f90c3d1de4a5..f466156ac0ddf56283f44027ba138de12f497e8b 100644 (file)
@@ -49,6 +49,7 @@ ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len)
        return err;
 }
 
+#ifdef HAVE_PLEDGE
 static ssize_t
 ps_root_doindirectioctl(unsigned long req, void *data, size_t len)
 {
@@ -68,6 +69,7 @@ ps_root_doindirectioctl(unsigned long req, void *data, size_t len)
                memmove(data, ifr.ifr_data, len - IFNAMSIZ);
        return err;
 }
+#endif
 
 static ssize_t
 ps_root_doroute(void *data, size_t len)
@@ -97,8 +99,12 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg)
                return ps_root_doioctldom(PF_LINK, psm->ps_flags, data, len);
        case PS_IOCTL6:
                return ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len);
+#ifdef HAVE_PLEDGE
        case PS_IOCTLINDIRECT:
                return ps_root_doindirectioctl(psm->ps_flags, data, len);
+       case PS_IP6FORWARDING:
+               return ip6_forwarding(NULL);
+#endif
        case PS_ROUTE:
                return ps_root_doroute(data, len);
        default:
@@ -134,6 +140,7 @@ ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request,
        return ps_root_ioctldom(ctx, PS_IOCTL6, request, data, len);
 }
 
+#ifdef HAVE_PLEDGE
 ssize_t
 ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
     const char *ifname, void *data, size_t len)
@@ -148,6 +155,17 @@ ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
        return ps_root_readerror(ctx, data, len);
 }
 
+ssize_t
+ps_root_ip6forwarding(struct dhcpcd_ctx *ctx)
+{
+
+       if (ps_sendcmd(ctx, ctx->ps_root_fd,
+           PS_IP6FORWARDING, 0, NULL, 0) == -1)
+               return -1;
+       return ps_root_readerror(ctx, NULL, 0);
+}
+#endif
+
 ssize_t
 ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len)
 {
index f0dc79a205529638abac9b7ee1d0f1312ea70de8..cb8632ecd10069ed1e9ccff1d7c591dee345a855 100644 (file)
@@ -308,7 +308,8 @@ ps_inet_start(struct dhcpcd_ctx *ctx)
 
        return ps_dostart(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd,
            ps_inet_recvmsg, ps_inet_dodispatch, ctx,
-           ps_inet_startcb, ps_inet_signalcb, PSF_DROPPRIVS);
+           ps_inet_startcb, ps_inet_signalcb,
+           PSF_DROPPRIVS | PSF_PLEDGE);
 }
 
 int
@@ -553,7 +554,8 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm,
        start = ps_dostart(ctx,
            &psp->psp_pid, &psp->psp_fd,
            ps_inet_recvmsgpsp, NULL, psp,
-           start_func, ps_inet_signalcb, PSF_DROPPRIVS);
+           start_func, ps_inet_signalcb,
+           PSF_DROPPRIVS | PSF_PLEDGE);
        switch (start) {
        case -1:
                ps_freeprocess(psp);
index dcfe309122384c72b2ea6da4d3edd686e285fb3a..9584af8400696e3ae132ebf346902f3a4548e8ad 100644 (file)
@@ -380,7 +380,7 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
                break;
        }
 
-       assert(msg->msg_iovlen == 1);
+       assert(msg->msg_iovlen == 0 || msg->msg_iovlen == 1);
 
        /* Reset errno */
        errno = 0;
index 27a481a61be75c61958163946dc76e883d262fd2..7f8bdc6544995d54fe5e1887d3d6aac0d230e1bc 100644 (file)
@@ -46,6 +46,7 @@ ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t);
 ssize_t ps_root_ioctl6(struct dhcpcd_ctx *, unsigned long, void *, size_t);
 ssize_t ps_root_indirectioctl(struct dhcpcd_ctx *, unsigned long, const char *,
     void *, size_t);
+ssize_t ps_root_ip6forwarding(struct dhcpcd_ctx *);
 #endif
 #ifdef __linux__
 ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
index 51fdf7b7a760c8ebc130b9689aeae793a1af6350..ac503a53e231373aadff116aefcb495a08bdc9aa 100644 (file)
@@ -176,6 +176,24 @@ ps_dropprivs(struct dhcpcd_ctx *ctx, unsigned int flags)
 #else
        UNUSED(flags);
 #endif
+
+#ifdef HAVE_PLEDGE
+       if (flags & PSF_PLEDGE) {
+               const char *promises;
+
+               if (ctx->options & DHCPCD_UNPRIV)
+                       promises = "stdio dns bpf";
+               else
+                       /* SIOCGIFGROUP requries inet
+                        * lease files and foo require rpath, wpath and cpath */
+                       promises = "stdio dns inet route rpath wpath cpath";
+                if (pledge(promises, NULL) == -1) {
+                        logerr("%s: pledge", __func__);
+                        return -1;
+                }
+       }
+#endif
+
        return 0;
 }
 
index 9d156e9e1ac4ab28acefa2db482758f7b543709c..d64210cd43cb54b48ef6a61b5dc8160f10e50946 100644 (file)
@@ -34,6 +34,7 @@
 /* Start flags */
 #define        PSF_DROPPRIVS           0x01
 #define        PSF_CAP_ENTER           0x02
+#define        PSF_PLEDGE              0x04
 
 /* Commands */
 #define        PS_BOOTP                0x01
 #define        PS_IOCTLLINK            0x15
 #define        PS_IOCTL6               0x16
 #define        PS_IOCTLINDIRECT        0x17
+#define        PS_IP6FORWARDING        0x18
 
 /* Linux commands */
-#define        PS_WRITEPATHUINT        0x18
+#define        PS_WRITEPATHUINT        0x19
 
 #define        PS_DELETE               0x20
 #define        PS_START                0x40