From 4f235d86281ed9b8f1029007158642352fa4dae9 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Fri, 6 Oct 2023 10:09:39 +0100 Subject: [PATCH] Import dhcpcd-10.0.3 with the following changes: DHCP: Don't crash on a test run dhcpcd: Fix off-by-one overflow when read() writes full BUFSIZ privsep: fix strlcpy overflow in psp_ifname privsep: Fix a FD leak when processes exit dhcpcd: Use a local variable instead of the optind dhcpcd: Guard against handling many SIGTERM/SIGINT DHCP6: Send correct amount of used buffer for prefix exclude option options: andsf6 is DHCPv6, not DHCP options: introduce the uri option as opposed to a string DHCP6: Set all requested addrs as not stale when starting discovery --- contrib/dhcpcd/README.md | 6 ++-- contrib/dhcpcd/src/defs.h | 2 +- contrib/dhcpcd/src/dhcp-common.c | 59 +++++++++++++++++++++++++++++++++++- contrib/dhcpcd/src/dhcp-common.h | 1 + contrib/dhcpcd/src/dhcp.c | 3 +- contrib/dhcpcd/src/dhcp6.c | 19 +++++++++--- contrib/dhcpcd/src/dhcpcd-embedded.c | 10 +++--- contrib/dhcpcd/src/dhcpcd-embedded.h | 2 +- contrib/dhcpcd/src/dhcpcd.8 | 4 +-- contrib/dhcpcd/src/dhcpcd.c | 47 ++++++++++++++++++++-------- contrib/dhcpcd/src/dhcpcd.conf.5 | 6 +++- contrib/dhcpcd/src/if-options.c | 2 ++ contrib/dhcpcd/src/ipv6nd.c | 2 +- contrib/dhcpcd/src/privsep.c | 7 ++--- contrib/dhcpcd/src/privsep.h | 2 +- 15 files changed, 135 insertions(+), 37 deletions(-) diff --git a/contrib/dhcpcd/README.md b/contrib/dhcpcd/README.md index 2f31d38a55..a2e0892edf 100644 --- a/contrib/dhcpcd/README.md +++ b/contrib/dhcpcd/README.md @@ -78,8 +78,8 @@ which only apply to calling dhcpcd from the command line. ## Compatibility -dhcpcd-5 is only fully command line compatible with dhcpcd-4 -For compatibility with older versions, use dhcpcd-4 +dhcpcd-5 is only fully command line compatible with dhcpcd-4. +For compatibility with older versions, use dhcpcd-4. ## Upgrading dhcpcd-7 defaults the database directory to `/var/db/dhcpcd` instead of @@ -87,7 +87,7 @@ dhcpcd-7 defaults the database directory to `/var/db/dhcpcd` instead of in /etc. dhcpcd-9 defaults the run directory to `/var/run/dhcpcd` instead of -`/var/run` and the prefix of dhcpcd has been removed from the files. +`/var/run` and the prefix of dhcpcd has been removed from the files therein. ## ChangeLog We no longer supply a ChangeLog. diff --git a/contrib/dhcpcd/src/defs.h b/contrib/dhcpcd/src/defs.h index c0d2e61b90..9749cc9d55 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 "10.0.2" +#define VERSION "10.0.3" #ifndef PRIVSEP_USER # define PRIVSEP_USER "_" PACKAGE diff --git a/contrib/dhcpcd/src/dhcp-common.c b/contrib/dhcpcd/src/dhcp-common.c index 679af24328..e5dd9efa72 100644 --- a/contrib/dhcpcd/src/dhcp-common.c +++ b/contrib/dhcpcd/src/dhcp-common.c @@ -125,6 +125,8 @@ dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols) printf(" binhex"); else if (opt->type & OT_STRING) printf(" string"); + else if (opt->type & OT_URI) + printf(" uri"); if (opt->type & OT_RFC3361) printf(" rfc3361"); if (opt->type & OT_RFC3442) @@ -518,6 +520,10 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) errno = EINVAL; break; } + if (type & OT_URI && isspace(c)) { + errno = EINVAL; + break; + } if ((type & (OT_ESCSTRING | OT_ESCFILE) && (c == '\\' || !isascii(c) || !isprint(c))) || (type & OT_ESCFILE && (c == '/' || c == ' '))) @@ -675,7 +681,58 @@ print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt, return print_rfc3442(fp, data, dl); #endif - if (opt->type & OT_STRING) { + /* Produces a space separated list of URIs. + * This is valid as a URI cannot contain a space. */ + if ((opt->type & (OT_ARRAY | OT_URI)) == (OT_ARRAY | OT_URI)) { +#ifdef SMALL + errno = ENOTSUP; + return -1; +#else + char buf[UINT16_MAX + 1]; + uint16_t sz; + bool first = true; + + while (dl) { + if (dl < 2) { + errno = EINVAL; + goto err; + } + + memcpy(&u16, data, sizeof(u16)); + sz = ntohs(u16); + data += sizeof(u16); + dl -= sizeof(u16); + + if (sz == 0) + continue; + if (sz > dl) { + errno = EINVAL; + goto err; + } + + if (print_string(buf, sizeof(buf), + opt->type, data, sz) == -1) + goto err; + + if (first) + first = false; + else if (fputc(' ', fp) == EOF) + goto err; + + if (fprintf(fp, "%s", buf) == -1) + goto err; + + data += sz; + dl -= sz; + } + + if (fputc('\0', fp) == EOF) + goto err; + return 0; +#endif + } + + if (opt->type & (OT_STRING | OT_URI)) { char buf[1024]; if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1) diff --git a/contrib/dhcpcd/src/dhcp-common.h b/contrib/dhcpcd/src/dhcp-common.h index 3b21c98e2d..5141314040 100644 --- a/contrib/dhcpcd/src/dhcp-common.h +++ b/contrib/dhcpcd/src/dhcp-common.h @@ -80,6 +80,7 @@ #define OT_ESCFILE (1 << 26) #define OT_BITFLAG (1 << 27) #define OT_RESERVED (1 << 28) +#define OT_URI (1 << 29) #define DHC_REQ(r, n, o) \ (has_option_mask((r), (o)) && !has_option_mask((n), (o))) diff --git a/contrib/dhcpcd/src/dhcp.c b/contrib/dhcpcd/src/dhcp.c index edd1c011bb..e029cee336 100644 --- a/contrib/dhcpcd/src/dhcp.c +++ b/contrib/dhcpcd/src/dhcp.c @@ -3314,7 +3314,8 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len, state->reason = "TEST"; script_runreason(ifp, state->reason); eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); - state->bpf->bpf_flags |= BPF_EOF; + if (state->bpf) + state->bpf->bpf_flags |= BPF_EOF; return; } eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); diff --git a/contrib/dhcpcd/src/dhcp6.c b/contrib/dhcpcd/src/dhcp6.c index e7767ca744..63fe2dc645 100644 --- a/contrib/dhcpcd/src/dhcp6.c +++ b/contrib/dhcpcd/src/dhcp6.c @@ -1022,9 +1022,11 @@ dhcp6_makemessage(struct interface *ifp) n--; while (n-- > 0) *ep++ = *pp--; - if (u8) + n = (size_t)(ep - exb); + if (u8) { *ep = (uint8_t)(*pp << u8); - n++; + n++; + } COPYIN(D6_OPTION_PD_EXCLUDE, exb, (uint16_t)n); ia_na_len = (uint16_t) @@ -1628,6 +1630,7 @@ dhcp6_startdiscover(void *arg) struct interface *ifp; struct dhcp6_state *state; int llevel; + struct ipv6_addr *ia; ifp = arg; state = D6_STATE(ifp); @@ -1652,6 +1655,14 @@ dhcp6_startdiscover(void *arg) state->new = NULL; state->new_len = 0; + /* If we fail to renew or confirm, our requested addreses will + * be marked as stale. + To re-request them, just mark them as not stale. */ + TAILQ_FOREACH(ia, &state->addrs, next) { + if (ia->flags & IPV6_AF_REQUEST) + ia->flags &= ~IPV6_AF_STALE; + } + if (dhcp6_makemessage(ifp) == -1) logerr("%s: %s", __func__, ifp->name); else @@ -2268,9 +2279,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid, } else { if (!(a->flags & IPV6_AF_DELEGATEDPFX)) a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX; - a->flags &= ~(IPV6_AF_STALE | - IPV6_AF_EXTENDED | - IPV6_AF_REQUEST); + a->flags &= ~(IPV6_AF_STALE | IPV6_AF_EXTENDED); if (a->prefix_vltime != pdp.vltime) a->flags |= IPV6_AF_NEW; } diff --git a/contrib/dhcpcd/src/dhcpcd-embedded.c b/contrib/dhcpcd/src/dhcpcd-embedded.c index 1b2f7ea4c5..320db1b831 100644 --- a/contrib/dhcpcd/src/dhcpcd-embedded.c +++ b/contrib/dhcpcd/src/dhcpcd-embedded.c @@ -273,7 +273,7 @@ const char dhcpcd_embedded_conf[] = "encap 3 domain es\n" "define 141 array domain sip_ua_cs_list\n" "define 142 array ipaddress andsf\n" -"define 143 array ip6address andsf6\n" +"define 143 array uri sztp_redirect\n" "define 144 binhex geoloc\n" "define 145 array byte forcerenew_nonce_capable\n" "define 146 embed rdnss_selection\n" @@ -300,7 +300,7 @@ const char dhcpcd_embedded_conf[] = "encap 1 binhex vpn_id\n" "encap 255 flag global\n" "define 249 rfc3442 ms_classless_static_routes\n" -"define 252 string wpad_url\n" +"define 252 uri wpad_url\n" "definend 1 binhex source_address\n" "definend 2 binhex target_address\n" "definend 3 index embed prefix_information\n" @@ -424,7 +424,7 @@ const char dhcpcd_embedded_conf[] = "encap 3 domain fqdn\n" "define6 57 domain access_domain\n" "define6 58 array domain sip_ua_cs_list\n" -"define6 59 string bootfile_url\n" +"define6 59 uri bootfile_url\n" "define6 60 binhex bootfile_param\n" "define6 61 array uint16 architecture_types\n" "define6 62 embed nii\n" @@ -493,9 +493,11 @@ const char dhcpcd_embedded_conf[] = "encap 90 option\n" "encap 92 option\n" "define6 112 string mudurl\n" -"define6 103 string captive_portal_uri\n" +"define6 103 uri captive_portal_uri\n" +"define6 136 array uri sztp_redirect\n" "define6 141 domain dots_ri\n" "define6 142 array ip6address dots_address\n" +"define6 143 array ip6address andsf6\n" #endif "\0"; diff --git a/contrib/dhcpcd/src/dhcpcd-embedded.h b/contrib/dhcpcd/src/dhcpcd-embedded.h index 5bb3a874f4..dc4df3d365 100644 --- a/contrib/dhcpcd/src/dhcpcd-embedded.h +++ b/contrib/dhcpcd/src/dhcpcd-embedded.h @@ -32,7 +32,7 @@ #else #define INITDEFINES 128 #define INITDEFINENDS 7 -#define INITDEFINE6S 72 +#define INITDEFINE6S 74 #endif extern const char dhcpcd_embedded_conf[]; diff --git a/contrib/dhcpcd/src/dhcpcd.8 b/contrib/dhcpcd/src/dhcpcd.8 index 54db4b9f8e..1f4102fefe 100644 --- a/contrib/dhcpcd/src/dhcpcd.8 +++ b/contrib/dhcpcd/src/dhcpcd.8 @@ -452,9 +452,9 @@ variable for use in .Pa /usr/libexec/dhcpcd-run-hooks . .It Fl p , Fl Fl persistent .Nm -normally de-configures the +de-configures the .Ar interface -when it exits. +when it exits unless this option is enabled. Sometimes, this isn't desirable if, for example, you have root mounted over NFS or SSH clients connect to this host and they need to be notified of the host shutting down. diff --git a/contrib/dhcpcd/src/dhcpcd.c b/contrib/dhcpcd/src/dhcpcd.c index e06733d318..5de55fafc6 100644 --- a/contrib/dhcpcd/src/dhcpcd.c +++ b/contrib/dhcpcd/src/dhcpcd.c @@ -75,6 +75,9 @@ static const char dhcpcd_copyright[] = "Copyright (c) 2006-2023 Roy Marples"; #ifdef HAVE_CAPSICUM #include #endif +#ifdef HAVE_OPENSSL +#include +#endif #ifdef HAVE_UTIL_H #include #endif @@ -1411,6 +1414,7 @@ dhcpcd_renew(struct dhcpcd_ctx *ctx) #ifdef USE_SIGNALS #define sigmsg "received %s, %s" +static volatile bool dhcpcd_exiting = false; void dhcpcd_signal_cb(int sig, void *arg) { @@ -1483,9 +1487,20 @@ dhcpcd_signal_cb(int sig, void *arg) return; } + /* + * Privsep has a mini-eloop for reading data from other processes. + * This mini-eloop processes signals as well so we can reap children. + * During teardown we don't want to process SIGTERM or SIGINT again, + * as that could trigger memory issues. + */ + if (dhcpcd_exiting) + return; + + dhcpcd_exiting = true; if (!(ctx->options & DHCPCD_TEST)) stop_all_interfaces(ctx, opts); eloop_exit(ctx->eloop, exit_code); + dhcpcd_exiting = false; } #endif @@ -1495,7 +1510,7 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, { struct interface *ifp; unsigned long long opts; - int opt, oi, do_reboot, do_renew, af = AF_UNSPEC; + int opt, oi, oifind, do_reboot, do_renew, af = AF_UNSPEC; size_t len, l, nifaces; char *tmp, *p; @@ -1511,7 +1526,7 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, return control_queue(fd, UNCONST(fd->ctx->cffile), strlen(fd->ctx->cffile) + 1); } else if (strcmp(*argv, "--getinterfaces") == 0) { - optind = argc = 0; + oifind = argc = 0; goto dumplease; } else if (strcmp(*argv, "--listen") == 0) { fd->flags |= FD_LISTEN; @@ -1574,6 +1589,9 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd, } } + /* store the index; the optind will change when a getopt get called */ + oifind = optind; + if (opts & DHCPCD_DUMPLEASE) { ctx->options |= DHCPCD_DUMPLEASE; dumplease: @@ -1581,11 +1599,11 @@ dumplease: TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (!ifp->active) continue; - for (oi = optind; oi < argc; oi++) { + for (oi = oifind; oi < argc; oi++) { if (strcmp(ifp->name, argv[oi]) == 0) break; } - if (optind == argc || oi < argc) { + if (oifind == argc || oi < argc) { opt = send_interface(NULL, ifp, af); if (opt == -1) goto dumperr; @@ -1597,11 +1615,11 @@ dumplease: TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (!ifp->active) continue; - for (oi = optind; oi < argc; oi++) { + for (oi = oifind; oi < argc; oi++) { if (strcmp(ifp->name, argv[oi]) == 0) break; } - if (optind == argc || oi < argc) { + if (oifind == argc || oi < argc) { if (send_interface(fd, ifp, af) == -1) goto dumperr; } @@ -1620,12 +1638,12 @@ dumperr: } if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) { - if (optind == argc) { + if (oifind == argc) { stop_all_interfaces(ctx, opts); eloop_exit(ctx->eloop, EXIT_SUCCESS); return 0; } - for (oi = optind; oi < argc; oi++) { + for (oi = oifind; oi < argc; oi++) { if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) continue; if (!ifp->active) @@ -1639,11 +1657,11 @@ dumperr: } if (do_renew) { - if (optind == argc) { + if (oifind == argc) { dhcpcd_renew(ctx); return 0; } - for (oi = optind; oi < argc; oi++) { + for (oi = oifind; oi < argc; oi++) { if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL) continue; dhcpcd_ifrenew(ifp); @@ -1653,7 +1671,7 @@ dumperr: reload_config(ctx); /* XXX: Respect initial commandline options? */ - reconf_reboot(ctx, do_reboot, argc, argv, optind - 1); + reconf_reboot(ctx, do_reboot, argc, argv, oifind); return 0; } @@ -1822,7 +1840,7 @@ dhcpcd_stderr_cb(void *arg, unsigned short events) if (!(events & ELE_READ)) return; - len = read(ctx->stderr_fd, log, sizeof(log)); + len = read(ctx->stderr_fd, log, sizeof(log) - 1); if (len == -1) { if (errno != ECONNRESET) logerr(__func__); @@ -2197,6 +2215,11 @@ printpidfile: } #endif +#ifdef HAVE_OPENSSL + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | + OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CONFIG, NULL); +#endif + #ifdef PRIVSEP ps_init(&ctx); #endif diff --git a/contrib/dhcpcd/src/dhcpcd.conf.5 b/contrib/dhcpcd/src/dhcpcd.conf.5 index 4e8e3d2264..2d99fe25f0 100644 --- a/contrib/dhcpcd/src/dhcpcd.conf.5 +++ b/contrib/dhcpcd/src/dhcpcd.conf.5 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 31, 2022 +.Dd October 4, 2023 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -927,6 +927,10 @@ A fixed value (1) to indicate that the option is present, 0 bytes. An RFC 3397 encoded string. .It Ic dname An RFC 1035 validated string. +.It Ic uri +If an array then the first two bytes are the URI length inside the option data. +Otherwise, the whole option data is the URI. +As a space is not allowed in the URI encoding, the URIs are space separated. .It Ic binhex Op : Ic length Binary data expressed as hexadecimal. .It Ic embed diff --git a/contrib/dhcpcd/src/if-options.c b/contrib/dhcpcd/src/if-options.c index bb1c1fca57..9c930f3817 100644 --- a/contrib/dhcpcd/src/if-options.c +++ b/contrib/dhcpcd/src/if-options.c @@ -1833,6 +1833,8 @@ err_sla: t |= OT_ADDRIPV6; else if (strcasecmp(arg, "string") == 0) t |= OT_STRING; + else if (strcasecmp(arg, "uri") == 0) + t |= OT_URI; else if (strcasecmp(arg, "byte") == 0) t |= OT_UINT8; else if (strcasecmp(arg, "bitflags") == 0) diff --git a/contrib/dhcpcd/src/ipv6nd.c b/contrib/dhcpcd/src/ipv6nd.c index 906bb93ee3..9bf7c5dff4 100644 --- a/contrib/dhcpcd/src/ipv6nd.c +++ b/contrib/dhcpcd/src/ipv6nd.c @@ -1238,7 +1238,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, old_lifetime = rap->lifetime; rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime); if (!new_rap && rap->lifetime == 0 && old_lifetime != 0) - logwarnx("%s: %s: no longer a default router", + logwarnx("%s: %s: no longer a default router (lifetime = 0)", ifp->name, rap->sfrom); if (nd_ra->nd_ra_curhoplimit != 0) rap->hoplimit = nd_ra->nd_ra_curhoplimit; diff --git a/contrib/dhcpcd/src/privsep.c b/contrib/dhcpcd/src/privsep.c index b11c0351c2..ecc517ec38 100644 --- a/contrib/dhcpcd/src/privsep.c +++ b/contrib/dhcpcd/src/privsep.c @@ -412,7 +412,6 @@ ps_startprocess(struct ps_process *psp, return pid; } - #ifdef PLUGIN_DEV /* If we are not the root process, stop listening to devices. */ if (ctx->ps_root != psp) @@ -541,11 +540,11 @@ ps_stopprocess(struct ps_process *psp) err = -1; } #endif - psp->psp_fd = -1; } /* Don't wait for the process as it may not respond to the shutdown - * request. We'll reap the process on receipt of SIGCHLD. */ + * request. We'll reap the process on receipt of SIGCHLD where we + * also close the fd. */ return err; } @@ -1200,7 +1199,7 @@ ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid) #endif if (!(ctx->options & DHCPCD_MANAGER)) - strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_name)); + strlcpy(psp->psp_ifname, ctx->ifv[0], sizeof(psp->psp_ifname)); TAILQ_INSERT_TAIL(&ctx->ps_processes, psp, next); return psp; } diff --git a/contrib/dhcpcd/src/privsep.h b/contrib/dhcpcd/src/privsep.h index 34d18dcf7b..00e8fc4f10 100644 --- a/contrib/dhcpcd/src/privsep.h +++ b/contrib/dhcpcd/src/privsep.h @@ -115,7 +115,7 @@ #define PS_ROOT_FD(ctx) ((ctx)->ps_root ? (ctx)->ps_root->psp_fd : -1) -#ifdef __linux__ +#if !defined(DISABLE_SECCOMP) && defined(__linux__) # include # if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) # define HAVE_SECCOMP -- 2.11.4.GIT