From: Roy Marples Date: Sun, 24 May 2020 10:30:23 +0000 (+0000) Subject: privsep: Allow dev plugins to work X-Git-Tag: v9.1.0~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f643f08e35fad9e54777b0e327c8cf768f2d82b3;p=thirdparty%2Fdhcpcd.git 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. --- 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 #include "common.h" +#include "dev.h" #include "dhcpcd.h" #include "dhcp6.h" #include "eloop.h" @@ -524,6 +525,14 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) case PS_IP6FORWARDING: 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); @@ -547,6 +556,27 @@ ps_root_recvmsg(void *arg) logerr(__func__); } +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) { @@ -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