Fixed upstream 1 Oct 2026  Upstream bug fix in dnsmasq

dnsmasq: stale SLAAC name records after a DHCP lease loses its hostname

Our scanner flagged that dnsmasq, the DNS and DHCP server built into many routers and Linux systems, could pass a NULL hostname to a %s log format in its SLAAC code. We sent a small patch to the dnsmasq-discuss mailing list. Author and maintainer Simon Kelley traced it to the underlying cause, SLAAC name records left on a lease that had lost its hostname, and fixed that the next day. His commit message credits Martin Vlach with finding a symptom of it in the SLAAC logging code. A second patch from the same scan, for an allocation-failure bug in poll_listen(), was applied as well.

What was wrong

For DHCPv4 clients on interfaces with router-advertisement naming, dnsmasq derives SLAAC IPv6 addresses from the client’s MAC address and maps them to the lease’s hostname. slaac_add_addrs() creates these records only when the lease has a hostname, and otherwise returned early without touching existing records.

A lease can lose its hostname later, for example when another client claims the same name and kill_name() clears it. Its SLAAC records stayed behind. When an ICMPv6 echo reply for one of those addresses arrived, slaac_ping_reply() logged it with lease->hostname, by then NULL, as a %s argument. That is undefined behaviour in C. glibc and musl print (null), so the visible symptom is cosmetic there, but the name-to-address data derived from the old hostname was no longer valid either way.

How it was fixed

Our patch only guarded the log line, printing * for a missing name as lease.c already does. Simon Kelley fixed the cause instead: kill_name() now removes the lease’s SLAAC records, lease_set_hostname() regenerates them when a name is added, and slaac_add_addrs() always drops the old records before deciding whether to create new ones.

   lease->hostname = lease->fqdn = NULL;
+
+#ifdef HAVE_DHCP6
+  /* A lease which had a hostname when slaac_add_addrs() was called on it
+     may have slaac-address records. Since it no longer has a hostname,
+     they are no-longer valid, so update to remove them */
+  slaac_add_addrs(lease, 0, 0);
+#endif
 }

A second patch from the same scan

The same run flagged poll_listen() in src/poll.c. When the pollfds array has to grow, the old code doubled arrsize before calling whine_realloc(). If that allocation failed, arrsize stayed doubled while the array kept its old size. The next call skipped the extension and wrote past the end of the array, or through NULL if the very first allocation had failed, and the state stayed broken until dnsmasq restarted. It only matters once memory allocation fails, so it is a robustness fix, not something an attacker can trigger directly. Our three-line patch updates arrsize only after the reallocation succeeds. Simon Kelley committed it on 1 Oct as baeb743 and replied “Patch applied.” on the list on 11 Oct.

Timeline

How to read this

The scanner found a symptom; the maintainer found the cause. Our patch would have quieted one log line, while the upstream fix removes the stale records that made it possible. A narrow patch is a starting point for the maintainer, not the final word. Findings are leads for people, not verdicts.

Sources

← Back to Success Stories