Opraveno v upstreamu 1. 10. 2026  Oprava chyby v dnsmasq v upstreamu

dnsmasq: zastaralé záznamy SLAAC po ztrátě jména DHCP lease

Náš skener upozornil, že dnsmasq, DNS a DHCP server vestavěný do mnoha routerů a linuxových systémů, mohl v kódu SLAAC předat NULL hostname do formátu %s při logování. Do konference dnsmasq-discuss jsme poslali malý patch. Autor a správce Simon Kelley dohledal skutečnou příčinu, záznamy SLAAC ponechané na lease, který přišel o hostname, a druhý den ji opravil. V commit message uvádí, že symptom v logování SLAAC našel Martin Vlach. Přijal i druhý patch ze stejného skenu, opravu chyby při selhání alokace v poll_listen().

Co bylo špatně

U klientů DHCPv4 na rozhraních s pojmenováním přes router advertisement odvozuje dnsmasq z MAC adresy klienta adresy SLAAC pro IPv6 a mapuje je na hostname daného lease. slaac_add_addrs() tyto záznamy vytváří, jen když lease hostname má, a jinak skončila dřív, aniž by na existující záznamy sáhla.

Lease může o hostname přijít později, třeba když si stejné jméno vezme jiný klient a kill_name() ho smaže. Jeho záznamy SLAAC ale zůstaly. Když pak přišla ICMPv6 echo odpověď pro některou z těchto adres, slaac_ping_reply() ji zalogovala s lease->hostname, v té době už NULL, jako argumentem %s. V C je to nedefinované chování. glibc i musl vypíšou (null), takže viditelný projev je tam jen kosmetický, ale mapování jména na adresy odvozené ze starého hostname už každopádně neplatilo.

Jak to bylo opraveno

Náš patch jen ošetřil řádek logu a pro chybějící jméno vypsal *, jak už to dělá lease.c. Simon Kelley místo toho opravil příčinu: kill_name() teď záznamy SLAAC daného lease odstraní, lease_set_hostname() je při přidání jména vytvoří znovu a slaac_add_addrs() staré záznamy vždy zahodí dřív, než rozhodne, zda vytvořit nové.

   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
 }

Druhý patch ze stejného skenu

Stejný běh upozornil na poll_listen() v src/poll.c. Když bylo potřeba zvětšit pole pollfds, starý kód zdvojnásobil arrsize ještě před voláním whine_realloc(). Pokud alokace selhala, arrsize zůstal zdvojený, zatímco pole mělo starou velikost. Další volání rozšíření přeskočilo a zapisovalo za konec pole, případně přes NULL, pokud selhala hned první alokace, a tento stav vydržel až do restartu dnsmasq. Projeví se jen při selhání alokace paměti, takže jde o opravu robustnosti, ne o chybu, kterou by útočník mohl přímo vyvolat. Náš třířádkový patch mění arrsize až po úspěšné realokaci. Simon Kelley ho 1. 10. commitnul jako baeb743 a 11. 10. v konferenci odpověděl „Patch applied.“

Časová osa

Jak to číst

Skener našel symptom, správce příčinu. Náš patch by umlčel jeden řádek logu, oprava v upstreamu odstraňuje zastaralé záznamy, které ho umožnily. Úzký patch je pro správce výchozí bod, ne poslední slovo. Nálezy jsou podněty pro lidi, ne rozsudky.

Zdroje

← Zpět na příběhy úspěchu