From b8b6954407734eddbe22cc1cf0031dbbe223f3ed Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sun, 6 Sep 2020 17:15:23 +0100 Subject: [PATCH] Update to dhcpcd-9.2.0 with the following changes: * route: ensure IPv4LL routes come last in priority * DHCP: fix many issues with extending the last lease * privsep: don't read control group from config in privsep * privsep: only the master process responds to signals * privsep: use a socketpair for stderr/stdin rather than dupping /dev/null * privsep: right limit stdin/stderr/stdout * privsep: dumping a lease is now run in a sandbox * options: check if kernel supports INET or INET6 before enabling default * options: let clientid override a prior duid * options: allow -1 to represent infinity for requested lease time * dhcpcd: fix a crash initing a new interface after route overflow --- contrib/dhcpcd/src/defs.h | 2 +- contrib/dhcpcd/src/dhcp.c | 82 +++++++++--------- contrib/dhcpcd/src/dhcpcd.8.in | 6 +- contrib/dhcpcd/src/dhcpcd.c | 159 +++++++++++++++++++++++------------ contrib/dhcpcd/src/dhcpcd.conf.5.in | 10 ++- contrib/dhcpcd/src/dhcpcd.h | 6 +- contrib/dhcpcd/src/eloop.c | 5 +- contrib/dhcpcd/src/if-options.c | 51 +++++++++-- contrib/dhcpcd/src/if.c | 47 +++++++++++ contrib/dhcpcd/src/if.h | 3 +- contrib/dhcpcd/src/ipv4.c | 9 +- contrib/dhcpcd/src/ipv4.h | 1 + contrib/dhcpcd/src/ipv4ll.c | 5 ++ contrib/dhcpcd/src/ipv6.c | 33 ++++---- contrib/dhcpcd/src/ipv6nd.c | 4 +- contrib/dhcpcd/src/logerr.c | 46 ++-------- contrib/dhcpcd/src/logerr.h | 2 - contrib/dhcpcd/src/privsep-bpf.c | 14 +-- contrib/dhcpcd/src/privsep-control.c | 25 ++---- contrib/dhcpcd/src/privsep-inet.c | 17 +--- contrib/dhcpcd/src/privsep-root.c | 31 ++++--- contrib/dhcpcd/src/privsep.c | 60 +++++++------ contrib/dhcpcd/src/privsep.h | 1 - contrib/dhcpcd/src/route.c | 8 ++ contrib/dhcpcd/src/route.h | 5 +- 25 files changed, 370 insertions(+), 262 deletions(-) diff --git a/contrib/dhcpcd/src/defs.h b/contrib/dhcpcd/src/defs.h index 4f90c7f2b9..bea6418cb6 100644 --- a/contrib/dhcpcd/src/defs.h +++ b/contrib/dhcpcd/src/defs.h @@ -29,7 +29,7 @@ #define CONFIG_H #define PACKAGE "dhcpcd" -#define VERSION "9.1.3" +#define VERSION "9.2.0" #ifndef PRIVSEP_USER # define PRIVSEP_USER "_" PACKAGE diff --git a/contrib/dhcpcd/src/dhcp.c b/contrib/dhcpcd/src/dhcp.c index b309b01c4c..61cc256a85 100644 --- a/contrib/dhcpcd/src/dhcp.c +++ b/contrib/dhcpcd/src/dhcp.c @@ -777,7 +777,7 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type) (type == DHCP_REQUEST && state->addr->mask.s_addr == lease->mask.s_addr && (state->new == NULL || IS_DHCP(state->new)) && - !(state->added & STATE_FAKE)))) + !(state->added & (STATE_FAKE | STATE_EXPIRED))))) bootp->ciaddr = state->addr->addr.s_addr; bootp->op = BOOTREQUEST; @@ -836,7 +836,7 @@ make_message(struct bootp **bootpm, const struct interface *ifp, uint8_t type) if (type == DHCP_DECLINE || (type == DHCP_REQUEST && (state->addr == NULL || - state->added & STATE_FAKE || + state->added & (STATE_FAKE | STATE_EXPIRED) || lease->addr.s_addr != state->addr->addr.s_addr))) { putip = true; @@ -1745,7 +1745,7 @@ send_message(struct interface *ifp, uint8_t type, goto fail; len = (size_t)r; - if (!(state->added & STATE_FAKE) && + if (!(state->added & (STATE_FAKE | STATE_EXPIRED)) && state->addr != NULL && ipv4_iffindaddr(ifp, &state->lease.addr, NULL) != NULL) from.s_addr = state->lease.addr.s_addr; @@ -1869,14 +1869,16 @@ dhcp_discover(void *arg) state->state = DHS_DISCOVER; dhcp_new_xid(ifp); eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); - if (ifo->fallback) - eloop_timeout_add_sec(ifp->ctx->eloop, - ifo->reboot, dhcp_fallback, ifp); + if (!(state->added & STATE_EXPIRED)) { + if (ifo->fallback) + eloop_timeout_add_sec(ifp->ctx->eloop, + ifo->reboot, dhcp_fallback, ifp); #ifdef IPV4LL - else if (ifo->options & DHCPCD_IPV4LL) - eloop_timeout_add_sec(ifp->ctx->eloop, - ifo->reboot, ipv4ll_start, ifp); + else if (ifo->options & DHCPCD_IPV4LL) + eloop_timeout_add_sec(ifp->ctx->eloop, + ifo->reboot, ipv4ll_start, ifp); #endif + } if (ifo->options & DHCPCD_REQUEST) loginfox("%s: soliciting a DHCP lease (requesting %s)", ifp->name, inet_ntoa(ifo->req_addr)); @@ -1897,30 +1899,21 @@ dhcp_request(void *arg) } static void -dhcp_expire1(struct interface *ifp) -{ - struct dhcp_state *state = D_STATE(ifp); - - eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); - dhcp_drop(ifp, "EXPIRE"); - dhcp_unlink(ifp->ctx, state->leasefile); - state->interval = 0; - if (!(ifp->options->options & DHCPCD_LINK) || ifp->carrier > LINK_DOWN) - dhcp_discover(ifp); -} - -static void dhcp_expire(void *arg) { struct interface *ifp = arg; + struct dhcp_state *state = D_STATE(ifp); if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { logwarnx("%s: DHCP lease expired, extending lease", ifp->name); - return; + state->added |= STATE_EXPIRED; + } else { + logerrx("%s: DHCP lease expired", ifp->name); + dhcp_drop(ifp, "EXPIRE"); + dhcp_unlink(ifp->ctx, state->leasefile); } - - logerrx("%s: DHCP lease expired", ifp->name); - dhcp_expire1(ifp); + state->interval = 0; + dhcp_discover(ifp); } #if defined(ARP) || defined(IN_IFF_DUPLICATED) @@ -2291,7 +2284,9 @@ dhcp_bind(struct interface *ifp) return; } if (state->reason == NULL) { - if (state->old && !(state->added & STATE_FAKE)) { + if (state->old && + !(state->added & (STATE_FAKE | STATE_EXPIRED))) + { if (state->old->yiaddr == state->new->yiaddr && lease->server.s_addr && state->state != DHS_REBIND) @@ -2364,19 +2359,6 @@ dhcp_bind(struct interface *ifp) eloop_event_add(ctx->eloop, state->udp_rfd, dhcp_handleifudp, ifp); } -static void -dhcp_lastlease(void *arg) -{ - struct interface *ifp = arg; - struct dhcp_state *state = D_STATE(ifp); - - loginfox("%s: timed out contacting a DHCP server, using last lease", - ifp->name); - dhcp_bind(ifp); - state->interval = 0; - dhcp_discover(ifp); -} - static size_t dhcp_message_new(struct bootp **bootp, const struct in_addr *addr, const struct in_addr *mask) @@ -2476,6 +2458,26 @@ dhcp_arp_bind(struct interface *ifp) #endif static void +dhcp_lastlease(void *arg) +{ + struct interface *ifp = arg; + struct dhcp_state *state = D_STATE(ifp); + + loginfox("%s: timed out contacting a DHCP server, using last lease", + ifp->name); +#if defined(ARP) || defined(KERNEL_RFC5227) + dhcp_arp_bind(ifp); +#else + dhcp_bind(ifp); +#endif + /* Set expired here because dhcp_bind() -> ipv4_addaddr() will reset + * state */ + state->added |= STATE_EXPIRED; + state->interval = 0; + dhcp_discover(ifp); +} + +static void dhcp_static(struct interface *ifp) { struct if_options *ifo; diff --git a/contrib/dhcpcd/src/dhcpcd.8.in b/contrib/dhcpcd/src/dhcpcd.8.in index 8704e24543..9309250aa4 100644 --- a/contrib/dhcpcd/src/dhcpcd.8.in +++ b/contrib/dhcpcd/src/dhcpcd.8.in @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 31, 2020 +.Dd September 2, 2020 .Dt DHCPCD 8 .Os .Sh NAME @@ -385,8 +385,10 @@ If no interfaces are left running, .Nm will exit. .It Fl l , Fl Fl leasetime Ar seconds -Request a specific lease time in +Request a lease time of .Ar seconds . +.Ar -1 +represents an infinite lease time. By default .Nm does not request any lease time and leaves it in the hands of the diff --git a/contrib/dhcpcd/src/dhcpcd.c b/contrib/dhcpcd/src/dhcpcd.c index 2bed8e0448..ba0c905a75 100644 --- a/contrib/dhcpcd/src/dhcpcd.c +++ b/contrib/dhcpcd/src/dhcpcd.c @@ -336,7 +336,7 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx) #ifdef THERE_IS_NO_FORK eloop_timeout_delete(ctx->eloop, handle_exit_timeout, ctx); errno = ENOSYS; - return 0; + return; #else int i; unsigned int logopts = loggetopts(); @@ -361,8 +361,8 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx) /* Don't use loginfo because this makes no sense in a log. */ if (!(logopts & LOGERR_QUIET)) - (void)fprintf(stderr, "forked to background, child pid %d\n", - getpid()); + (void)fprintf(stderr, + "forked to background, child pid %d\n", getpid()); i = EXIT_SUCCESS; if (write(ctx->fork_fd, &i, sizeof(i)) == -1) logerr("write"); @@ -371,11 +371,18 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx) close(ctx->fork_fd); ctx->fork_fd = -1; - if (isatty(loggeterrfd())) { - logopts &= ~LOGERR_ERR; - logsetopts(logopts); - logseterrfd(-1); - } + /* + * Stop writing to stderr. + * On the happy path, only the master process writes to stderr, + * so this just stops wasting fprintf calls to nowhere. + * All other calls - ie errors in privsep processes or script output, + * will error when printing. + * If we *really* want to fix that, then we need to suck + * stderr/stdout in the master process and either disacrd it or pass + * it to the launcher process and then to stderr. + */ + logopts &= ~LOGERR_ERR; + logsetopts(logopts); #endif } @@ -1153,6 +1160,15 @@ dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx) } #endif +static void +dhcpcd_runprestartinterface(void *arg) +{ + struct interface *ifp = arg; + + run_preinit(ifp); + dhcpcd_prestartinterface(ifp); +} + void dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) { @@ -1215,9 +1231,11 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) continue; } TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); - if (ifp->active) + if (ifp->active) { + dhcpcd_initstate(ifp, 0); eloop_timeout_add_sec(ctx->eloop, 0, - dhcpcd_prestartinterface, ifp); + dhcpcd_runprestartinterface, ifp); + } } free(ifaces); @@ -1765,6 +1783,24 @@ dhcpcd_fork_cb(void *arg) eloop_exit(ctx->eloop, exit_code); } +static void +dhcpcd_stderr_cb(void *arg) +{ + struct dhcpcd_ctx *ctx = arg; + char log[BUFSIZ]; + ssize_t len; + + len = read(ctx->stderr_fd, log, sizeof(log)); + if (len == -1) { + if (errno != ECONNRESET) + logerr(__func__); + return; + } + + log[len] = '\0'; + fprintf(stderr, "%s", log); +} + int main(int argc, char **argv) { @@ -1778,7 +1814,7 @@ main(int argc, char **argv) ssize_t len; #if defined(USE_SIGNALS) || !defined(THERE_IS_NO_FORK) pid_t pid; - int sigpipe[2]; + int fork_fd[2], stderr_fd[2]; #endif #ifdef USE_SIGNALS int sig = 0; @@ -2100,11 +2136,20 @@ printpidfile: } #endif +#ifdef PRIVSEP + ps_init(&ctx); +#endif + #ifndef SMALL if (ctx.options & DHCPCD_DUMPLEASE && ioctl(fileno(stdin), FIONREAD, &i, sizeof(i)) == 0 && i > 0) { + ctx.options |= DHCPCD_FORKED; /* pretend child process */ +#ifdef PRIVSEP + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) + goto exit_failure; +#endif ifp = calloc(1, sizeof(*ifp)); if (ifp == NULL) { logerr(__func__); @@ -2153,6 +2198,14 @@ printpidfile: ctx.control_fd = control_open(NULL, AF_UNSPEC, ctx.options & DHCPCD_DUMPLEASE); if (ctx.control_fd != -1) { +#ifdef PRIVSEP + ctx.options &= ~DHCPCD_FORKED; + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) { + ctx.options |= DHCPCD_FORKED; + goto exit_failure; + } + ctx.options |= DHCPCD_FORKED; +#endif if (!(ctx.options & DHCPCD_DUMPLEASE)) loginfox("sending commands to dhcpcd process"); len = control_send(&ctx, argc, argv); @@ -2186,6 +2239,8 @@ printpidfile: if (!(ctx.options & DHCPCD_TEST)) { /* Ensure we have the needed directories */ + if (mkdir(DBDIR, 0750) == -1 && errno != EEXIST) + logerr("%s: mkdir `%s'", __func__, DBDIR); if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST) logerr("%s: mkdir `%s'", __func__, RUNDIR); if ((pid = pidfile_lock(ctx.pidfile)) != 0) { @@ -2204,29 +2259,40 @@ printpidfile: if (freopen(_PATH_DEVNULL, "r", stdin) == NULL) logerr("%s: freopen stdin", __func__); - -#ifdef PRIVSEP - ps_init(&ctx); -#endif - -#ifdef USE_SIGNALS - if (pipe(sigpipe) == -1) { - logerr("pipe"); - goto exit_failure; - } -#ifdef HAVE_CAPSICUM - if (ps_rights_limit_fdpair(sigpipe) == -1) { - logerr("ps_rights_limit_fdpair"); +#if defined(USE_SIGNALS) && !defined(THERE_IS_NO_FORK) + if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fork_fd) == -1 || + xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1) + { + logerr("socketpair"); goto exit_failure; } -#endif switch (pid = fork()) { case -1: logerr("fork"); goto exit_failure; case 0: - ctx.fork_fd = sigpipe[1]; - close(sigpipe[0]); + ctx.fork_fd = fork_fd[1]; + close(fork_fd[0]); +#ifdef PRIVSEP_RIGHTS + if (ps_rights_limit_fd(fork_fd[1]) == -1) { + logerr("ps_rights_limit_fdpair"); + goto exit_failure; + } +#endif + /* + * Redirect stderr to the stderr socketpair. + * Redirect stdout as well. + * dhcpcd doesn't output via stdout, but something in + * a called script might. + * + * Do NOT rights limit this fd as it will affect scripts. + * For example, cmp reports insufficient caps on FreeBSD. + */ + if (dup2(stderr_fd[1], STDERR_FILENO) == -1 || + dup2(stderr_fd[1], STDOUT_FILENO) == -1) + logerr("dup2"); + close(stderr_fd[0]); + close(stderr_fd[1]); if (setsid() == -1) { logerr("%s: setsid", __func__); goto exit_failure; @@ -2246,10 +2312,22 @@ printpidfile: break; default: ctx.options |= DHCPCD_FORKED; /* A lie */ - ctx.fork_fd = sigpipe[0]; - close(sigpipe[1]); + ctx.fork_fd = fork_fd[0]; + close(fork_fd[1]); + ctx.stderr_fd = stderr_fd[0]; + close(stderr_fd[1]); +#ifdef PRIVSEP_RIGHTS + if (ps_rights_limit_fd(fork_fd[0]) == -1 || + ps_rights_limit_fd(stderr_fd[0]) == 1) + { + logerr("ps_rights_limit_fdpair"); + goto exit_failure; + } +#endif setproctitle("[launcher]"); eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + eloop_event_add(ctx.eloop, ctx.stderr_fd, dhcpcd_stderr_cb, + &ctx); goto run_loop; } @@ -2268,29 +2346,6 @@ printpidfile: if_disable_rtadv(); #endif - if (isatty(STDOUT_FILENO) && - freopen(_PATH_DEVNULL, "r", stdout) == NULL) - logerr("%s: freopen stdout", __func__); - if (isatty(STDERR_FILENO)) { - int fd = dup(STDERR_FILENO); - - if (fd == -1) - logerr("%s: dup", __func__); - else if (logseterrfd(fd) == -1) - logerr("%s: logseterrfd", __func__); - else if (freopen(_PATH_DEVNULL, "r", stderr) == NULL) { - logseterrfd(-1); - logerr("%s: freopen stderr", __func__); - } - } - - /* If we're not running in privsep, we need to create the DB - * directory here. */ - if (!(ctx.options & DHCPCD_PRIVSEP)) { - if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST) - logerr("%s: mkdir `%s'", __func__, DBDIR); - } - #ifdef PRIVSEP if (IN_PRIVSEP(&ctx) && ps_start(&ctx) == -1) { logerr("ps_start"); diff --git a/contrib/dhcpcd/src/dhcpcd.conf.5.in b/contrib/dhcpcd/src/dhcpcd.conf.5.in index 071bef49d1..998f99e92b 100644 --- a/contrib/dhcpcd/src/dhcpcd.conf.5.in +++ b/contrib/dhcpcd/src/dhcpcd.conf.5.in @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 18, 2020 +.Dd September 2, 2020 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -448,8 +448,14 @@ Enables IPv6 Router Advertisement solicitation. This is on by default, but is documented here in the case where it is disabled globally but needs to be enabled for one interface. .It Ic leasetime Ar seconds -Request a leasetime of +Request a lease time of .Ar seconds . +.Ar -1 +represents an infinite lease time. +By default +.Nm dhcpcd +does not request any lease time and leaves it in the hands of the +DHCP server. .It Ic link_rcvbuf Ar size Override the size of the link receive buffer from the kernel default. While diff --git a/contrib/dhcpcd/src/dhcpcd.h b/contrib/dhcpcd/src/dhcpcd.h index 61a6a08144..95b7e07370 100644 --- a/contrib/dhcpcd/src/dhcpcd.h +++ b/contrib/dhcpcd/src/dhcpcd.h @@ -96,7 +96,6 @@ TAILQ_HEAD(if_head, interface); #include "privsep.h" -#ifdef INET6 /* dhcpcd requires CMSG_SPACE to evaluate to a compile time constant. */ #if defined(__QNX) || \ (defined(__NetBSD_Version__) && __NetBSD_Version__ < 600000000) @@ -113,16 +112,13 @@ TAILQ_HEAD(if_head, interface); #define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len)) #endif -#define IP6BUFLEN (CMSG_SPACE(sizeof(struct in6_pktinfo)) + \ - CMSG_SPACE(sizeof(int))) -#endif - struct passwd; struct dhcpcd_ctx { char pidfile[sizeof(PIDFILE) + IF_NAMESIZE + 1]; char vendor[256]; int fork_fd; /* FD for the fork init signal pipe */ + int stderr_fd; /* FD for logging to stderr */ const char *cffile; unsigned long long options; char *logfile; diff --git a/contrib/dhcpcd/src/eloop.c b/contrib/dhcpcd/src/eloop.c index d43dbe8340..16bb9b2a9d 100644 --- a/contrib/dhcpcd/src/eloop.c +++ b/contrib/dhcpcd/src/eloop.c @@ -703,9 +703,10 @@ eloop_start(struct eloop *eloop, sigset_t *signals) if (eloop->exitnow) break; - if (_eloop_nsig != 0 && eloop->signal_cb != NULL) { + if (_eloop_nsig != 0) { n = _eloop_sig[--_eloop_nsig]; - eloop->signal_cb(n, eloop->signal_cb_ctx); + if (eloop->signal_cb != NULL) + eloop->signal_cb(n, eloop->signal_cb_ctx); continue; } diff --git a/contrib/dhcpcd/src/if-options.c b/contrib/dhcpcd/src/if-options.c index 62fe7ede5b..213d05cc18 100644 --- a/contrib/dhcpcd/src/if-options.c +++ b/contrib/dhcpcd/src/if-options.c @@ -59,6 +59,8 @@ #define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED) #define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED) +static unsigned long long default_options; + const struct option cf_options[] = { {"background", no_argument, NULL, 'b'}, {"script", required_argument, NULL, 'c'}, @@ -759,6 +761,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, break; case 'l': ARG_REQUIRED; + if (strcmp(arg, "-1") == 0) { + ifo->leasetime = DHCP_INFINITE_LIFETIME; + break; + } ifo->leasetime = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); if (e) { @@ -1021,6 +1027,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, } ifo->options |= DHCPCD_CLIENTID; ifo->clientid[0] = (uint8_t)s; + ifo->options &= ~DHCPCD_DUID; break; case 'J': ifo->options |= DHCPCD_BROADCAST; @@ -1204,13 +1211,23 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, ifo->options |= DHCPCD_ONESHOT; break; case '4': +#ifdef INET ifo->options &= ~DHCPCD_IPV6; ifo->options |= DHCPCD_IPV4; break; +#else + logerrx("INET has been compiled out"); + return -1; +#endif case '6': +#ifdef INET6 ifo->options &= ~DHCPCD_IPV4; ifo->options |= DHCPCD_IPV6; break; +#else + logerrx("INET6 has been compiled out"); + return -1; +#endif case O_IPV4: ifo->options |= DHCPCD_IPV4; break; @@ -2090,6 +2107,12 @@ invalid_token: break; case O_CONTROLGRP: ARG_REQUIRED; +#ifdef PRIVSEP + /* Control group is already set by this point. + * We don't need to pledge getpw either with this. */ + if (IN_PRIVSEP(ctx)) + break; +#endif #ifdef _REENTRANT l = sysconf(_SC_GETGR_R_SIZE_MAX); if (l == -1) @@ -2326,18 +2349,30 @@ read_config(struct dhcpcd_ctx *ctx, /* Seed our default options */ if ((ifo = default_config(ctx)) == NULL) return NULL; - ifo->options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY; -#ifdef PLUGIN_DEV - ifo->options |= DHCPCD_DEV; -#endif + if (default_options == 0) { + default_options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY; #ifdef INET - ifo->options |= DHCPCD_IPV4 | DHCPCD_ARP | DHCPCD_DHCP | DHCPCD_IPV4LL; + skip = socket(PF_INET, SOCK_DGRAM, 0); + if (skip != -1) { + close(skip); + default_options |= DHCPCD_IPV4 | DHCPCD_ARP | + DHCPCD_DHCP | DHCPCD_IPV4LL; + } #endif #ifdef INET6 - ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS; - ifo->options |= DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS; - ifo->options |= DHCPCD_DHCP6; + skip = socket(PF_INET6, SOCK_DGRAM, 0); + if (skip != -1) { + close(skip); + default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS | + DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS | + DHCPCD_DHCP6; + } #endif +#ifdef PLUGIN_DEV + default_options |= DHCPCD_DEV; +#endif + } + ifo->options |= default_options; CLEAR_CONFIG_BLOCK(ifo); diff --git a/contrib/dhcpcd/src/if.c b/contrib/dhcpcd/src/if.c index d711542ab2..40fdadcf0e 100644 --- a/contrib/dhcpcd/src/if.c +++ b/contrib/dhcpcd/src/if.c @@ -995,3 +995,50 @@ out: return -1; #endif } + +int +xsocketpair(int domain, int type, int protocol, int fd[2]) +{ + int s; +#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) + int xflags, xtype = type; +#endif + +#ifndef HAVE_SOCK_CLOEXEC + if (xtype & SOCK_CLOEXEC) + type &= ~SOCK_CLOEXEC; +#endif +#ifndef HAVE_SOCK_NONBLOCK + if (xtype & SOCK_NONBLOCK) + type &= ~SOCK_NONBLOCK; +#endif + + if ((s = socketpair(domain, type, protocol, fd)) == -1) + return -1; + +#ifndef HAVE_SOCK_CLOEXEC + if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 || + fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1)) + goto out; + if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[1], F_GETFD)) == -1 || + fcntl(fd[1], F_SETFD, xflags | FD_CLOEXEC) == -1)) + goto out; +#endif +#ifndef HAVE_SOCK_NONBLOCK + if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[0], F_GETFL)) == -1 || + fcntl(fd[0], F_SETFL, xflags | O_NONBLOCK) == -1)) + goto out; + if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[1], F_GETFL)) == -1 || + fcntl(fd[1], F_SETFL, xflags | O_NONBLOCK) == -1)) + goto out; +#endif + + return s; + +#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) +out: + close(fd[0]); + close(fd[1]); + return -1; +#endif +} diff --git a/contrib/dhcpcd/src/if.h b/contrib/dhcpcd/src/if.h index 2323501f3b..e053fe5b62 100644 --- a/contrib/dhcpcd/src/if.h +++ b/contrib/dhcpcd/src/if.h @@ -224,6 +224,8 @@ int if_setmac(struct interface *ifp, void *, uint8_t); #ifndef SOCK_CXNB #define SOCK_CXNB SOCK_CLOEXEC | SOCK_NONBLOCK #endif +int xsocket(int, int, int); +int xsocketpair(int, int, int, int[2]); int if_route(unsigned char, const struct rt *rt); int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int); @@ -259,7 +261,6 @@ int if_getlifetime6(struct ipv6_addr *); int if_machinearch(char *, size_t); struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *, struct msghdr *, int *); -int xsocket(int, int, int); #ifdef __linux__ int if_linksocket(struct sockaddr_nl *, int, int); diff --git a/contrib/dhcpcd/src/ipv4.c b/contrib/dhcpcd/src/ipv4.c index c6a76ea336..92ecdbd0f1 100644 --- a/contrib/dhcpcd/src/ipv4.c +++ b/contrib/dhcpcd/src/ipv4.c @@ -661,8 +661,13 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr, ia->mask = *mask; ia->brd = *bcast; #ifdef IP_LIFETIME - ia->vltime = vltime; - ia->pltime = pltime; + if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { + /* We don't want the kernel to expire the address. */ + ia->vltime = ia->pltime = DHCP_INFINITE_LIFETIME; + } else { + ia->vltime = vltime; + ia->pltime = pltime; + } #else UNUSED(vltime); UNUSED(pltime); diff --git a/contrib/dhcpcd/src/ipv4.h b/contrib/dhcpcd/src/ipv4.h index 3b933a7113..bb3d5b2c7a 100644 --- a/contrib/dhcpcd/src/ipv4.h +++ b/contrib/dhcpcd/src/ipv4.h @@ -129,6 +129,7 @@ bool inet_getroutes(struct dhcpcd_ctx *, rb_tree_t *); #define STATE_ADDED 0x01 #define STATE_FAKE 0x02 +#define STATE_EXPIRED 0x04 int ipv4_deladdr(struct ipv4_addr *, int); struct ipv4_addr *ipv4_addaddr(struct interface *, diff --git a/contrib/dhcpcd/src/ipv4ll.c b/contrib/dhcpcd/src/ipv4ll.c index 9d93ac11ca..fee115f250 100644 --- a/contrib/dhcpcd/src/ipv4ll.c +++ b/contrib/dhcpcd/src/ipv4ll.c @@ -111,6 +111,7 @@ ipv4ll_subnetroute(rb_tree_t *routes, struct interface *ifp) in.s_addr = INADDR_ANY; sa_in_init(&rt->rt_gateway, &in); sa_in_init(&rt->rt_ifa, &state->addr->addr); + rt->rt_dflags |= RTDF_IPV4LL; return rt_proto_add(routes, rt) ? 1 : 0; } @@ -134,6 +135,10 @@ ipv4ll_defaultroute(rb_tree_t *routes, struct interface *ifp) sa_in_init(&rt->rt_netmask, &in); sa_in_init(&rt->rt_gateway, &in); sa_in_init(&rt->rt_ifa, &state->addr->addr); + rt->rt_dflags |= RTDF_IPV4LL; +#ifdef HAVE_ROUTE_METRIC + rt->rt_metric += 10000; +#endif return rt_proto_add(routes, rt) ? 1 : 0; } diff --git a/contrib/dhcpcd/src/ipv6.c b/contrib/dhcpcd/src/ipv6.c index c42b3d6df8..5442ebdedc 100644 --- a/contrib/dhcpcd/src/ipv6.c +++ b/contrib/dhcpcd/src/ipv6.c @@ -679,6 +679,14 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now) /* Adjust plftime and vltime based on acquired time */ pltime = ia->prefix_pltime; vltime = ia->prefix_vltime; + + if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { + /* We don't want the kernel to expire the address. + * The saved times will be re-applied to the ia + * before exiting this function. */ + ia->prefix_vltime = ia->prefix_pltime = ND6_INFINITE_LIFETIME; + } + if (timespecisset(&ia->acquired) && (ia->prefix_pltime != ND6_INFINITE_LIFETIME || ia->prefix_vltime != ND6_INFINITE_LIFETIME)) @@ -1092,33 +1100,22 @@ ipv6_anyglobal(struct interface *sifp) struct interface *ifp; struct ipv6_state *state; struct ipv6_addr *ia; -#ifdef BSD bool forwarding; -#if defined(PRIVSEP) && defined(HAVE_PLEDGE) + /* BSD forwarding is either on or off. + * Linux forwarding is technically the same as it's + * configured by the "all" interface. + * Per interface only affects IsRouter of NA messages. */ +#if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__)) if (IN_PRIVSEP(sifp->ctx)) - forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) == 1; + forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0; else #endif - forwarding = ip6_forwarding(NULL) == 1; -#endif - + forwarding = ip6_forwarding(NULL) != 0; TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) { -#ifdef BSD if (ifp != sifp && !forwarding) continue; -#else -#if defined(PRIVSEP) && defined(__linux__) - if (IN_PRIVSEP(sifp->ctx)) { - if (ifp != sifp && - ps_root_ip6forwarding(sifp->ctx, ifp->name) != 1) - continue; - } else -#endif - if (ifp != sifp && ip6_forwarding(ifp->name) != 1) - continue; -#endif state = IPV6_STATE(ifp); if (state == NULL) diff --git a/contrib/dhcpcd/src/ipv6nd.c b/contrib/dhcpcd/src/ipv6nd.c index 009792dce3..d1cc4efab7 100644 --- a/contrib/dhcpcd/src/ipv6nd.c +++ b/contrib/dhcpcd/src/ipv6nd.c @@ -544,11 +544,11 @@ ipv6nd_advertise(struct ipv6_addr *ia) na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE; #if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE)) if (IN_PRIVSEP(ctx)) { - if (ps_root_ip6forwarding(ctx, ifp->name) == 1) + if (ps_root_ip6forwarding(ctx, ifp->name) != 0) na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; } else #endif - if (ip6_forwarding(ifp->name) == 1) + if (ip6_forwarding(ifp->name) != 0) na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; na->nd_na_target = ia->addr; diff --git a/contrib/dhcpcd/src/logerr.c b/contrib/dhcpcd/src/logerr.c index 8a219b0214..817c53ca4d 100644 --- a/contrib/dhcpcd/src/logerr.c +++ b/contrib/dhcpcd/src/logerr.c @@ -52,7 +52,6 @@ struct logctx { char log_buf[BUFSIZ]; unsigned int log_opts; - FILE *log_err; #ifndef SMALL FILE *log_file; #ifdef LOGERR_TAG @@ -117,7 +116,6 @@ logprintdate(FILE *stream) __printflike(3, 0) static int vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) { - FILE *err; int len = 0, e; va_list a; #ifndef SMALL @@ -126,9 +124,8 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) bool log_tag; #endif - err = ctx->log_err == NULL ? stderr : ctx->log_err; - if ((stream == err && ctx->log_opts & LOGERR_ERR_DATE) || - (stream != err && ctx->log_opts & LOGERR_LOG_DATE)) + if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) || + (stream != stderr && ctx->log_opts & LOGERR_LOG_DATE)) { if ((e = logprintdate(stream)) == -1) return -1; @@ -136,8 +133,8 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) } #ifdef LOGERR_TAG - log_tag = ((stream == err && ctx->log_opts & LOGERR_ERR_TAG) || - (stream != err && ctx->log_opts & LOGERR_LOG_TAG)); + log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) || + (stream != stderr && ctx->log_opts & LOGERR_LOG_TAG)); if (log_tag) { if (ctx->log_tag == NULL) ctx->log_tag = getprogname(); @@ -147,8 +144,8 @@ vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args) } #endif - log_pid = ((stream == err && ctx->log_opts & LOGERR_ERR_PID) || - (stream != err && ctx->log_opts & LOGERR_LOG_PID)); + log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) || + (stream != stderr && ctx->log_opts & LOGERR_LOG_PID)); if (log_pid) { if ((e = fprintf(stream, "[%d]", getpid())) == -1) return -1; @@ -205,12 +202,7 @@ vlogmessage(int pri, const char *fmt, va_list args) (pri <= LOG_ERR || (!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) || (ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG))) - { - FILE *err; - - err = ctx->log_err == NULL ? stderr : ctx->log_err; - len = vlogprintf_r(ctx, err, fmt, args); - } + len = vlogprintf_r(ctx, stderr, fmt, args); if (!(ctx->log_opts & LOGERR_LOG)) return len; @@ -371,30 +363,6 @@ logsettag(const char *tag) #endif int -loggeterrfd(void) -{ - struct logctx *ctx = &_logctx; - FILE *err = ctx->log_err == NULL ? stderr : ctx->log_err; - - return fileno(err); -} - -int -logseterrfd(int fd) -{ - struct logctx *ctx = &_logctx; - - if (ctx->log_err != NULL) - fclose(ctx->log_err); - if (fd == -1) { - ctx->log_err = NULL; - return 0; - } - ctx->log_err = fdopen(fd, "a"); - return ctx->log_err == NULL ? -1 : 0; -} - -int logopen(const char *path) { struct logctx *ctx = &_logctx; diff --git a/contrib/dhcpcd/src/logerr.h b/contrib/dhcpcd/src/logerr.h index 82368d1f5b..4b4d6dc425 100644 --- a/contrib/dhcpcd/src/logerr.h +++ b/contrib/dhcpcd/src/logerr.h @@ -97,8 +97,6 @@ void logsetopts(unsigned int); void logsettag(const char *); #endif -int loggeterrfd(void); -int logseterrfd(int); int logopen(const char *); void logclose(void); int logreopen(void); diff --git a/contrib/dhcpcd/src/privsep-bpf.c b/contrib/dhcpcd/src/privsep-bpf.c index 6892bf2a6a..3025fda891 100644 --- a/contrib/dhcpcd/src/privsep-bpf.c +++ b/contrib/dhcpcd/src/privsep-bpf.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -170,17 +169,6 @@ ps_bpf_start_bpf(void *arg) return -1; } -static void -ps_bpf_signal_bpfcb(int sig, void *arg) -{ - struct dhcpcd_ctx *ctx = arg; - - if (sig != SIGTERM) - return; - - eloop_exit(ctx->eloop, EXIT_SUCCESS); -} - ssize_t ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) { @@ -249,7 +237,7 @@ ps_bpf_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) start = ps_dostart(ctx, &psp->psp_pid, &psp->psp_fd, ps_bpf_recvmsg, NULL, psp, - ps_bpf_start_bpf, ps_bpf_signal_bpfcb, + ps_bpf_start_bpf, NULL, PSF_DROPPRIVS); switch (start) { case -1: diff --git a/contrib/dhcpcd/src/privsep-control.c b/contrib/dhcpcd/src/privsep-control.c index 306ab58fa1..01a8acd744 100644 --- a/contrib/dhcpcd/src/privsep-control.c +++ b/contrib/dhcpcd/src/privsep-control.c @@ -27,7 +27,6 @@ */ #include -#include #include #include @@ -95,18 +94,6 @@ ps_ctl_recvmsg(void *arg) logerr(__func__); } -static void -ps_ctl_signalcb(int sig, void *arg) -{ - struct dhcpcd_ctx *ctx = arg; - - if (sig != SIGTERM) - return; - - shutdown(ctx->ps_control_fd, SHUT_RDWR); - eloop_exit(ctx->eloop, EXIT_SUCCESS); -} - ssize_t ps_ctl_handleargs(struct fd_list *fd, char *data, size_t len) { @@ -238,20 +225,18 @@ ps_ctl_start(struct dhcpcd_ctx *ctx) int data_fd[2], listen_fd[2]; pid_t pid; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_fd) == -1) - return -1; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1) + if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_fd) == -1 || + xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1) return -1; #ifdef PRIVSEP_RIGHTS - if (ps_rights_limit_fdpair(data_fd) == -1) - return -1; - if (ps_rights_limit_fdpair(listen_fd) == -1) + if (ps_rights_limit_fdpair(data_fd) == -1 || + ps_rights_limit_fdpair(listen_fd) == -1) return -1; #endif pid = ps_dostart(ctx, &ctx->ps_control_pid, &ctx->ps_control_fd, ps_ctl_recvmsg, ps_ctl_dodispatch, ctx, - ps_ctl_startcb, ps_ctl_signalcb, + ps_ctl_startcb, NULL, PSF_DROPPRIVS); if (pid == -1) diff --git a/contrib/dhcpcd/src/privsep-inet.c b/contrib/dhcpcd/src/privsep-inet.c index 8bc0c2eaf0..89ba79e039 100644 --- a/contrib/dhcpcd/src/privsep-inet.c +++ b/contrib/dhcpcd/src/privsep-inet.c @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -291,18 +290,6 @@ ps_inet_recvmsg(void *arg) logerr(__func__); } -static void -ps_inet_signalcb(int sig, void *arg) -{ - struct dhcpcd_ctx *ctx = arg; - - if (sig != SIGTERM) - return; - - shutdown(ctx->ps_inet_fd, SHUT_RDWR); - eloop_exit(ctx->eloop, EXIT_SUCCESS); -} - ssize_t ps_inet_dispatch(void *arg, struct ps_msghdr *psm, struct msghdr *msg) { @@ -347,7 +334,7 @@ ps_inet_start(struct dhcpcd_ctx *ctx) pid = ps_dostart(ctx, &ctx->ps_inet_pid, &ctx->ps_inet_fd, ps_inet_recvmsg, ps_inet_dodispatch, ctx, - ps_inet_startcb, ps_inet_signalcb, + ps_inet_startcb, NULL, PSF_DROPPRIVS); #ifdef HAVE_CAPSICUM @@ -576,7 +563,7 @@ ps_inet_cmd(struct dhcpcd_ctx *ctx, struct ps_msghdr *psm, struct msghdr *msg) start = ps_dostart(ctx, &psp->psp_pid, &psp->psp_fd, ps_inet_recvmsgpsp, NULL, psp, - start_func, ps_inet_signalcb, + start_func, NULL, PSF_DROPPRIVS); switch (start) { case -1: diff --git a/contrib/dhcpcd/src/privsep-root.c b/contrib/dhcpcd/src/privsep-root.c index f1b4074531..1a438b67d3 100644 --- a/contrib/dhcpcd/src/privsep-root.c +++ b/contrib/dhcpcd/src/privsep-root.c @@ -638,27 +638,46 @@ ps_root_startcb(void *arg) /* Open network sockets for sending. * This is a small bit wasteful for non sandboxed OS's * but makes life very easy for unicasting DHCPv6 in non master - * mode as we no longer care about address selection. */ + * mode as we no longer care about address selection. + * We can't call shutdown SHUT_RD on the socket because it's + * not connectd. All we can do is try and set a zero sized + * receive buffer and just let it overflow. + * Reading from it just to drain it is a waste of CPU time. */ #ifdef INET if (ctx->options & DHCPCD_IPV4) { + int buflen = 1; + ctx->udp_wfd = xsocket(PF_INET, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP); if (ctx->udp_wfd == -1) logerr("%s: dhcp_openraw", __func__); + else if (setsockopt(ctx->udp_wfd, SOL_SOCKET, SO_RCVBUF, + &buflen, sizeof(buflen)) == -1) + logerr("%s: setsockopt SO_RCVBUF DHCP", __func__); } #endif #ifdef INET6 if (ctx->options & DHCPCD_IPV6) { + int buflen = 1; + ctx->nd_fd = ipv6nd_open(false); if (ctx->nd_fd == -1) logerr("%s: ipv6nd_open", __func__); + else if (setsockopt(ctx->nd_fd, SOL_SOCKET, SO_RCVBUF, + &buflen, sizeof(buflen)) == -1) + logerr("%s: setsockopt SO_RCVBUF ND", __func__); } #endif #ifdef DHCP6 if (ctx->options & DHCPCD_IPV6) { + int buflen = 1; + ctx->dhcp6_wfd = dhcp6_openraw(); if (ctx->dhcp6_wfd == -1) logerr("%s: dhcp6_openraw", __func__); + else if (setsockopt(ctx->dhcp6_wfd, SOL_SOCKET, SO_RCVBUF, + &buflen, sizeof(buflen)) == -1) + logerr("%s: setsockopt SO_RCVBUF DHCP6", __func__); } #endif @@ -674,22 +693,14 @@ ps_root_startcb(void *arg) } static void -ps_root_signalcb(int sig, void *arg) +ps_root_signalcb(int sig, __unused void *arg) { - struct dhcpcd_ctx *ctx = arg; if (sig == SIGCHLD) { while (waitpid(-1, NULL, WNOHANG) > 0) ; return; } - - if (sig != SIGTERM) - return; - - shutdown(ctx->ps_root_fd, SHUT_RDWR); - shutdown(ctx->ps_data_fd, SHUT_RDWR); - eloop_exit(ctx->eloop, EXIT_SUCCESS); } int (*handle_interface)(void *, int, const char *); diff --git a/contrib/dhcpcd/src/privsep.c b/contrib/dhcpcd/src/privsep.c index 65260f2c46..3f1dc2d6e0 100644 --- a/contrib/dhcpcd/src/privsep.c +++ b/contrib/dhcpcd/src/privsep.c @@ -34,6 +34,7 @@ * Spawn an unpriv process to send/receive common network data. * Then drop all privs and start running. * Every process aside from the privileged actioneer is chrooted. + * All privsep processes ignore signals - only the master process accepts them. * * dhcpcd will maintain the config file in the chroot, no need to handle * this in a script or something. @@ -74,6 +75,8 @@ #ifdef HAVE_CAPSICUM #include +#include +#define ps_rights_limit_stdio caph_limit_stdio #endif #ifdef HAVE_UTIL_H #include @@ -109,7 +112,7 @@ ps_init(struct dhcpcd_ctx *ctx) return 0; } -int +static int ps_dropprivs(struct dhcpcd_ctx *ctx) { struct passwd *pw = ctx->ps_user; @@ -121,9 +124,10 @@ ps_dropprivs(struct dhcpcd_ctx *ctx) if (chdir("/") == -1) logerr("%s: chdir `/'", __func__); - if (setgroups(1, &pw->pw_gid) == -1 || + if ((setgroups(1, &pw->pw_gid) == -1 || setgid(pw->pw_gid) == -1 || - setuid(pw->pw_uid) == -1) + setuid(pw->pw_uid) == -1) && + (errno != EPERM || ctx->options & DHCPCD_FORKED)) { logerr("failed to drop privileges"); return -1; @@ -162,7 +166,7 @@ ps_dropprivs(struct dhcpcd_ctx *ctx) /* Prohibit writing to files. * Obviously this won't work if we are using a logfile * or redirecting stderr to a file. */ - if (ctx->logfile == NULL && isatty(loggeterrfd())) { + if (ctx->logfile == NULL) { if (setrlimit(RLIMIT_FSIZE, &rzero) == -1) logerr("setrlimit RLIMIT_FSIZE"); } @@ -283,12 +287,10 @@ ps_dostart(struct dhcpcd_ctx *ctx, void *recv_ctx, int (*callback)(void *), void (*signal_cb)(int, void *), unsigned int flags) { - int stype; int fd[2]; pid_t pid; - stype = SOCK_CLOEXEC | SOCK_NONBLOCK; - if (socketpair(AF_UNIX, SOCK_DGRAM | stype, 0, fd) == -1) { + if (xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, fd) == -1) { logerr("%s: socketpair", __func__); return -1; } @@ -341,6 +343,14 @@ ps_dostart(struct dhcpcd_ctx *ctx, close(ctx->ps_root_fd); ctx->ps_root_fd = -1; } + +#ifdef PRIVSEP_RIGHTS + /* We cannot limit the root process in any way. */ + if (ps_rights_limit_stdio() == -1) { + logerr("ps_rights_limit_stdio"); + goto errexit; + } +#endif } if (priv_fd != &ctx->ps_inet_fd && ctx->ps_inet_fd != -1) { @@ -471,9 +481,10 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx) } #ifdef PRIVSEP_RIGHTS - if ((ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1 || - ps_rights_limit_fd(ctx->link_fd) == -1) && - errno != ENOSYS) + if ((ctx->pf_inet_fd != -1 && + ps_rights_limit_ioctl(ctx->pf_inet_fd) == -1) || + (ctx->link_fd != -1 && ps_rights_limit_fd(ctx->link_fd) == -1) || + ps_rights_limit_stdio() == -1) { logerr("%s: cap_rights_limit", __func__); return -1; @@ -645,12 +656,12 @@ ps_sendpsmmsg(struct dhcpcd_ctx *ctx, int fd, iovlen = 1; len = writev(fd, iov, iovlen); -#ifdef PRIVSEP_DEBUG - logdebugx("%s: %zd", __func__, len); -#endif - if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED && - !(ctx->options & DHCPCD_PRIVSEPROOT)) - eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + if (len == -1) { + logerr(__func__); + if (ctx->options & DHCPCD_FORKED && + !(ctx->options & DHCPCD_PRIVSEPROOT)) + eloop_exit(ctx->eloop, EXIT_FAILURE); + } return len; } @@ -789,10 +800,9 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) }; ssize_t len = recvmsg(rfd, &msg, 0); -#ifdef PRIVSEP_DEBUG - logdebugx("%s: recv fd %d, %zd bytes", __func__, rfd, len); -#endif + if (len == -1) + logerr("%s: recvmsg", __func__); if (len == -1 || len == 0) { if (ctx->options & DHCPCD_FORKED && !(ctx->options & DHCPCD_PRIVSEPROOT)) @@ -803,12 +813,12 @@ ps_recvmsg(struct dhcpcd_ctx *ctx, int rfd, uint16_t cmd, int wfd) iov[0].iov_len = (size_t)len; len = ps_sendcmdmsg(wfd, cmd, &msg); -#ifdef PRIVSEP_DEBUG - logdebugx("%s: send fd %d, %zu bytes", __func__, wfd, len); -#endif - if ((len == -1 || len == 0) && ctx->options & DHCPCD_FORKED && - !(ctx->options & DHCPCD_PRIVSEPROOT)) - eloop_exit(ctx->eloop, len == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + if (len == -1) { + logerr("ps_sendcmdmsg"); + if (ctx->options & DHCPCD_FORKED && + !(ctx->options & DHCPCD_PRIVSEPROOT)) + eloop_exit(ctx->eloop, EXIT_FAILURE); + } return len; } diff --git a/contrib/dhcpcd/src/privsep.h b/contrib/dhcpcd/src/privsep.h index 877f1527e6..c789543282 100644 --- a/contrib/dhcpcd/src/privsep.h +++ b/contrib/dhcpcd/src/privsep.h @@ -166,7 +166,6 @@ TAILQ_HEAD(ps_process_head, ps_process); #endif int ps_init(struct dhcpcd_ctx *); -int ps_dropprivs(struct dhcpcd_ctx *); int ps_start(struct dhcpcd_ctx *); int ps_stop(struct dhcpcd_ctx *); int ps_mastersandbox(struct dhcpcd_ctx *); diff --git a/contrib/dhcpcd/src/route.c b/contrib/dhcpcd/src/route.c index 401ce07c6f..83bc37c777 100644 --- a/contrib/dhcpcd/src/route.c +++ b/contrib/dhcpcd/src/route.c @@ -168,6 +168,14 @@ rt_compare_proto(void *context, const void *node1, const void *node2) if (c != 0) return -c; +#ifdef INET + /* IPv4LL routes always come last */ + if (rt1->rt_dflags & RTDF_IPV4LL && !(rt2->rt_dflags & RTDF_IPV4LL)) + return -1; + else if (!(rt1->rt_dflags & RTDF_IPV4LL) && rt2->rt_dflags & RTDF_IPV4LL) + return 1; +#endif + /* Lower metric interfaces come first. */ c = (int)(ifp1->metric - ifp2->metric); if (c != 0) diff --git a/contrib/dhcpcd/src/route.h b/contrib/dhcpcd/src/route.h index d94fc25d5a..e9ac121af3 100644 --- a/contrib/dhcpcd/src/route.h +++ b/contrib/dhcpcd/src/route.h @@ -102,8 +102,9 @@ struct rt { #define RTPREF_RESERVED (-2) #define RTPREF_INVALID (-3) /* internal */ unsigned int rt_dflags; -#define RTDF_IFA_ROUTE 0x02 /* Address generated route */ -#define RTDF_FAKE 0x04 /* Maybe us on lease reboot */ +#define RTDF_IFA_ROUTE 0x01 /* Address generated route */ +#define RTDF_FAKE 0x02 /* Maybe us on lease reboot */ +#define RTDF_IPV4LL 0x04 /* IPv4LL route */ #define RTDF_RA 0x08 /* Router Advertisement */ #define RTDF_DHCP 0x10 /* DHCP route */ #define RTDF_STATIC 0x20 /* Configured in dhcpcd */ -- 2.11.4.GIT