summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-05-24 10:30:23 +0000
committerRoy Marples <roy@marples.name>2020-05-24 10:30:23 +0000
commitf643f08e35fad9e54777b0e327c8cf768f2d82b3 (patch)
treee7847afc494da9d0ed00c6fbce96bedeb40e8e50
parenta4951704171655b11c683bacff6df58da5287aa2 (diff)
downloaddhcpcd-f643f08e35fad9e54777b0e327c8cf768f2d82b3.tar.xz
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.
-rw-r--r--src/dev.c34
-rw-r--r--src/dev.h2
-rw-r--r--src/dhcpcd.c5
-rw-r--r--src/privsep-root.c104
-rw-r--r--src/privsep-root.h5
-rw-r--r--src/privsep.c2
-rw-r--r--src/privsep.h10
7 files changed, 146 insertions, 16 deletions
diff --git a/src/dev.c b/src/dev.c
index 7e49d5ac..f7da67e4 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -42,6 +42,12 @@ int
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 @@ int
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 @@ void
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 @@ dev_start2(struct dhcpcd_ctx *ctx, const char *name)
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 @@ dev_start2(struct dhcpcd_ctx *ctx, const char *name)
}
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 @@ dev_start1(struct dhcpcd_ctx *ctx)
}
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 @@ dev_start1(struct dhcpcd_ctx *ctx)
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 @@ dev_handle_data(void *arg)
}
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)
diff --git a/src/dev.h b/src/dev.h
index 74a693e6..8ce4eb71 100644
--- a/src/dev.h
+++ b/src/dev.h
@@ -49,7 +49,7 @@ int dev_init(struct dev *, const struct dev_dhcpcd *);
#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)
diff --git a/src/dhcpcd.c b/src/dhcpcd.c
index e2501d6f..0c32098c 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -2258,9 +2258,10 @@ printpidfile:
/* 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],
diff --git a/src/privsep-root.c b/src/privsep-root.c
index b4216760..6a82fb6b 100644
--- a/src/privsep-root.c
+++ b/src/privsep-root.c
@@ -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 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
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 @@ ps_root_recvmsg(void *arg)
}
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 @@ ps_root_startcb(void *arg)
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 @@ ps_root_signalcb(int sig, void *arg)
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 @@ ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
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
diff --git a/src/privsep-root.h b/src/privsep-root.h
index 998c7830..a56e30af 100644
--- a/src/privsep-root.h
+++ b/src/privsep-root.h
@@ -59,4 +59,9 @@ ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *);
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
diff --git a/src/privsep.c b/src/privsep.c
index 92804a99..3ee508be 100644
--- a/src/privsep.c
+++ b/src/privsep.c
@@ -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 @@ ps_recvpsmsg(struct dhcpcd_ctx *ctx, int fd,
logdebugx("process %d stopping", getpid());
#endif
ps_free(ctx);
+ dev_stop(ctx);
eloop_exit(ctx->eloop, len != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
return len;
}
diff --git a/src/privsep.h b/src/privsep.h
index 09bfa897..93058225 100644
--- a/src/privsep.h
+++ b/src/privsep.h
@@ -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