From be38669a3c0270d63b1dcbe546750d11c3a85cb9 Mon Sep 17 00:00:00 2001 From: roy Date: Mon, 5 Oct 2020 16:02:15 +0000 Subject: [PATCH] Sync with dhcpcd-9.3.0 --- external/bsd/dhcpcd/dist/src/bpf.c | 7 +- external/bsd/dhcpcd/dist/src/dhcp.c | 18 +- external/bsd/dhcpcd/dist/src/dhcp6.c | 10 +- external/bsd/dhcpcd/dist/src/dhcpcd.c | 216 ++++++++++++---------- external/bsd/dhcpcd/dist/src/if-bsd.c | 96 +++++----- external/bsd/dhcpcd/dist/src/if-options.c | 52 +++--- external/bsd/dhcpcd/dist/src/ipv6nd.c | 2 +- external/bsd/dhcpcd/dist/src/logerr.c | 2 +- external/bsd/dhcpcd/dist/src/privsep.c | 109 ++++++++--- external/bsd/dhcpcd/dist/src/script.c | 2 +- 10 files changed, 299 insertions(+), 215 deletions(-) diff --git a/external/bsd/dhcpcd/dist/src/bpf.c b/external/bsd/dhcpcd/dist/src/bpf.c index d3736a1b8ae6..9e85dbe24ecb 100644 --- a/external/bsd/dhcpcd/dist/src/bpf.c +++ b/external/bsd/dhcpcd/dist/src/bpf.c @@ -70,14 +70,14 @@ (insn)->jt = 0; \ (insn)->jf = 0; \ (insn)->k = (uint32_t)(v); \ -}; +} #define BPF_SET_JUMP(insn, c, v, t, f) { \ (insn)->code = (c); \ (insn)->jt = (t); \ (insn)->jf = (f); \ (insn)->k = (uint32_t)(v); \ -}; +} size_t bpf_frame_header_len(const struct interface *ifp) @@ -585,9 +585,6 @@ static const struct bpf_insn bpf_bootp_ether[] = { }; #define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether) -#define BOOTP_MIN_SIZE sizeof(struct ip) + sizeof(struct udphdr) + \ - sizeof(struct bootp) - static const struct bpf_insn bpf_bootp_base[] = { /* Make sure it's an IPv4 packet. */ BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), diff --git a/external/bsd/dhcpcd/dist/src/dhcp.c b/external/bsd/dhcpcd/dist/src/dhcp.c index 61cc256a8596..10671c6c6a39 100644 --- a/external/bsd/dhcpcd/dist/src/dhcp.c +++ b/external/bsd/dhcpcd/dist/src/dhcp.c @@ -1164,7 +1164,7 @@ read_lease(struct interface *ifp, struct bootp **bootp) logdebugx("reading standard input"); sbytes = read(fileno(stdin), buf.buf, sizeof(buf.buf)); } else { - logdebugx("%s: reading lease `%s'", + logdebugx("%s: reading lease: %s", ifp->name, state->leasefile); sbytes = dhcp_readfile(ifp->ctx, state->leasefile, buf.buf, sizeof(buf.buf)); @@ -2314,7 +2314,7 @@ dhcp_bind(struct interface *ifp) state->state = DHS_BOUND; if (!state->lease.frominfo && !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) { - logdebugx("%s: writing lease `%s'", + logdebugx("%s: writing lease: %s", ifp->name, state->leasefile); if (dhcp_writefile(ifp->ctx, state->leasefile, 0640, state->new, state->new_len) == -1) @@ -2865,10 +2865,10 @@ log_dhcp(int loglevel, const char *msg, print_string(sname, sizeof(sname), OT_STRING | OT_DOMAIN, bootp->sname, sizeof(bootp->sname)); if (a == NULL) - logmessage(loglevel, "%s: %s %s %s `%s'", + logmessage(loglevel, "%s: %s %s %s %s", ifp->name, msg, tfrom, inet_ntoa(addr), sname); else - logmessage(loglevel, "%s: %s %s %s %s `%s'", + logmessage(loglevel, "%s: %s %s %s %s %s", ifp->name, msg, a, tfrom, inet_ntoa(addr), sname); } else { if (r != 0) { @@ -3477,6 +3477,16 @@ dhcp_packet(struct interface *ifp, uint8_t *data, size_t len, #ifdef PRIVSEP const struct dhcp_state *state = D_CSTATE(ifp); + /* It's possible that an interface departs and arrives in short + * order to receive a BPF frame out of order. + * There is a similar check in ARP, but much lower down the stack. + * It's not needed for other inet protocols because we send the + * message as a whole and select the interface off that and then + * check state. BPF on the other hand is very interface + * specific and we do need this check. */ + if (state == NULL) + return; + /* Ignore double reads */ if (IN_PRIVSEP(ifp->ctx)) { switch (state->state) { diff --git a/external/bsd/dhcpcd/dist/src/dhcp6.c b/external/bsd/dhcpcd/dist/src/dhcp6.c index 2cf40793fc23..0dbf83332a42 100644 --- a/external/bsd/dhcpcd/dist/src/dhcp6.c +++ b/external/bsd/dhcpcd/dist/src/dhcp6.c @@ -147,7 +147,7 @@ struct dhcp_compat { uint16_t dhcp6_opt; }; -const struct dhcp_compat dhcp_compats[] = { +static const struct dhcp_compat dhcp_compats[] = { { DHO_DNSSERVER, D6_OPTION_DNS_SERVERS }, { DHO_HOSTNAME, D6_OPTION_FQDN }, { DHO_DNSDOMAIN, D6_OPTION_FQDN }, @@ -2588,7 +2588,7 @@ dhcp6_readlease(struct interface *ifp, int validate) logdebugx("reading standard input"); bytes = read(fileno(stdin), buf.buf, sizeof(buf.buf)); } else { - logdebugx("%s: reading lease `%s'", + logdebugx("%s: reading lease: %s", ifp->name, state->leasefile); bytes = dhcp_readfile(ifp->ctx, state->leasefile, buf.buf, sizeof(buf.buf)); @@ -3218,7 +3218,7 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) ifp->name, state->expire); rt_build(ifp->ctx, AF_INET6); if (!confirmed && !timedout) { - logdebugx("%s: writing lease `%s'", + logdebugx("%s: writing lease: %s", ifp->name, state->leasefile); if (dhcp_writefile(ifp->ctx, state->leasefile, 0640, state->new, state->new_len) == -1) @@ -3657,12 +3657,12 @@ dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, struct ipv6_addr *ia) "/tmp/dhcp6.reply%d.raw", replyn++); fd = open(fname, O_RDONLY, 0); if (fd == -1) { - logerr("%s: open `%s'", __func__, fname); + logerr("%s: open: %s", __func__, fname); return; } tlen = read(fd, tbuf, sizeof(tbuf)); if (tlen == -1) - logerr("%s: read `%s'", __func__, fname); + logerr("%s: read: %s", __func__, fname); close(fd); /* Copy across ServerID so we can work with our own server. */ diff --git a/external/bsd/dhcpcd/dist/src/dhcpcd.c b/external/bsd/dhcpcd/dist/src/dhcpcd.c index ba0c905a7583..604a08ca7f18 100644 --- a/external/bsd/dhcpcd/dist/src/dhcpcd.c +++ b/external/bsd/dhcpcd/dist/src/dhcpcd.c @@ -26,7 +26,7 @@ * SUCH DAMAGE. */ -const char dhcpcd_copyright[] = "Copyright (c) 2006-2020 Roy Marples"; +static const char dhcpcd_copyright[] = "Copyright (c) 2006-2020 Roy Marples"; #include #include @@ -360,7 +360,7 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx) return; /* Don't use loginfo because this makes no sense in a log. */ - if (!(logopts & LOGERR_QUIET)) + if (!(logopts & LOGERR_QUIET) && ctx->stderr_valid) (void)fprintf(stderr, "forked to background, child pid %d\n", getpid()); i = EXIT_SUCCESS; @@ -432,8 +432,6 @@ stop_interface(struct interface *ifp) /* De-activate the interface */ ifp->active = IF_INACTIVE; ifp->options->options &= ~DHCPCD_STOPPING; - /* Set the link state to unknown as we're no longer tracking it. */ - ifp->carrier = LINK_UNKNOWN; if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_TEST))) eloop_exit(ctx->eloop, EXIT_FAILURE); @@ -700,43 +698,36 @@ dhcpcd_reportssid(struct interface *ifp) return; } - loginfox("%s: connected to Access Point `%s'", ifp->name, pssid); + loginfox("%s: connected to Access Point: %s", ifp->name, pssid); } void -dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, - const char *ifname) +dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags) { - struct interface *ifp; - - ifp = if_find(ctx->ifaces, ifname); - if (ifp == NULL || - ifp->options == NULL || !(ifp->options->options & DHCPCD_LINK) || - !ifp->active) - return; + bool nolink = ifp->options == NULL || + !(ifp->options->options & DHCPCD_LINK); + ifp->flags = flags; if (carrier == LINK_UNKNOWN) { - if (ifp->wireless) { + if (ifp->wireless) carrier = LINK_DOWN; - ifp->flags = flags; - } else - carrier = if_carrier(ifp); - } else - ifp->flags = flags; - if (carrier == LINK_UNKNOWN) - carrier = IF_UPANDRUNNING(ifp) ? LINK_UP : LINK_DOWN; + else + carrier = IF_UPANDRUNNING(ifp) ? LINK_UP : LINK_DOWN; + } if (carrier == LINK_DOWN || (ifp->flags & IFF_UP) == 0) { if (ifp->carrier != LINK_DOWN) { - if (ifp->carrier == LINK_UP) - loginfox("%s: carrier lost", ifp->name); #ifdef NOCARRIER_PRESERVE_IP if (ifp->flags & IFF_UP && - !(ifp->options->options & DHCPCD_ANONYMOUS)) + (ifp->options == NULL || + !(ifp->options->options & DHCPCD_ANONYMOUS))) ifp->carrier = LINK_DOWN_IFFUP; else #endif ifp->carrier = LINK_DOWN; + if (!ifp->active || nolink) + return; + loginfox("%s: carrier lost", ifp->name); script_runreason(ifp, "NOCARRIER"); #ifdef NOCARRIER_PRESERVE_IP if (ifp->flags & IFF_UP && @@ -767,13 +758,14 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, } } else if (carrier == LINK_UP && ifp->flags & IFF_UP) { if (ifp->carrier != LINK_UP) { - loginfox("%s: carrier acquired", ifp->name); ifp->carrier = LINK_UP; + if (ifp->active) + loginfox("%s: carrier acquired", ifp->name); #if !defined(__linux__) && !defined(__NetBSD__) /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the * hardware address changes so we have to go * through the disovery process to work it out. */ - dhcpcd_handleinterface(ctx, 0, ifp->name); + dhcpcd_handleinterface(ifp->ctx, 0, ifp->name); #endif if (ifp->wireless) { uint8_t ossid[IF_SSIDLEN]; @@ -784,8 +776,9 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, if_getssid(ifp); /* If we changed SSID network, drop leases */ - if (ifp->ssid_len != olen || - memcmp(ifp->ssid, ossid, ifp->ssid_len)) + if ((ifp->ssid_len != olen || + memcmp(ifp->ssid, ossid, ifp->ssid_len)) && + ifp->active) { dhcpcd_reportssid(ifp); #ifdef NOCARRIER_PRESERVE_IP @@ -796,6 +789,8 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags, #endif } } + if (!ifp->active || nolink) + return; dhcpcd_initstate(ifp, 0); script_runreason(ifp, "CARRIER"); #ifdef INET6 @@ -871,20 +866,11 @@ dhcpcd_startinterface(void *arg) struct interface *ifp = arg; struct if_options *ifo = ifp->options; - if (ifo->options & DHCPCD_LINK) { - switch (ifp->carrier) { - case LINK_UP: - break; - case LINK_DOWN: - loginfox("%s: waiting for carrier", ifp->name); - return; - case LINK_UNKNOWN: - /* No media state available. - * Loop until both IFF_UP and IFF_RUNNING are set */ - if (ifo->poll == 0) - if_pollinit(ifp); - return; - } + if (ifo->options & DHCPCD_LINK && (ifp->carrier == LINK_DOWN || + (ifp->carrier == LINK_UNKNOWN && !IF_UPANDRUNNING(ifp)))) + { + loginfox("%s: waiting for carrier", ifp->name); + return; } if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) && @@ -993,9 +979,6 @@ dhcpcd_prestartinterface(void *arg) logerr(__func__); } - if (ifp->options->poll != 0) - if_pollinit(ifp); - dhcpcd_startinterface(ifp); } @@ -1034,14 +1017,13 @@ dhcpcd_activateinterface(struct interface *ifp, unsigned long long options) int dhcpcd_handleinterface(void *arg, int action, const char *ifname) { - struct dhcpcd_ctx *ctx; + struct dhcpcd_ctx *ctx = arg; struct ifaddrs *ifaddrs; struct if_head *ifs; struct interface *ifp, *iff; const char * const argv[] = { ifname }; int e; - ctx = arg; if (action == -1) { ifp = if_find(ctx->ifaces, ifname); if (ifp == NULL) { @@ -1131,14 +1113,14 @@ dhcpcd_handlelink(void *arg) static void dhcpcd_checkcarrier(void *arg) { - struct interface *ifp = arg; - int carrier; + struct interface *ifp0 = arg, *ifp; - /* Check carrier here rather than setting LINK_UNKNOWN. - * This is because we force LINK_UNKNOWN as down for wireless which - * we do not want when dealing with a route socket overflow. */ - carrier = if_carrier(ifp); - dhcpcd_handlecarrier(ifp->ctx, carrier, ifp->flags, ifp->name); + ifp = if_find(ifp0->ctx->ifaces, ifp0->name); + if (ifp == NULL || ifp->carrier == ifp0->carrier) + return; + + dhcpcd_handlecarrier(ifp, ifp0->carrier, ifp0->flags); + if_free(ifp0); } #ifndef SMALL @@ -1224,10 +1206,10 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) ifp1 = if_find(ctx->ifaces, ifp->name); if (ifp1 != NULL) { /* If the interface already exists, - * check carrier state. */ + * check carrier state. + * dhcpcd_checkcarrier will free ifp. */ eloop_timeout_add_sec(ctx->eloop, 0, - dhcpcd_checkcarrier, ifp1); - if_free(ifp); + dhcpcd_checkcarrier, ifp); continue; } TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); @@ -1417,17 +1399,9 @@ dhcpcd_signal_cb(int sig, void *arg) } if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) { - if (sig == SIGHUP) - return; - - pid_t pid = pidfile_read(ctx->pidfile); - if (pid == -1) { - if (errno != ENOENT) - logerr("%s: pidfile_read",__func__); - } else if (pid == 0) - logerr("%s: pid cannot be zero", __func__); - else if (kill(pid, sig) == -1) - logerr("%s: kill", __func__); + if (sig != SIGHUP && + write(ctx->fork_fd, &sig, sizeof(sig)) == -1) + logerr("%s: write", __func__); return; } @@ -1780,7 +1754,10 @@ dhcpcd_fork_cb(void *arg) __func__, len, sizeof(exit_code)); exit_code = EXIT_FAILURE; } - eloop_exit(ctx->eloop, exit_code); + if (ctx->options & DHCPCD_FORKED) + eloop_exit(ctx->eloop, exit_code); + else + dhcpcd_signal_cb(exit_code, ctx); } static void @@ -1893,9 +1870,16 @@ main(int argc, char **argv) ctx.ps_inet_fd = ctx.ps_control_fd = -1; TAILQ_INIT(&ctx.ps_processes); #endif - rt_init(&ctx); - logopts = LOGERR_ERR|LOGERR_LOG|LOGERR_LOG_DATE|LOGERR_LOG_PID; + /* Check our streams for validity */ + ctx.stdin_valid = fcntl(STDIN_FILENO, F_GETFD) != -1; + ctx.stdout_valid = fcntl(STDOUT_FILENO, F_GETFD) != -1; + ctx.stderr_valid = fcntl(STDERR_FILENO, F_GETFD) != -1; + + logopts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID; + if (ctx.stderr_valid) + logopts |= LOGERR_ERR; + i = 0; while ((opt = getopt_long(argc, argv, ctx.options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS, @@ -1979,6 +1963,8 @@ main(int argc, char **argv) ctx.ifc = argc - optind; ctx.ifv = argv + optind; + rt_init(&ctx); + ifo = read_config(&ctx, NULL, NULL, NULL); if (ifo == NULL) { if (ctx.options & DHCPCD_PRINT_PIDFILE) @@ -2080,7 +2066,7 @@ printpidfile: } if (chdir("/") == -1) - logerr("%s: chdir `/'", __func__); + logerr("%s: chdir: /", __func__); /* Freeing allocated addresses from dumping leases can trigger * eloop removals as well, so init here. */ @@ -2147,7 +2133,7 @@ printpidfile: { ctx.options |= DHCPCD_FORKED; /* pretend child process */ #ifdef PRIVSEP - if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) goto exit_failure; #endif ifp = calloc(1, sizeof(*ifp)); @@ -2199,12 +2185,9 @@ printpidfile: 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; + if (IN_PRIVSEP(&ctx) && + ps_mastersandbox(&ctx, NULL) == -1) goto exit_failure; - } - ctx.options |= DHCPCD_FORKED; #endif if (!(ctx.options & DHCPCD_DUMPLEASE)) loginfox("sending commands to dhcpcd process"); @@ -2240,9 +2223,9 @@ 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); + logerr("%s: mkdir: %s", __func__, DBDIR); if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST) - logerr("%s: mkdir `%s'", __func__, RUNDIR); + logerr("%s: mkdir: %s", __func__, RUNDIR); if ((pid = pidfile_lock(ctx.pidfile)) != 0) { if (pid == -1) logerr("%s: pidfile_lock: %s", @@ -2256,12 +2239,13 @@ printpidfile: } loginfox(PACKAGE "-" VERSION " starting"); - if (freopen(_PATH_DEVNULL, "r", stdin) == NULL) - logerr("%s: freopen stdin", __func__); + if (ctx.stdin_valid && freopen(_PATH_DEVNULL, "w", stdin) == NULL) + logwarn("freopen stdin"); #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) + (ctx.stderr_valid && + xsocketpair(AF_UNIX, SOCK_DGRAM | SOCK_CXNB, 0, stderr_fd) == -1)) { logerr("socketpair"); goto exit_failure; @@ -2279,20 +2263,25 @@ printpidfile: goto exit_failure; } #endif + eloop_event_add(ctx.eloop, ctx.fork_fd, dhcpcd_fork_cb, &ctx); + /* * 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 (ctx.stderr_valid) { + if (dup2(stderr_fd[1], STDERR_FILENO) == -1 || + (ctx.stdout_valid && + dup2(stderr_fd[1], STDOUT_FILENO) == -1)) + logerr("dup2"); + close(stderr_fd[0]); + close(stderr_fd[1]); + } else if (ctx.stdout_valid) { + if (freopen(_PATH_DEVNULL, "w", stdout) == NULL) + logerr("freopen stdout"); + } if (setsid() == -1) { logerr("%s: setsid", __func__); goto exit_failure; @@ -2311,11 +2300,10 @@ printpidfile: } break; default: - ctx.options |= DHCPCD_FORKED; /* A lie */ + setproctitle("[launcher]"); + ctx.options |= DHCPCD_FORKED; 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) @@ -2324,10 +2312,25 @@ printpidfile: 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); + + if (ctx.stderr_valid) { + ctx.stderr_fd = stderr_fd[0]; + close(stderr_fd[1]); +#ifdef PRIVSEP_RIGHTS + if (ps_rights_limit_fd(stderr_fd[0]) == 1) { + logerr("ps_rights_limit_fdpair"); + goto exit_failure; + } +#endif + if (ctx.stderr_valid) + eloop_event_add(ctx.eloop, ctx.stderr_fd, + dhcpcd_stderr_cb, &ctx); + } +#ifdef PRIVSEP + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, NULL) == -1) + goto exit_failure; +#endif goto run_loop; } @@ -2336,10 +2339,16 @@ printpidfile: ctx.options |= DHCPCD_STARTED; if ((pid = pidfile_lock(ctx.pidfile)) != 0) { logerr("%s: pidfile_lock %d", __func__, pid); +#ifdef PRIVSEP + /* privsep has not started ... */ + ctx.options &= ~DHCPCD_PRIVSEP; +#endif goto exit_failure; } #endif + os_init(); + #if defined(BSD) && defined(INET6) /* Disable the kernel RTADV sysctl as early as possible. */ if (ctx.options & DHCPCD_IPV6 && ctx.options & DHCPCD_IPV6RS) @@ -2399,7 +2408,7 @@ printpidfile: eloop_event_add(ctx.eloop, ctx.link_fd, dhcpcd_handlelink, &ctx); #ifdef PRIVSEP - if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx) == -1) + if (IN_PRIVSEP(&ctx) && ps_mastersandbox(&ctx, "stdio route") == -1) goto exit_failure; #endif @@ -2525,6 +2534,9 @@ exit1: #endif freeifaddrs(ifaddrs); } + /* ps_stop will clear DHCPCD_PRIVSEP but we need to + * remember it to avoid attemping to remove the pidfile */ + oi = ctx.options & DHCPCD_PRIVSEP ? 1 : 0; #ifdef PRIVSEP ps_stop(&ctx); #endif @@ -2573,14 +2585,14 @@ exit1: setproctitle_free(); #endif #ifdef USE_SIGNALS - if (ctx.options & DHCPCD_FORKED) - _exit(i); /* so atexit won't remove our pidfile */ - else if (ctx.options & DHCPCD_STARTED) { + if (ctx.options & DHCPCD_STARTED) { /* Try to detach from the launch process. */ if (ctx.fork_fd != -1 && write(ctx.fork_fd, &i, sizeof(i)) == -1) logerr("%s: write", __func__); } + if (ctx.options & DHCPCD_FORKED || oi != 0) + _exit(i); /* so atexit won't remove our pidfile */ #endif return i; } diff --git a/external/bsd/dhcpcd/dist/src/if-bsd.c b/external/bsd/dhcpcd/dist/src/if-bsd.c index 5e748a4e9dcf..8f10acdcf14d 100644 --- a/external/bsd/dhcpcd/dist/src/if-bsd.c +++ b/external/bsd/dhcpcd/dist/src/if-bsd.c @@ -107,6 +107,7 @@ static const char * const ifnames_ignore[] = { "fwe", /* Firewire */ "fwip", /* Firewire */ "tap", + "vether", "xvif", /* XEN DOM0 -> guest interface */ NULL }; @@ -121,6 +122,12 @@ struct rtm char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX]; }; +int +os_init(void) +{ + return 0; +} + int if_init(__unused struct interface *iface) { @@ -208,6 +215,13 @@ if_opensockets_os(struct dhcpcd_ctx *ctx) #warning kernel does not support route message filtering #endif +#ifdef PRIVSEP_RIGHTS + /* We need to getsockopt for SO_RCVBUF and + * setsockopt for RO_MISSFILTER. */ + if (IN_PRIVSEP(ctx)) + ps_rights_limit_fd_sockopt(ctx->link_fd); +#endif + return 0; } @@ -353,21 +367,40 @@ if_ignore(struct dhcpcd_ctx *ctx, const char *ifname) #endif } -int -if_carrier(struct interface *ifp) +static int if_indirect_ioctl(struct dhcpcd_ctx *ctx, + const char *ifname, unsigned long cmd, void *data, size_t len) { - struct ifmediareq ifmr = { .ifm_status = 0 }; + struct ifreq ifr = { .ifr_flags = 0 }; - /* Not really needed, but the other OS update flags here also */ - if (if_getflags(ifp) == -1) +#if defined(PRIVSEP) && (defined(HAVE_CAPSICUM) || defined(HAVE_PLEDGE)) + if (IN_PRIVSEP(ctx)) + return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len); +#else + UNUSED(len); +#endif + + strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_data = data; + return ioctl(ctx->pf_inet_fd, cmd, &ifr); +} + +int +if_carrier(__unused struct interface *ifp, const void *ifadata) +{ + const struct if_data *ifi = ifadata; + + /* + * Every BSD returns this and it is the sole source of truth. + * Not all BSD's support SIOCGIFDATA and not all interfaces + * support SIOCGIFMEDIA. + */ + assert(ifadata != NULL); + + if (ifi->ifi_link_state >= LINK_STATE_UP) + return LINK_UP; + if (ifi->ifi_link_state == LINK_STATE_UNKNOWN) return LINK_UNKNOWN; - - strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); - if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) == -1 || - !(ifmr.ifm_status & IFM_AVALID)) - return LINK_UNKNOWN; - - return (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN; + return LINK_DOWN; } static void @@ -381,25 +414,6 @@ if_linkaddr(struct sockaddr_dl *sdl, const struct interface *ifp) sdl->sdl_index = (unsigned short)ifp->index; } -#if defined(SIOCG80211NWID) || defined(SIOCGETVLAN) -static int if_indirect_ioctl(struct dhcpcd_ctx *ctx, - const char *ifname, unsigned long cmd, void *data, size_t len) -{ - struct ifreq ifr = { .ifr_flags = 0 }; - -#if defined(PRIVSEP) && defined(HAVE_PLEDGE) - if (IN_PRIVSEP(ctx)) - return (int)ps_root_indirectioctl(ctx, cmd, ifname, data, len); -#else - UNUSED(len); -#endif - - strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_data = data; - return ioctl(ctx->pf_inet_fd, cmd, &ifr); -} -#endif - static int if_getssid1(struct dhcpcd_ctx *ctx, const char *ifname, void *ssid) { @@ -1186,24 +1200,8 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) return 0; - switch (ifm->ifm_data.ifi_link_state) { - case LINK_STATE_UNKNOWN: - link_state = LINK_UNKNOWN; - break; -#ifdef LINK_STATE_FULL_DUPLEX - case LINK_STATE_HALF_DUPLEX: /* FALLTHROUGH */ - case LINK_STATE_FULL_DUPLEX: /* FALLTHROUGH */ -#endif - case LINK_STATE_UP: - link_state = LINK_UP; - break; - default: - link_state = LINK_DOWN; - break; - } - - dhcpcd_handlecarrier(ctx, link_state, - (unsigned int)ifm->ifm_flags, ifp->name); + link_state = if_carrier(ifp, &ifm->ifm_data); + dhcpcd_handlecarrier(ifp, link_state, (unsigned int)ifm->ifm_flags); return 0; } diff --git a/external/bsd/dhcpcd/dist/src/if-options.c b/external/bsd/dhcpcd/dist/src/if-options.c index 213d05cc186b..9b2c74fb695d 100644 --- a/external/bsd/dhcpcd/dist/src/if-options.c +++ b/external/bsd/dhcpcd/dist/src/if-options.c @@ -49,6 +49,7 @@ #include "dhcp.h" #include "dhcp6.h" #include "dhcpcd-embedded.h" +#include "duid.h" #include "if.h" #include "if-options.h" #include "ipv4.h" @@ -94,7 +95,7 @@ const struct option cf_options[] = { {"noarp", no_argument, NULL, 'A'}, {"nobackground", no_argument, NULL, 'B'}, {"nohook", required_argument, NULL, 'C'}, - {"duid", no_argument, NULL, 'D'}, + {"duid", optional_argument, NULL, 'D'}, {"lastlease", no_argument, NULL, 'E'}, {"fqdn", optional_argument, NULL, 'F'}, {"nogateway", no_argument, NULL, 'G'}, @@ -164,7 +165,6 @@ const struct option cf_options[] = { {"inactive", no_argument, NULL, O_INACTIVE}, {"mudurl", required_argument, NULL, O_MUDURL}, {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, - {"poll", optional_argument, NULL, O_POLL}, {NULL, 0, NULL, '\0'} }; @@ -460,13 +460,13 @@ parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg) if (e != 0 || (net != NULL && inet_cidrtoaddr((int)i, net) != 0)) { - logerrx("`%s' is not a valid CIDR", p); + logerrx("invalid CIDR: %s", p); return -1; } } if (addr != NULL && inet_aton(arg, addr) == 0) { - logerrx("`%s' is not a valid IP address", arg); + logerrx("invalid IP address: %s", arg); return -1; } if (p != NULL) @@ -788,7 +788,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) { - logerrx("unknown option `%s'", arg); + logerrx("unknown option: %s", arg); return -1; } break; @@ -800,7 +800,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || make_option_mask(d, dl, od, odl, require, arg, -1) != 0) { - logerrx("unknown option `%s'", arg); + logerrx("unknown option: %s", arg); return -1; } break; @@ -985,6 +985,20 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, break; case 'D': ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID; + if (ifname != NULL) /* duid type only a global option */ + break; + if (arg == NULL) + ctx->duid_type = DUID_DEFAULT; + else if (strcmp(arg, "ll") == 0) + ctx->duid_type = DUID_LL; + else if (strcmp(arg, "llt") == 0) + ctx->duid_type = DUID_LLT; + else if (strcmp(arg, "uuid") == 0) + ctx->duid_type = DUID_UUID; + else { + logwarnx("%s: invalid duid type", arg); + ctx->duid_type = DUID_DEFAULT; + } break; case 'E': ifo->options |= DHCPCD_LASTLEASE; @@ -1003,7 +1017,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, else if (strcmp(arg, "disable") == 0) ifo->fqdn = FQDN_DISABLE; else { - logerrx("invalid value `%s' for FQDN", arg); + logerrx("invalid FQDN value: %s", arg); return -1; } break; @@ -1049,7 +1063,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, make_option_mask(d, dl, od, odl, require, arg, -1) != 0 || make_option_mask(d, dl, od, odl, no, arg, 1) != 0) { - logerrx("unknown option `%s'", arg); + logerrx("unknown option: %s", arg); return -1; } break; @@ -1062,7 +1076,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || make_option_mask(d, dl, od, odl, reject, arg, -1) != 0) { - logerrx("unknown option `%s'", arg); + logerrx("unknown option: %s", arg); return -1; } break; @@ -1299,10 +1313,10 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, ifo->dstmask, arg, 2) != 0) { if (errno == EINVAL) - logerrx("option `%s' does not take" - " an IPv4 address", arg); + logerrx("option does not take" + " an IPv4 address: %s", arg); else - logerrx("unknown option `%s'", arg); + logerrx("unknown option: %s", arg); return -1; } break; @@ -1785,7 +1799,7 @@ err_sla: return -1; } if (l && !(t & (OT_STRING | OT_BINHEX))) { - logwarnx("ignoring length for type `%s'", arg); + logwarnx("ignoring length for type: %s", arg); l = 0; } if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) && @@ -2220,18 +2234,6 @@ invalid_token: } #endif break; - case O_POLL: - if (arg == NULL) { - ifo->poll = IF_POLL_UP; - break; - } - ifo->poll = (unsigned long) - strtou(arg, NULL, 0, 0, ULONG_MAX, &e); - if (e) { - logerrx("failed to convert poll %s", arg); - return -1; - } - break; default: return 0; } diff --git a/external/bsd/dhcpcd/dist/src/ipv6nd.c b/external/bsd/dhcpcd/dist/src/ipv6nd.c index d1cc4efab773..4afbf1fbad6f 100644 --- a/external/bsd/dhcpcd/dist/src/ipv6nd.c +++ b/external/bsd/dhcpcd/dist/src/ipv6nd.c @@ -1223,7 +1223,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, if (rap->willexpire) new_data = true; loglevel = new_rap || rap->willexpire || !rap->isreachable ? - LOG_INFO : LOG_DEBUG, + LOG_INFO : LOG_DEBUG; logmessage(loglevel, "%s: Router Advertisement from %s", ifp->name, rap->sfrom); diff --git a/external/bsd/dhcpcd/dist/src/logerr.c b/external/bsd/dhcpcd/dist/src/logerr.c index 817c53ca4d1b..5fba91d33c58 100644 --- a/external/bsd/dhcpcd/dist/src/logerr.c +++ b/external/bsd/dhcpcd/dist/src/logerr.c @@ -382,7 +382,7 @@ logopen(const char *path) } #ifndef SMALL - if ((ctx->log_file = fopen(path, "a")) == NULL) + if ((ctx->log_file = fopen(path, "ae")) == NULL) return -1; setlinebuf(ctx->log_file); return fileno(ctx->log_file); diff --git a/external/bsd/dhcpcd/dist/src/privsep.c b/external/bsd/dhcpcd/dist/src/privsep.c index 3f1dc2d6e06d..d1c74f4ae9d9 100644 --- a/external/bsd/dhcpcd/dist/src/privsep.c +++ b/external/bsd/dhcpcd/dist/src/privsep.c @@ -76,7 +76,6 @@ #ifdef HAVE_CAPSICUM #include #include -#define ps_rights_limit_stdio caph_limit_stdio #endif #ifdef HAVE_UTIL_H #include @@ -118,11 +117,12 @@ ps_dropprivs(struct dhcpcd_ctx *ctx) struct passwd *pw = ctx->ps_user; if (!(ctx->options & DHCPCD_FORKED)) - logdebugx("chrooting to `%s' as %s", pw->pw_dir, pw->pw_name); - if (chroot(pw->pw_dir) == -1) - logerr("%s: chroot `%s'", __func__, pw->pw_dir); + logdebugx("chrooting as %s to %s", pw->pw_name, pw->pw_dir); + if (chroot(pw->pw_dir) == -1 && + (errno != EPERM || ctx->options & DHCPCD_FORKED)) + logerr("%s: chroot: %s", __func__, pw->pw_dir); if (chdir("/") == -1) - logerr("%s: chdir `/'", __func__); + logerr("%s: chdir: /", __func__); if ((setgroups(1, &pw->pw_gid) == -1 || setgid(pw->pw_gid) == -1 || @@ -259,6 +259,18 @@ ps_rights_limit_fd(int fd) return 0; } +int +ps_rights_limit_fd_sockopt(int fd) +{ + cap_rights_t rights; + + cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, + CAP_GETSOCKOPT, CAP_SETSOCKOPT); + if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) + return -1; + return 0; +} + int ps_rights_limit_fd_rdonly(int fd) { @@ -278,6 +290,25 @@ ps_rights_limit_fdpair(int fd[]) return -1; return 0; } + +static int +ps_rights_limit_stdio(struct dhcpcd_ctx *ctx) +{ + const int iebadf = CAPH_IGNORE_EBADF; + int error = 0; + + if (ctx->stdin_valid && + caph_limit_stream(STDIN_FILENO, CAPH_READ | iebadf) == -1) + error = -1; + if (ctx->stdout_valid && + caph_limit_stream(STDOUT_FILENO, CAPH_WRITE | iebadf) == -1) + error = -1; + if (ctx->stderr_valid && + caph_limit_stream(STDERR_FILENO, CAPH_WRITE | iebadf) == -1) + error = -1; + + return error; +} #endif pid_t @@ -346,7 +377,7 @@ ps_dostart(struct dhcpcd_ctx *ctx, #ifdef PRIVSEP_RIGHTS /* We cannot limit the root process in any way. */ - if (ps_rights_limit_stdio() == -1) { + if (ps_rights_limit_stdio(ctx) == -1) { logerr("ps_rights_limit_stdio"); goto errexit; } @@ -472,10 +503,45 @@ started_net: } int -ps_mastersandbox(struct dhcpcd_ctx *ctx) +ps_entersandbox(const char *_pledge, const char **sandbox) { - if (ps_dropprivs(ctx) == -1) { +#if !defined(HAVE_PLEDGE) + UNUSED(_pledge); +#endif + +#if defined(HAVE_CAPSICUM) + if (sandbox != NULL) + *sandbox = "capsicum"; + return cap_enter(); +#elif defined(HAVE_PLEDGE) + if (sandbox != NULL) + *sandbox = "pledge"; + return pledge(_pledge, NULL); +#elif defined(HAVE_SECCOMP) + if (sandbox != NULL) + *sandbox = "seccomp"; + return ps_seccomp_enter(); +#else + if (sandbox != NULL) + *sandbox = "posix resource limited"; + return 0; +#endif +} + +int +ps_mastersandbox(struct dhcpcd_ctx *ctx, const char *_pledge) +{ + const char *sandbox = NULL; + bool forked; + int dropped; + + forked = ctx->options & DHCPCD_FORKED; + ctx->options &= ~DHCPCD_FORKED; + dropped = ps_dropprivs(ctx); + if (forked) + ctx->options |= DHCPCD_FORKED; + if (dropped == -1) { logerr("%s: ps_dropprivs", __func__); return -1; } @@ -483,26 +549,25 @@ ps_mastersandbox(struct dhcpcd_ctx *ctx) #ifdef PRIVSEP_RIGHTS 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) + ps_rights_limit_stdio(ctx) == -1) { logerr("%s: cap_rights_limit", __func__); return -1; } #endif -#ifdef HAVE_CAPSICUM - if (cap_enter() == -1 && errno != ENOSYS) { - logerr("%s: cap_enter", __func__); - return -1; - } -#endif -#ifdef HAVE_PLEDGE - if (pledge("stdio route", NULL) == -1) { - logerr("%s: pledge", __func__); - return -1; - } -#endif + if (_pledge == NULL) + _pledge = "stdio"; + if (ps_entersandbox(_pledge, &sandbox) == -1) { + if (errno == ENOSYS) { + if (sandbox != NULL) + logwarnx("sandbox unavailable: %s", sandbox); + return 0; + } + logerr("%s: %s", __func__, sandbox); + return -1; + } else if (!forked) + logdebugx("sandbox: %s", sandbox); return 0; } diff --git a/external/bsd/dhcpcd/dist/src/script.c b/external/bsd/dhcpcd/dist/src/script.c index 059e9ab22621..d611a644c65b 100644 --- a/external/bsd/dhcpcd/dist/src/script.c +++ b/external/bsd/dhcpcd/dist/src/script.c @@ -736,7 +736,7 @@ script_runreason(const struct interface *ifp, const char *reason) argv[0] = ctx->script; argv[1] = NULL; - logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); + logdebugx("%s: executing: %s %s", ifp->name, argv[0], reason); #ifdef PRIVSEP if (ctx->options & DHCPCD_PRIVSEP) {