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) {

Reply via email to