changeset 5260:7571d82b48da draft

privsep: Allow dev plugins to work For udev at least, it requires a /var/run to be available in the chroot which is poor. As such, give it a full IPC.
author Roy Marples <roy@marples.name>
date Sun, 24 May 2020 10:30:23 +0000
parents d569724efab3
children 33324d44a2e8
files src/dev.c src/dev.h src/dhcpcd.c src/privsep-root.c src/privsep-root.h src/privsep.c src/privsep.h
diffstat 7 files changed, 146 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/dev.c	Sun May 24 05:54:40 2020 +0000
+++ b/src/dev.c	Sun May 24 10:30:23 2020 +0000
@@ -42,6 +42,12 @@
 dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
+#ifdef PRIVSEP
+	if (ctx->options & DHCPCD_PRIVSEP &&
+	    !(ctx->options & DHCPCD_PRIVSEPROOT))
+		return ps_root_dev_initialized(ctx, ifname);
+#endif
+
 	if (ctx->dev == NULL)
 		return 1;
 	return ctx->dev->initialized(ifname);
@@ -51,6 +57,12 @@
 dev_listening(struct dhcpcd_ctx *ctx)
 {
 
+#ifdef PRIVSEP
+	if (ctx->options & DHCPCD_PRIVSEP &&
+	    !(ctx->options & DHCPCD_PRIVSEPROOT))
+		return ps_root_dev_listening(ctx);
+#endif
+
 	if (ctx->dev == NULL)
 		return 0;
 	return ctx->dev->listening();
@@ -79,17 +91,17 @@
 dev_stop(struct dhcpcd_ctx *ctx)
 {
 
-	dev_stop1(ctx,!(ctx->options & DHCPCD_FORKED));
+	dev_stop1(ctx, !(ctx->options & DHCPCD_FORKED));
 }
 
 static int
-dev_start2(struct dhcpcd_ctx *ctx, const char *name)
+dev_start2(struct dhcpcd_ctx *ctx, const struct dev_dhcpcd *dev_dhcpcd,
+    const char *name)
 {
 	char file[PATH_MAX];
 	void *h;
 	void (*fptr)(struct dev *, const struct dev_dhcpcd *);
 	int r;
-	struct dev_dhcpcd dev_dhcpcd;
 
 	snprintf(file, sizeof(file), DEVDIR "/%s", name);
 	h = dlopen(file, RTLD_LAZY);
@@ -108,8 +120,7 @@
 		dlclose(h);
 		return -1;
 	}
-	dev_dhcpcd.handle_interface = &dhcpcd_handleinterface;
-	fptr(ctx->dev, &dev_dhcpcd);
+	fptr(ctx->dev, dev_dhcpcd);
 	if (ctx->dev->start  == NULL || (r = ctx->dev->start()) == -1) {
 		free(ctx->dev);
 		ctx->dev = NULL;
@@ -122,7 +133,7 @@
 }
 
 static int
-dev_start1(struct dhcpcd_ctx *ctx)
+dev_start1(struct dhcpcd_ctx *ctx, const struct dev_dhcpcd *dev_dhcpcd)
 {
 	DIR *dp;
 	struct dirent *d;
@@ -134,7 +145,7 @@
 	}
 
 	if (ctx->dev_load)
-		return dev_start2(ctx, ctx->dev_load);
+		return dev_start2(ctx, dev_dhcpcd, ctx->dev_load);
 
 	dp = opendir(DEVDIR);
 	if (dp == NULL) {
@@ -147,7 +158,7 @@
 		if (d->d_name[0] == '.')
 			continue;
 
-		r = dev_start2(ctx, d->d_name);
+		r = dev_start2(ctx, dev_dhcpcd, d->d_name);
 		if (r != -1)
 			break;
 	}
@@ -167,15 +178,18 @@
 }
 
 int
-dev_start(struct dhcpcd_ctx *ctx)
+dev_start(struct dhcpcd_ctx *ctx, int (*handler)(void *, int, const char *))
 {
+	struct dev_dhcpcd dev_dhcpcd = {
+		.handle_interface = handler,
+	};
 
 	if (ctx->dev_fd != -1) {
 		logerrx("%s: already started on fd %d", __func__, ctx->dev_fd);
 		return ctx->dev_fd;
 	}
 
-	ctx->dev_fd = dev_start1(ctx);
+	ctx->dev_fd = dev_start1(ctx, &dev_dhcpcd);
 	if (ctx->dev_fd != -1) {
 		if (eloop_event_add(ctx->eloop, ctx->dev_fd,
 		    dev_handle_data, ctx) == -1)
--- a/src/dev.h	Sun May 24 05:54:40 2020 +0000
+++ b/src/dev.h	Sun May 24 10:30:23 2020 +0000
@@ -49,7 +49,7 @@
 #include "dhcpcd.h"
 int dev_initialized(struct dhcpcd_ctx *, const char *);
 int dev_listening(struct dhcpcd_ctx *);
-int dev_start(struct dhcpcd_ctx *);
+int dev_start(struct dhcpcd_ctx *, int (*)(void *, int, const char *));
 void dev_stop(struct dhcpcd_ctx *);
 #else
 #define dev_initialized(a, b) (1)
--- a/src/dhcpcd.c	Sun May 24 05:54:40 2020 +0000
+++ b/src/dhcpcd.c	Sun May 24 10:30:23 2020 +0000
@@ -2258,9 +2258,10 @@
 
 	/* Start any dev listening plugin which may want to
 	 * change the interface name provided by the kernel */
-	if ((ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
+	if (!IN_PRIVSEP(&ctx) &&
+	    (ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
 	    (DHCPCD_MASTER | DHCPCD_DEV))
-		dev_start(&ctx);
+		dev_start(&ctx, dhcpcd_handleinterface);
 
 	setproctitle("%s%s%s",
 	    ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind],
--- a/src/privsep-root.c	Sun May 24 05:54:40 2020 +0000
+++ b/src/privsep-root.c	Sun May 24 10:30:23 2020 +0000
@@ -44,6 +44,7 @@
 #include <unistd.h>
 
 #include "common.h"
+#include "dev.h"
 #include "dhcpcd.h"
 #include "dhcp6.h"
 #include "eloop.h"
@@ -525,6 +526,14 @@
 		 err = ip6_forwarding(data);
 		 break;
 #endif
+#ifdef PLUGIN_DEV
+	case PS_DEV_INITTED:
+		err = dev_initialized(ctx, data);
+		break;
+	case PS_DEV_LISTENING:
+		err = dev_listening(ctx);
+		break;
+#endif
 	default:
 		err = ps_root_os(psm, msg);
 		break;
@@ -548,6 +557,27 @@
 }
 
 static int
+ps_root_handleinterface(void *arg, int action, const char *ifname)
+{
+	struct dhcpcd_ctx *ctx = arg;
+	unsigned long flag;
+
+	if (action == 1)
+		flag = PS_DEV_IFADDED;
+	else if (action == -1)
+		flag = PS_DEV_IFREMOVED;
+	else if (action == 0)
+		flag = PS_DEV_IFUPDATED;
+	else {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return (int)ps_sendcmd(ctx, ctx->ps_data_fd, PS_DEV_IFCMD, flag,
+	    ifname, strlen(ifname) + 1);
+}
+
+static int
 ps_root_startcb(void *arg)
 {
 	struct dhcpcd_ctx *ctx = arg;
@@ -582,6 +612,12 @@
 		return -1;
 #endif
 
+	/* Start any dev listening plugin which may want to
+	 * change the interface name provided by the kernel */
+	if ((ctx->options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
+	    (DHCPCD_MASTER | DHCPCD_DEV))
+		dev_start(ctx, ps_root_handleinterface);
+
 	return 0;
 }
 
@@ -603,17 +639,58 @@
 	eloop_exit(ctx->eloop, sig == SIGTERM ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
+int (*handle_interface)(void *, int, const char *);
+
+#ifdef PLUGIN_DEV
+static ssize_t
+ps_root_devcb(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg)
+{
+	int action;
+	struct iovec *iov = msg->msg_iov;
+
+	if (msg->msg_iovlen != 1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	switch(psm->ps_flags) {
+	case PS_DEV_IFADDED:
+		action = 1;
+		break;
+	case PS_DEV_IFREMOVED:
+		action = -1;
+		break;
+	case PS_DEV_IFUPDATED:
+		action = 0;
+		break;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	return dhcpcd_handleinterface(ctx, action, iov->iov_base);
+}
+#endif
+
 static ssize_t
 ps_root_dispatchcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
 {
 	struct dhcpcd_ctx *ctx = arg;
 	ssize_t err;
 
+	switch(psm->ps_cmd) {
+#ifdef PLUGIN_DEV
+	case PS_DEV_IFCMD:
+		err = ps_root_devcb(ctx, psm, msg);
+		break;
+#endif
+	default:
+		err = ps_bpf_dispatch(ctx, psm, msg);
 #ifdef INET
-	err = ps_bpf_dispatch(ctx, psm, msg);
-	if (err == -1 && errno == ENOTSUP)
+		if (err == -1 && errno == ENOTSUP)
 #endif
-		err = ps_inet_dispatch(ctx, psm, msg);
+			err = ps_inet_dispatch(ctx, psm, msg);
+	}
 	return err;
 }
 
@@ -826,3 +903,24 @@
 	return ps_root_readerror(ctx, NULL, 0);
 }
 #endif
+
+#ifdef PLUGIN_DEV
+int
+ps_root_dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_INITTED, 0,
+	    ifname, strlen(ifname) + 1)== -1)
+		return -1;
+	return (int)ps_root_readerror(ctx, NULL, 0);
+}
+
+int
+ps_root_dev_listening(struct dhcpcd_ctx * ctx)
+{
+
+	if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_DEV_LISTENING, 0, NULL, 0)== -1)
+		return -1;
+	return (int)ps_root_readerror(ctx, NULL, 0);
+}
+#endif
--- a/src/privsep-root.h	Sun May 24 05:54:40 2020 +0000
+++ b/src/privsep-root.h	Sun May 24 10:30:23 2020 +0000
@@ -59,4 +59,9 @@
 ssize_t ps_root_writepathuint(struct dhcpcd_ctx *, const char *, unsigned int);
 #endif
 
+#ifdef PLUGIN_DEV
+int ps_root_dev_initialized(struct dhcpcd_ctx *, const char *);
+int ps_root_dev_listening(struct dhcpcd_ctx *);
 #endif
+
+#endif
--- a/src/privsep.c	Sun May 24 05:54:40 2020 +0000
+++ b/src/privsep.c	Sun May 24 10:30:23 2020 +0000
@@ -63,6 +63,7 @@
 #include "arp.h"
 #include "common.h"
 #include "control.h"
+#include "dev.h"
 #include "dhcp.h"
 #include "dhcp6.h"
 #include "eloop.h"
@@ -696,6 +697,7 @@
 		logdebugx("process %d stopping", getpid());
 #endif
 		ps_free(ctx);
+		dev_stop(ctx);
 		eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
 		return len;
 	}
--- a/src/privsep.h	Sun May 24 05:54:40 2020 +0000
+++ b/src/privsep.h	Sun May 24 10:30:23 2020 +0000
@@ -57,6 +57,16 @@
 #define	PS_IP6FORWARDING	0x0104
 #define	PS_GETIFADDRS		0x0105
 
+/* Dev Commands */
+#define	PS_DEV_LISTENING	0x0201
+#define	PS_DEV_INITTED		0x0202
+#define	PS_DEV_IFCMD		0x0203
+
+/* Dev Interface Commands (via flags) */
+#define	PS_DEV_IFADDED		0x0001
+#define	PS_DEV_IFREMOVED	0x0002
+#define	PS_DEV_IFUPDATED	0x0003
+
 /* Process commands */
 #define	PS_START		0x4000
 #define	PS_STOP			0x8000