changeset 5310:0a6bde63868b draft

privsep: Remove pledges inet and dns from the master process Achieved by adding IPC to ignore interfaces names based on the interface group. This means every process just pledges stdio for IPC which the exception of the master process which also pledges route so it can access the routing table.
author Roy Marples <roy@marples.name>
date Fri, 05 Jun 2020 11:12:21 +0100
parents 700fa2afe696
children fd78486b12a7
files src/dhcpcd.c src/if-bsd.c src/if.h src/privsep-bsd.c src/privsep-root.h src/privsep.h
diffstat 6 files changed, 73 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/src/dhcpcd.c	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/dhcpcd.c	Fri Jun 05 11:12:21 2020 +0100
@@ -2309,7 +2309,7 @@
 		}
 #endif
 #ifdef HAVE_PLEDGE
-		if (pledge("stdio inet route dns", NULL) == -1) {
+		if (pledge("stdio route", NULL) == -1) {
 			logerr("%s: pledge", __func__);
 			goto exit_failure;
 		}
--- a/src/if-bsd.c	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/if-bsd.c	Fri Jun 05 11:12:21 2020 +0100
@@ -292,6 +292,38 @@
 	return false;
 }
 
+#ifdef SIOCGIFGROUP
+int
+if_ignoregroup(int s, const char *ifname)
+{
+	struct ifgroupreq ifgr = { .ifgr_len = 0 };
+	struct ifg_req *ifg;
+	size_t ifg_len;
+
+	/* Sadly it is possible to remove the device name
+	 * from the interface groups, but hopefully this
+	 * will be very unlikely.... */
+
+	strlcpy(ifgr.ifgr_name, ifname, sizeof(ifgr.ifgr_name));
+	if (ioctl(s, SIOCGIFGROUP, &ifgr) == -1 ||
+	    (ifgr.ifgr_groups = malloc(ifgr.ifgr_len)) == NULL ||
+	    ioctl(s, SIOCGIFGROUP, &ifgr) == -1)
+	{
+		logerr(__func__);
+		return -1;
+	}
+
+	for (ifg = ifgr.ifgr_groups, ifg_len = ifgr.ifgr_len;
+	     ifg && ifg_len >= sizeof(*ifg);
+	     ifg++, ifg_len -= sizeof(*ifg))
+	{
+		if (if_ignore1(ifg->ifgrq_group))
+			return 1;
+	}
+	return 0;
+}
+#endif
+
 bool
 if_ignore(struct dhcpcd_ctx *ctx, const char *ifname)
 {
@@ -304,38 +336,17 @@
 		return true;
 
 #ifdef SIOCGIFGROUP
-#ifdef HAVE_PLEDGE
-#warning Fix SIOCGIFGROUP to use privsep to remove inet pledge requirement
+#if defined(PRIVSEP) && defined(HAVE_PLEDGE)
+	if (IN_PRIVSEP(ctx))
+		return ps_root_ifignoregroup(ctx, ifname) == 1 ? true : false;
 #endif
-	struct ifgroupreq ifgr = { .ifgr_len = 0 };
-	struct ifg_req *ifg;
-	size_t ifg_len;
-
-	/* Sadly it is possible to remove the device name
-	 * from the interface groups, but hopefully this
-	 * will be very unlikely.... */
-
-	strlcpy(ifgr.ifgr_name, ifname, sizeof(ifgr.ifgr_name));
-	if (ioctl(ctx->pf_inet_fd, SIOCGIFGROUP, &ifgr) == -1 ||
-	    (ifgr.ifgr_groups = malloc(ifgr.ifgr_len)) == NULL ||
-	    ioctl(ctx->pf_inet_fd, SIOCGIFGROUP, &ifgr) == -1)
-	{
-		logerr(__func__);
-		return false;
-	}
-
-	for (ifg = ifgr.ifgr_groups, ifg_len = ifgr.ifgr_len;
-	     ifg && ifg_len >= sizeof(*ifg);
-	     ifg++, ifg_len -= sizeof(*ifg))
-	{
-		if (if_ignore1(ifg->ifgrq_group))
-			return true;
-	}
+	else
+		return if_ignoregroup(ctx->pf_inet_fd, ifname) == 1 ?
+		    true : false;
 #else
 	UNUSED(ctx);
+	return false;
 #endif
-
-	return false;
 }
 
 int
--- a/src/if.h	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/if.h	Fri Jun 05 11:12:21 2020 +0100
@@ -182,6 +182,7 @@
 int if_conf(struct interface *);
 int if_init(struct interface *);
 int if_getssid(struct interface *);
+int if_ignoregroup(int, const char *);
 bool if_ignore(struct dhcpcd_ctx *, const char *);
 int if_vimaster(struct dhcpcd_ctx *ctx, const char *);
 unsigned short if_vlanid(const struct interface *);
--- a/src/privsep-bsd.c	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/privsep-bsd.c	Fri Jun 05 11:12:21 2020 +0100
@@ -136,6 +136,24 @@
 
 	return ps_root_doioctldom(PF_INET, req, &ifr, sizeof(ifr));
 }
+
+static ssize_t
+ps_root_doifignoregroup(void *data, size_t len)
+{
+	int s, err;
+
+	if (len == 0 || ((const char *)data)[len - 1] != '\0') {
+		errno = EINVAL;
+		return -1;
+	}
+
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		return -1;
+	err = if_ignoregroup(s, data);
+	close(s);
+	return err;
+}
 #endif
 
 ssize_t
@@ -160,6 +178,8 @@
 	case PS_IOCTLINDIRECT:
 		err = ps_root_doindirectioctl(psm->ps_flags, data, len);
 		break;
+	case PS_IFIGNOREGRP:
+		return ps_root_doifignoregroup(data, len);
 #endif
 	default:
 		errno = ENOTSUP;
@@ -228,4 +248,14 @@
 		return -1;
 	return ps_root_readerror(ctx, data, len);
 }
+
+ssize_t
+ps_root_ifignoregroup(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IFIGNOREGRP, 0,
+	    ifname, strlen(ifname) + 1) == -1)
+		return -1;
+	return ps_root_readerror(ctx, NULL, 0);
+}
 #endif
--- a/src/privsep-root.h	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/privsep-root.h	Fri Jun 05 11:12:21 2020 +0100
@@ -54,6 +54,7 @@
 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_ifignoregroup(struct dhcpcd_ctx *, const char *);
 #endif
 #ifdef __linux__
 ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
--- a/src/privsep.h	Thu Jun 04 21:49:37 2020 +0100
+++ b/src/privsep.h	Fri Jun 05 11:12:21 2020 +0100
@@ -57,6 +57,7 @@
 #define	PS_IOCTLINDIRECT	0x0103
 #define	PS_IP6FORWARDING	0x0104
 #define	PS_GETIFADDRS		0x0105
+#define	PS_IFIGNOREGRP		0x0106
 
 /* Dev Commands */
 #define	PS_DEV_LISTENING	0x0201