Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dhcpcd for openSUSE:Factory checked in at 2026-03-17 19:02:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dhcpcd (Old) and /work/SRC/openSUSE:Factory/.dhcpcd.new.8177 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dhcpcd" Tue Mar 17 19:02:48 2026 rev:11 rq:1339332 version:10.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/dhcpcd/dhcpcd.changes 2026-01-21 14:11:24.991981698 +0100 +++ /work/SRC/openSUSE:Factory/.dhcpcd.new.8177/dhcpcd.changes 2026-03-17 19:04:02.643544109 +0100 @@ -1,0 +2,21 @@ +Mon Mar 16 12:13:49 UTC 2026 - Jorik Cronenberg <[email protected]> + +- Update to 10.3.1 + * BSD: don't send uninitialised memory using + ps_root_indirectioctl + * Fix fallback_time option + * IPv4: Ignore DHCP state when building routes + * options: Ensure ldop is not NULL dereferenced + * route: Routes may not have an interface assinged + * options: Ensure that an overly long bitflag string does not + crash + * options: Don't assume vsio options have an argument + * common: Cast via uintptr_t rather than unsigned long in UNCONST + * privsep: Ensure we recv for real after a successful recv + MSG_PEEK + * DHCP: Add parentheses to macro definitions + * ipv6nd: empty IPV6RA_EXPIRE eloop queue when dropping + +- Add ghost entry for /var/lib/dhcpcd + +------------------------------------------------------------------- Old: ---- dhcpcd-10.3.0.tar.xz dhcpcd-10.3.0.tar.xz.asc New: ---- dhcpcd-10.3.1.tar.xz dhcpcd-10.3.1.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dhcpcd.spec ++++++ --- /var/tmp/diff_new_pack.UvOwhN/_old 2026-03-17 19:04:05.047643739 +0100 +++ /var/tmp/diff_new_pack.UvOwhN/_new 2026-03-17 19:04:05.067644568 +0100 @@ -17,7 +17,7 @@ Name: dhcpcd -Version: 10.3.0 +Version: 10.3.1 Release: 0 Summary: Minimal DHCPv4 and DHCPv6 client License: BSD-2-Clause @@ -94,4 +94,5 @@ %{_unitdir}/[email protected] %{_sysusersdir}/dhcpcd.conf %{_tmpfilesdir}/dhcpcd.conf +%ghost %{_sharedstatedir}/dhcpcd ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.UvOwhN/_old 2026-03-17 19:04:05.359656669 +0100 +++ /var/tmp/diff_new_pack.UvOwhN/_new 2026-03-17 19:04:05.387657830 +0100 @@ -1,6 +1,6 @@ -mtime: 1768841165 -commit: 23b08435fa2b08c6235b05d2523aa0ca9c63eef045b7e19366a9d0ef45211eef +mtime: 1773663651 +commit: 7bc5ba4bd320326c1624b29d7ec1cffcfb3ed6818fab0238d1d01d655250f81a url: https://src.opensuse.org/dhcp/dhcpcd.git -revision: 23b08435fa2b08c6235b05d2523aa0ca9c63eef045b7e19366a9d0ef45211eef +revision: 7bc5ba4bd320326c1624b29d7ec1cffcfb3ed6818fab0238d1d01d655250f81a projectscmsync: https://src.opensuse.org/dhcp/_ObsPrj.git ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-03-16 13:21:22.000000000 +0100 @@ -0,0 +1 @@ +.osc ++++++ dhcpcd-10.3.0.tar.xz -> dhcpcd-10.3.1.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/hooks/50-ntp.conf new/dhcpcd-10.3.1/hooks/50-ntp.conf --- old/dhcpcd-10.3.0/hooks/50-ntp.conf 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/hooks/50-ntp.conf 2026-03-16 13:03:38.000000000 +0100 @@ -131,7 +131,9 @@ # For ease of use, map DHCP6 names onto our DHCP4 names case "$reason" in BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6) - new_ntp_servers="$new_dhcp6_sntp_servers $new_dhcp6_ntp_server_addr $new_dhcp6_ntp_server_fqdn" + new_ntp_servers="$new_dhcp6_sntp_servers" + new_ntp_servers="$new_ntp_servers${new_ntp_servers:+ }$new_dhcp6_ntp_server_addr" + new_ntp_servers="$new_ntp_servers${new_ntp_servers:+ }$new_dhcp6_ntp_server_fqdn" ;; esac diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/hooks/50-timesyncd.conf new/dhcpcd-10.3.1/hooks/50-timesyncd.conf --- old/dhcpcd-10.3.0/hooks/50-timesyncd.conf 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/hooks/50-timesyncd.conf 2026-03-16 13:03:38.000000000 +0100 @@ -54,7 +54,9 @@ # For ease of use, map DHCP6 names onto our DHCP4 names case "$reason" in BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6) - new_ntp_servers="$new_dhcp6_sntp_servers $new_dhcp6_ntp_server_addr $new_dhcp6_ntp_server_fqdn" + new_ntp_servers="$new_dhcp6_sntp_servers" + new_ntp_servers="$new_ntp_servers${new_ntp_servers:+ }$new_dhcp6_ntp_server_addr" + new_ntp_servers="$new_ntp_servers${new_ntp_servers:+ }$new_dhcp6_ntp_server_fqdn" ;; esac diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/common.h new/dhcpcd-10.3.1/src/common.h --- old/dhcpcd-10.3.0/src/common.h 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/common.h 2026-03-16 13:03:38.000000000 +0100 @@ -55,7 +55,7 @@ #define MAX(a,b) ((/*CONSTCOND*/(a)>(b))?(a):(b)) #endif -#define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) #define STRINGIFY(a) #a #define TOSTRING(a) STRINGIFY(a) #define UNUSED(a) (void)(a) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/defs.h new/dhcpcd-10.3.1/src/defs.h --- old/dhcpcd-10.3.0/src/defs.h 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/defs.h 2026-03-16 13:03:38.000000000 +0100 @@ -29,7 +29,7 @@ #define DEFS_H #define PACKAGE "dhcpcd" -#define VERSION "10.3.0" +#define VERSION "10.3.1" #ifndef PRIVSEP_USER # define PRIVSEP_USER "_" PACKAGE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/dhcp.c new/dhcpcd-10.3.1/src/dhcp.c --- old/dhcpcd-10.3.0/src/dhcp.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/dhcp.c 2026-03-16 13:03:38.000000000 +0100 @@ -98,8 +98,8 @@ __CTASSERT(sizeof(struct ip) == 20); __CTASSERT(sizeof(struct udphdr) == 8); __CTASSERT(sizeof(struct bootp) == 300); -#define IP_UDP_SIZE sizeof(struct ip) + sizeof(struct udphdr) -#define BOOTP_MIN_MTU IP_UDP_SIZE + sizeof(struct bootp) +#define IP_UDP_SIZE (sizeof(struct ip) + sizeof(struct udphdr)) +#define BOOTP_MIN_MTU (IP_UDP_SIZE + sizeof(struct bootp)) struct dhcp_op { uint8_t value; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/dhcp6.c new/dhcpcd-10.3.1/src/dhcp6.c --- old/dhcpcd-10.3.0/src/dhcp6.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/dhcp6.c 2026-03-16 13:03:38.000000000 +0100 @@ -1818,8 +1818,9 @@ * merely one facet of the lease as a whole. * This poor wording might explain the lack of similar text for INFORM * in 18.1.5 because there are no addresses in the INFORM message. */ - eloop_timeout_add_sec(ifp->ctx->eloop, - INF_MAX_RD, dhcp6_failinform, ifp); + if (!state->failed) + eloop_timeout_add_sec(ifp->ctx->eloop, + INF_MAX_RD, dhcp6_failinform, ifp); } static bool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/dhcpcd.c new/dhcpcd-10.3.1/src/dhcpcd.c --- old/dhcpcd-10.3.0/src/dhcpcd.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/dhcpcd.c 2026-03-16 13:03:38.000000000 +0100 @@ -729,7 +729,10 @@ dhcpcd_initstate(struct interface *ifp, unsigned long long options) { - dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options); + dhcpcd_initstate1(ifp, + ifp->argv ? ifp->argc : ifp->ctx->argc, + ifp->argv ? ifp->argv : ifp->ctx->argv, + options); } static void @@ -1399,28 +1402,48 @@ } static void -reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi) +reconf_reboot(struct dhcpcd_ctx *ctx, const bool reboot, + const int argc, char **argv, const int oi) { int i; struct interface *ifp; + bool all_interfaces = argc == oi, iface_found; TAILQ_FOREACH(ifp, ctx->ifaces, next) { for (i = oi; i < argc; i++) { if (strcmp(ifp->name, argv[i]) == 0) break; } - if (oi != argc && i == argc) + + iface_found = i != argc; + if (!all_interfaces && !iface_found) continue; + if (ifp->active == IF_ACTIVE_USER) { - if (action) + if (reboot) if_reboot(ifp, argc, argv); #ifdef INET else ipv4_applyaddr(ifp); #endif - } else if (i != argc) { + } else if (iface_found) { ifp->active = IF_ACTIVE_USER; dhcpcd_initstate1(ifp, argc, argv, 0); + + free(ifp->argv); + if (argc > 0) { + ifp->argv = alloc_args(argc, argv); + if (ifp->argv == NULL) { + logerr("alloc_args"); + goto alloc_args_err; + } + ifp->argc = argc; + } else { +alloc_args_err: + ifp->argv = NULL; + ifp->argc = 0; + } + run_preinit(ifp); dhcpcd_prestartinterface(ifp); } @@ -1529,7 +1552,7 @@ reload_config(ctx); /* Preserve any options passed on the commandline * when we were started. */ - reconf_reboot(ctx, 1, ctx->argc, ctx->argv, + reconf_reboot(ctx, true, ctx->argc, ctx->argv, ctx->argc - ctx->ifc); return; case SIGUSR1: @@ -1590,7 +1613,8 @@ struct interface *ifp; struct if_options *ifo; unsigned long long opts, orig_opts; - int opt, oi, oifind, do_reboot, do_renew, af = AF_UNSPEC; + int opt, oi, oifind, af = AF_UNSPEC; + bool do_reboot, do_renew; size_t len, l, nifaces; char *tmp, *p; @@ -1635,7 +1659,7 @@ optind = 0; oi = 0; opts = 0; - do_reboot = do_renew = 0; + do_reboot = do_renew = false; while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1) { switch (opt) { @@ -1646,7 +1670,7 @@ opts |= DHCPCD_RELEASE; break; case 'n': - do_reboot = 1; + do_reboot = true; break; case 'p': opts |= DHCPCD_PERSISTENT; @@ -1655,7 +1679,7 @@ opts |= DHCPCD_EXITING; break; case 'N': - do_renew = 1; + do_renew = true; break; case 'U': opts |= DHCPCD_DUMPLEASE; @@ -1773,7 +1797,6 @@ } reload_config(ctx); - /* XXX: Respect initial commandline options? */ reconf_reboot(ctx, do_reboot, argc, argv, oifind); return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/dhcpcd.h new/dhcpcd-10.3.1/src/dhcpcd.h --- old/dhcpcd-10.3.0/src/dhcpcd.h 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/dhcpcd.h 2026-03-16 13:03:38.000000000 +0100 @@ -85,6 +85,9 @@ uint8_t ssid[IF_SSIDLEN]; unsigned int ssid_len; + int argc; + char **argv; + char profile[PROFILE_LEN]; struct if_options *options; void *if_data[IF_DATA_MAX]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/if-options.c new/dhcpcd-10.3.1/src/if-options.c --- old/dhcpcd-10.3.0/src/if-options.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/if-options.c 2026-03-16 13:03:38.000000000 +0100 @@ -44,6 +44,7 @@ #include <string.h> #include <unistd.h> #include <time.h> +#include <assert.h> #include "config.h" #include "common.h" @@ -936,7 +937,7 @@ return -1; #else fp = strwhite(arg); - if (fp) + if (fp != NULL) *fp++ = '\0'; u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); if (e) { @@ -944,9 +945,13 @@ return -1; } - fp = strskipwhite(fp); - p = strchr(fp, ','); - if (!p || !p[1]) { + if (fp != NULL) + fp = strskipwhite(fp); + if (fp != NULL) + p = strchr(fp, ','); + else + p = NULL; + if (p == NULL || p[1] == '\0') { logerrx("invalid vendor format: %s", arg); return -1; } @@ -1882,7 +1887,7 @@ if (*edop) { dop = &(*edop)->embopts; dop_len = &(*edop)->embopts_len; - } else if (ldop) { + } else if (*ldop) { dop = &(*ldop)->embopts; dop_len = &(*ldop)->embopts_len; } else { @@ -2130,6 +2135,10 @@ ndop->var = np; if (bp) { dl = strlen(bp); + if (dl > sizeof(ndop->bitflags)) { + logwarnx("bitflag string too long %s", bp); + dl = sizeof(ndop->bitflags); + } memcpy(ndop->bitflags, bp, dl); memset(ndop->bitflags + dl, 0, sizeof(ndop->bitflags) - dl); @@ -2546,7 +2555,7 @@ #ifdef INET case O_FALLBACK_TIME: ARG_REQUIRED; - ifo->request_time = + ifo->fallback_time = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e); if (e) { logerrx("invalid fallback time: %s", arg); @@ -2986,6 +2995,48 @@ return r; } +char +**alloc_args(int argc, char **argv) +{ + int i; + size_t strslen = 0, len; + size_t nptrs = (size_t)argc; + size_t ptrslen = nptrs * sizeof(char *); + void *buf; + char **ptrs, *strsp; + + for (i = 0; i < argc; i++) { + strslen += strlen(argv[i]) + 1; + } + if (strslen == 0) + return NULL; + + buf = malloc(ptrslen + strslen); + if (!buf) + return NULL; + + ptrs = buf; + strsp = (char *)&ptrs[nptrs]; + + for (i = 0; i < argc; i++) { + len = strlcpy(strsp, argv[i], strslen); + if (len >= strslen) /* truncated */ + goto err; + + ptrs[i] = strsp; + strsp += len + 1; + assert(strslen >= len + 1); + strslen -= len + 1; + } + + assert(strslen == 0); + return ptrs; + +err: + free(buf); + return NULL; +} + void free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/if-options.h new/dhcpcd-10.3.1/src/if-options.h --- old/dhcpcd-10.3.0/src/if-options.h 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/if-options.h 2026-03-16 13:03:38.000000000 +0100 @@ -322,4 +322,6 @@ void free_dhcp_opt_embenc(struct dhcp_opt *); void free_options(struct dhcpcd_ctx *, struct if_options *); +char **alloc_args(int argc, char **argv); + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/if.c new/dhcpcd-10.3.1/src/if.c --- old/dhcpcd-10.3.0/src/if.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/if.c 2026-03-16 13:03:38.000000000 +0100 @@ -100,6 +100,7 @@ #endif rt_freeif(ifp); free_options(ifp->ctx, ifp->options); + free(ifp->argv); free(ifp); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/ipv4.c new/dhcpcd-10.3.1/src/ipv4.c --- old/dhcpcd-10.3.0/src/ipv4.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/ipv4.c 2026-03-16 13:03:38.000000000 +0100 @@ -291,7 +291,7 @@ int n; state = D_CSTATE(ifp); - if (state == NULL || state->state != DHS_BOUND || !state->added) + if (state == NULL || !(state->added & STATE_ADDED)) return 0; /* An address does have to exist. */ @@ -359,6 +359,8 @@ rt->rt_mtu = mtu; if (!(rt->rt_dflags & RTDF_STATIC)) rt->rt_dflags |= RTDF_DHCP; + if (state->added & STATE_FAKE) + rt->rt_dflags |= RTDF_FAKE; sa_in_init(&rt->rt_ifa, &state->addr->addr); if (rb_tree_insert_node(routes, rt) != rt) { rt_free(rt); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/ipv6nd.c new/dhcpcd-10.3.1/src/ipv6nd.c --- old/dhcpcd-10.3.0/src/ipv6nd.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/ipv6nd.c 2026-03-16 13:03:38.000000000 +0100 @@ -681,11 +681,14 @@ static void ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra) { + struct dhcpcd_ctx *ctx = rap->iface->ctx; - eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface); - eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap); + eloop_q_timeout_delete(ctx->eloop, ELOOP_IPV6RA_EXPIRE, NULL, + rap->iface); + eloop_timeout_delete(ctx->eloop, NULL, rap->iface); + eloop_timeout_delete(ctx->eloop, NULL, rap); if (remove_ra) - TAILQ_REMOVE(rap->iface->ctx->ra_routers, rap, next); + TAILQ_REMOVE(ctx->ra_routers, rap, next); ipv6_freedrop_addrs(&rap->addrs, drop_ra, 0, NULL); routeinfohead_free(&rap->rinfos); free(rap->data); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/privsep-bsd.c new/dhcpcd-10.3.1/src/privsep-bsd.c --- old/dhcpcd-10.3.0/src/privsep-bsd.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/privsep-bsd.c 2026-03-16 13:03:38.000000000 +0100 @@ -149,18 +149,30 @@ { char *p = data; struct ifreq ifr = { .ifr_flags = 0 }; + size_t ifnamelen; /* ioctl filtering is done in ps_root_doioctldom */ - if (len < IFNAMSIZ + 1) { + if (len < sizeof(ifnamelen)) { errno = EINVAL; return -1; } + memcpy(&ifnamelen, p, sizeof(ifnamelen)); + len -= sizeof(ifnamelen); - strlcpy(ifr.ifr_name, p, IFNAMSIZ); - len -= IFNAMSIZ; - memmove(data, p + IFNAMSIZ, len); - ifr.ifr_data = data; + if (len < ifnamelen || ifnamelen > sizeof(ifr.ifr_name)) { + errno = EINVAL; + return -1; + } + + memcpy(ifr.ifr_name, p, ifnamelen); + len -= ifnamelen; + + if (len != 0) { + /* Ensure data is now aligned */ + memmove(data, p + ifnamelen, len); + ifr.ifr_data = data; + } return ps_root_doioctldom(ctx, PF_INET, req, &ifr, sizeof(ifr)); } @@ -337,17 +349,29 @@ ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request, const char *ifname, void *data, size_t len) { - char buf[PS_BUFLEN]; + size_t ifnamelen = strlen(ifname + 1); - if (IFNAMSIZ + len > sizeof(buf)) { - errno = ENOBUFS; - return -1; - } + struct iovec iov[] = { + { + .iov_base = &ifnamelen, + .iov_len = sizeof(ifnamelen), + }, + { + .iov_base = UNCONST(ifname), + .iov_len = ifnamelen, + }, + { + .iov_base = data, + .iov_len = len, + } + }; + struct msghdr msg = { + .msg_iov = iov, + .msg_iovlen = __arraycount(iov), + }; - strlcpy(buf, ifname, IFNAMSIZ); - memcpy(buf + IFNAMSIZ, data, len); - if (ps_sendcmd(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT, - request, buf, IFNAMSIZ + len) == -1) + if (ps_sendcmdmsg(ctx, PS_ROOT_FD(ctx), PS_IOCTLINDIRECT, + request, &msg) == -1) return -1; return ps_root_readerror(ctx, data, len); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/privsep-root.c new/dhcpcd-10.3.1/src/privsep-root.c --- old/dhcpcd-10.3.0/src/privsep-root.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/privsep-root.c 2026-03-16 13:03:38.000000000 +0100 @@ -71,108 +71,119 @@ struct psr_error psr_error; size_t psr_datalen; void *psr_data; - size_t psr_mdatalen; - void *psr_mdata; - bool psr_usemdata; + bool psr_mallocdata; }; static ssize_t -ps_root_readerrorcb(struct psr_ctx *psr_ctx) +ps_root_readerrorcb(struct psr_ctx *pc) { - struct dhcpcd_ctx *ctx = psr_ctx->psr_ctx; + struct dhcpcd_ctx *ctx = pc->psr_ctx; int fd = PS_ROOT_FD(ctx); - struct psr_error *psr_error = &psr_ctx->psr_error; + struct psr_error *psr_error = &pc->psr_error; struct iovec iov[] = { { .iov_base = psr_error, .iov_len = sizeof(*psr_error) }, - { .iov_base = NULL, .iov_len = 0 }, + { .iov_base = pc->psr_data, .iov_len = pc->psr_datalen }, }; + struct msghdr msg = { .msg_iov = iov, .msg_iovlen = __arraycount(iov) }; ssize_t len; #define PSR_ERROR(e) \ do { \ - psr_error->psr_result = -1; \ psr_error->psr_errno = (e); \ - return -1; \ + goto error; \ } while (0 /* CONSTCOND */) if (eloop_waitfd(fd) == -1) PSR_ERROR(errno); - len = recv(fd, psr_error, sizeof(*psr_error), MSG_PEEK); + if (!pc->psr_mallocdata) + goto recv; + + /* We peek at the psr_error structure to tell us how much of a buffer + * we need to read the whole packet. */ + msg.msg_iovlen--; + len = recvmsg(fd, &msg, MSG_PEEK | MSG_WAITALL); if (len == -1) PSR_ERROR(errno); - else if ((size_t)len < sizeof(*psr_error)) + + /* After this point, we MUST do another recvmsg even on a failure + * to remove the message after peeking. */ + if ((size_t)len < sizeof(*psr_error)) { + /* We can't use the header to work out buffers, so + * remove the message and bail. */ + (void)recvmsg(fd, &msg, MSG_WAITALL); PSR_ERROR(EINVAL); + } - if (psr_error->psr_datalen > SSIZE_MAX) - PSR_ERROR(ENOBUFS); - if (psr_ctx->psr_usemdata && - psr_error->psr_datalen > psr_ctx->psr_mdatalen) - { - void *d = realloc(psr_ctx->psr_mdata, psr_error->psr_datalen); - if (d == NULL) - PSR_ERROR(errno); - psr_ctx->psr_mdata = d; - psr_ctx->psr_mdatalen = psr_error->psr_datalen; - } - if (psr_error->psr_datalen != 0) { - if (psr_ctx->psr_usemdata) - iov[1].iov_base = psr_ctx->psr_mdata; - else { - if (psr_error->psr_datalen > psr_ctx->psr_datalen) - PSR_ERROR(ENOBUFS); - iov[1].iov_base = psr_ctx->psr_data; - } + /* No data to read? Unlikely but ... */ + if (psr_error->psr_datalen == 0) + goto recv; + + pc->psr_data = malloc(psr_error->psr_datalen); + if (pc->psr_data != NULL) { + iov[1].iov_base = pc->psr_data; iov[1].iov_len = psr_error->psr_datalen; + msg.msg_iovlen++; } - len = readv(fd, iov, __arraycount(iov)); +recv: + len = recvmsg(fd, &msg, MSG_WAITALL); if (len == -1) PSR_ERROR(errno); - else if ((size_t)len != sizeof(*psr_error) + psr_error->psr_datalen) + else if ((size_t)len < sizeof(*psr_error)) PSR_ERROR(EINVAL); + else if (msg.msg_flags & MSG_TRUNC) + PSR_ERROR(ENOBUFS); + else if ((size_t)len != sizeof(*psr_error) + psr_error->psr_datalen) { +#ifdef PRIVSEP_DEBUG + logerrx("%s: recvmsg returned %zd, expecting %zu", __func__, + len, sizeof(*psr_error) + psr_error->psr_datalen); +#endif + PSR_ERROR(EBADMSG); + } return len; + +error: + psr_error->psr_result = -1; + if (pc->psr_mallocdata && pc->psr_data != NULL) { + free(pc->psr_data); + pc->psr_data = NULL; + } + return -1; } ssize_t ps_root_readerror(struct dhcpcd_ctx *ctx, void *data, size_t len) { - struct psr_ctx *pc = ctx->ps_root->psp_data; + struct psr_ctx pc = { + .psr_ctx = ctx, + .psr_data = data, + .psr_datalen = len, + .psr_mallocdata = false + }; - pc->psr_data = data; - pc->psr_datalen = len; - pc->psr_usemdata = false; - ps_root_readerrorcb(pc); + ps_root_readerrorcb(&pc); - errno = pc->psr_error.psr_errno; - return pc->psr_error.psr_result; + errno = pc.psr_error.psr_errno; + return pc.psr_error.psr_result; } ssize_t ps_root_mreaderror(struct dhcpcd_ctx *ctx, void **data, size_t *len) { - struct psr_ctx *pc = ctx->ps_root->psp_data; - void *d; + struct psr_ctx pc = { + .psr_ctx = ctx, + .psr_data = NULL, + .psr_datalen = 0, + .psr_mallocdata = true + }; - pc->psr_usemdata = true; - ps_root_readerrorcb(pc); + ps_root_readerrorcb(&pc); - if (pc->psr_error.psr_datalen != 0) { - if (pc->psr_error.psr_datalen > pc->psr_mdatalen) { - errno = EINVAL; - return -1; - } - d = malloc(pc->psr_error.psr_datalen); - if (d == NULL) - return -1; - memcpy(d, pc->psr_mdata, pc->psr_error.psr_datalen); - } else - d = NULL; - - errno = pc->psr_error.psr_errno; - *data = d; - *len = pc->psr_error.psr_datalen; - return pc->psr_error.psr_result; + errno = pc.psr_error.psr_errno; + *data = pc.psr_data; + *len = pc.psr_error.psr_datalen; + return pc.psr_error.psr_result; } static ssize_t @@ -196,6 +207,8 @@ logdebugx("%s: result %zd errno %d", __func__, result, errno); #endif + if (len == 0) + msg.msg_iovlen = 1; err = sendmsg(fd, &msg, MSG_EOR); /* Error sending the message? Try sending the error of sending. */ @@ -204,8 +217,8 @@ __func__, result, data, len); psr.psr_result = err; psr.psr_errno = errno; - iov[1].iov_base = NULL; - iov[1].iov_len = 0; + psr.psr_datalen = 0; + msg.msg_iovlen = 1; err = sendmsg(fd, &msg, MSG_EOR); } @@ -602,7 +615,7 @@ break; } - err = ps_root_writeerror(ctx, err, rlen != 0 ? rdata : 0, rlen); + err = ps_root_writeerror(ctx, err, rdata, rlen); if (free_rdata) free(rdata); return err; @@ -843,17 +856,6 @@ logerr(__func__); } -static void -ps_root_freepsdata(void *arg) -{ - struct psr_ctx *pc = arg; - - if (pc == NULL) - return; - free(pc->psr_mdata); - free(pc); -} - pid_t ps_root_start(struct dhcpcd_ctx *ctx) { @@ -864,7 +866,6 @@ struct ps_process *psp; int logfd[2] = { -1, -1}, datafd[2] = { -1, -1}; pid_t pid; - struct psr_ctx *pc; if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, logfd) == -1) return -1; @@ -883,27 +884,15 @@ return -1; #endif - pc = calloc(1, sizeof(*pc)); - if (pc == NULL) - return -1; - pc->psr_ctx = ctx; - psp = ctx->ps_root = ps_newprocess(ctx, &id); if (psp == NULL) - { - free(pc); return -1; - } - psp->psp_freedata = ps_root_freepsdata; + strlcpy(psp->psp_name, "privileged proxy", sizeof(psp->psp_name)); pid = ps_startprocess(psp, ps_root_recvmsg, NULL, ps_root_startcb, PSF_ELOOP); - if (pid == -1) { - free(pc); + if (pid == -1) return -1; - } - - psp->psp_data = pc; if (pid == 0) { ctx->ps_log_fd = logfd[0]; /* Keep open to pass to processes */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/privsep.c new/dhcpcd-10.3.1/src/privsep.c --- old/dhcpcd-10.3.0/src/privsep.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/privsep.c 2026-03-16 13:03:38.000000000 +0100 @@ -761,11 +761,6 @@ TAILQ_REMOVE(&ctx->ps_processes, psp, next); - if (psp->psp_freedata != NULL) - psp->psp_freedata(psp->psp_data); - else - free(psp->psp_data); - if (psp->psp_fd != -1) { eloop_event_delete(ctx->eloop, psp->psp_fd); close(psp->psp_fd); @@ -919,7 +914,7 @@ len = sendmsg(fd, &m, MSG_EOR); - if (len == -1) { + if (len == -1 && ctx != NULL) { if (ctx->options & DHCPCD_FORKED && !(ctx->options & DHCPCD_PRIVSEPROOT)) eloop_exit(ctx->eloop, EXIT_FAILURE); @@ -1003,57 +998,13 @@ return ps_sendpsmmsg(ctx, fd, &psm, &msg); } -static ssize_t -ps_sendcmdmsg(int fd, uint16_t cmd, const struct msghdr *msg) +ssize_t +ps_sendcmdmsg(struct dhcpcd_ctx *ctx, int fd, uint16_t cmd, + unsigned long flags, const struct msghdr *msg) { - struct ps_msghdr psm = { .ps_cmd = cmd }; - uint8_t data[PS_BUFLEN], *p = data; - struct iovec iov[] = { - { .iov_base = &psm, .iov_len = sizeof(psm) }, - { .iov_base = data, .iov_len = 0 }, - }; - struct msghdr m = { .msg_iov = iov, .msg_iovlen = __arraycount(iov) }; - size_t dl = sizeof(data); - socklen_t cmsg_padlen = - CALC_CMSG_PADLEN(msg->msg_controllen, msg->msg_namelen); + struct ps_msghdr psm = { .ps_cmd = cmd, .ps_flags = flags }; - if (msg->msg_namelen != 0) { - if (msg->msg_namelen > dl) - goto nobufs; - psm.ps_namelen = msg->msg_namelen; - memcpy(p, msg->msg_name, msg->msg_namelen); - p += msg->msg_namelen; - dl -= msg->msg_namelen; - } - - if (msg->msg_controllen != 0) { - if (msg->msg_controllen + cmsg_padlen > dl) - goto nobufs; - if (cmsg_padlen != 0) { - memset(p, 0, cmsg_padlen); - p += cmsg_padlen; - dl -= cmsg_padlen; - } - psm.ps_controllen = (socklen_t)msg->msg_controllen; - memcpy(p, msg->msg_control, msg->msg_controllen); - p += msg->msg_controllen; - dl -= msg->msg_controllen; - } - - psm.ps_datalen = msg->msg_iov[0].iov_len; - if (psm.ps_datalen > dl) - goto nobufs; - - iov[1].iov_len = - psm.ps_namelen + psm.ps_controllen + psm.ps_datalen + cmsg_padlen; - if (psm.ps_datalen != 0) - memcpy(p, msg->msg_iov[0].iov_base, psm.ps_datalen); - - return sendmsg(fd, &m, MSG_EOR); - -nobufs: - errno = ENOBUFS; - return -1; + return ps_sendpsmmsg(ctx, fd, &psm, msg); } ssize_t @@ -1082,7 +1033,7 @@ } iov[0].iov_len = (size_t)len; - len = ps_sendcmdmsg(wfd, cmd, &msg); + len = ps_sendcmdmsg(NULL, wfd, cmd, 0, &msg); if (len == -1) logerr("%s: ps_sendcmdmsg", __func__); return len; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/privsep.h new/dhcpcd-10.3.1/src/privsep.h --- old/dhcpcd-10.3.0/src/privsep.h 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/privsep.h 2026-03-16 13:03:38.000000000 +0100 @@ -184,8 +184,6 @@ char psp_name[PSP_NAMESIZE]; uint16_t psp_proto; const char *psp_protostr; - void *psp_data; - void (*psp_freedata)(void *); bool psp_started; #ifdef INET @@ -224,6 +222,8 @@ const struct msghdr *); ssize_t ps_sendcmd(struct dhcpcd_ctx *, int, uint16_t, unsigned long, const void *data, size_t len); +ssize_t ps_sendcmdmsg(struct dhcpcd_ctx *, int fd, uint16_t cmd, + unsigned long flags, const struct msghdr *msg); ssize_t ps_recvmsg(int, unsigned short, uint16_t, int); ssize_t ps_recvpsmsg(struct dhcpcd_ctx *, int, unsigned short, ssize_t (*callback)(void *, struct ps_msghdr *, struct msghdr *), void *); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dhcpcd-10.3.0/src/route.c new/dhcpcd-10.3.1/src/route.c --- old/dhcpcd-10.3.0/src/route.c 2025-11-14 16:38:04.000000000 +0100 +++ new/dhcpcd-10.3.1/src/route.c 2026-03-16 13:03:38.000000000 +0100 @@ -313,9 +313,9 @@ if (rts == NULL) return; - assert(ctx != NULL); #ifdef RT_FREE_ROUTE_TABLE - assert(&ctx->froutes != rts); + if (ctx != NULL) + assert(&ctx->froutes != rts); #endif RB_TREE_FOREACH_SAFE(rt, rts, rtn) { @@ -335,7 +335,7 @@ if (rts == NULL || (rt = RB_TREE_MIN(rts)) == NULL) return; - rt_headclear0(rt->rt_ifp->ctx, rts, af); + rt_headclear0(rt->rt_ifp ? rt->rt_ifp->ctx : NULL, rts, af); } static void @@ -566,7 +566,7 @@ struct dhcpcd_ctx *ctx; struct rt *krt; int loglevel = LOG_INFO; - bool change, result; + bool change, result = false; assert(nrt != NULL); ctx = nrt->rt_ifp->ctx; @@ -686,7 +686,6 @@ logerr: #endif logerr("if_route (ADD)"); - result = false; out: if (krt != NULL) {
