summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure15
-rw-r--r--src/dhcpcd.c31
-rw-r--r--src/if-bsd.c50
-rw-r--r--src/if.c5
-rw-r--r--src/if.h7
-rw-r--r--src/ipv6.c16
-rw-r--r--src/ipv6nd.c4
-rw-r--r--src/privsep-bpf.c10
-rw-r--r--src/privsep-bsd.c18
-rw-r--r--src/privsep-inet.c6
-rw-r--r--src/privsep-root.c2
-rw-r--r--src/privsep-root.h1
-rw-r--r--src/privsep.c18
-rw-r--r--src/privsep.h4
14 files changed, 141 insertions, 46 deletions
diff --git a/configure b/configure
index b38fe6c1..98410a8f 100755
--- 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
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index 4c61c6f0..e17bebc0 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -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))
diff --git a/src/if-bsd.c b/src/if-bsd.c
index 15d20168..e75952e2 100644
--- a/src/if-bsd.c
+++ b/src/if-bsd.c
@@ -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;
diff --git a/src/if.c b/src/if.c
index 3fbb38f7..e479dc35 100644
--- 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;
diff --git a/src/if.h b/src/if.h
index 0a2fc6cb..f58b3028 100644
--- 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 *);
diff --git a/src/ipv6.c b/src/ipv6.c
index 4ea61019..18d890ef 100644
--- a/src/ipv6.c
+++ b/src/ipv6.c
@@ -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)
diff --git a/src/ipv6nd.c b/src/ipv6nd.c
index ae267c7a..09595bc2 100644
--- a/src/ipv6nd.c
+++ b/src/ipv6nd.c
@@ -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;
diff --git a/src/privsep-bpf.c b/src/privsep-bpf.c
index b1ed821d..fd76576c 100644
--- a/src/privsep-bpf.c
+++ b/src/privsep-bpf.c
@@ -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);
diff --git a/src/privsep-bsd.c b/src/privsep-bsd.c
index 1a105b63..f466156a 100644
--- a/src/privsep-bsd.c
+++ b/src/privsep-bsd.c
@@ -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)
@@ -149,6 +156,17 @@ ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request,
}
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)
{
diff --git a/src/privsep-inet.c b/src/privsep-inet.c
index f0dc79a2..cb8632ec 100644
--- a/src/privsep-inet.c
+++ b/src/privsep-inet.c
@@ -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);
diff --git a/src/privsep-root.c b/src/privsep-root.c
index dcfe3091..9584af84 100644
--- a/src/privsep-root.c
+++ b/src/privsep-root.c
@@ -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;
diff --git a/src/privsep-root.h b/src/privsep-root.h
index 27a481a6..7f8bdc65 100644
--- a/src/privsep-root.h
+++ b/src/privsep-root.h
@@ -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 *);
diff --git a/src/privsep.c b/src/privsep.c
index 51fdf7b7..ac503a53 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -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;
}
diff --git a/src/privsep.h b/src/privsep.h
index 9d156e9e..d64210cd 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -34,6 +34,7 @@
/* Start flags */
#define PSF_DROPPRIVS 0x01
#define PSF_CAP_ENTER 0x02
+#define PSF_PLEDGE 0x04
/* Commands */
#define PS_BOOTP 0x01
@@ -53,9 +54,10 @@
#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