Our pinned Zephyr carries a stack-use-after-return in the mDNS responder that kills all
mDNS answering intermittently, with no user code involved. Fixed upstream on 2026-08-06 by
ba0bd94d4e9 ("Use static storage for listener poll arrays"), which is not in our pin.
subsys/net/lib/dns/mdns_responder.c in our pin declares the arrays inside
init_listener():
1643: struct zsock_pollfd ipv6_fds[MAX_IPV6_IFACE_COUNT]; automatic storage
1753: struct zsock_pollfd ipv4_fds[MAX_IPV4_IFACE_COUNT]; automatic storage
1741: register_dispatcher(&v6_ctx[i], &v6_svc, ..., ipv6_fds, ARRAY_SIZE(ipv6_fds));
1851: register_dispatcher(&v4_ctx[i], &v4_svc, ..., ipv4_fds, ARRAY_SIZE(ipv4_fds));
1512: ctx->dispatcher.fds = fds; pointer retained
and the retained pointer is dereferenced after the frame dies, at dispatcher.c:398 and in
the ctx->fds[i].fd reads at dispatcher.c:278-288 and 335-349.
Trap for anyone verifying: net_socket_service_register() itself copies the fds
(svc->pev[i].event = fds[i]), so that function looks safe in isolation. The retention is
one level up, via ctx->dispatcher.fds.
Symptom is intermittent, which is the signature: fine while the freed frame happens to be
intact, dead once it is reused. A board can answer nothing from a fresh boot with no Python
object in existence, then answer correctly after the next reset.
Verified on hardware. Applying the upstream commit as a local test patch:
.bss +32 bytes exactly, confirming the arrays moved to file scope
5 hard-reset cycles, 3 probe rounds each, no user mdns.Server
declared pass criterion >=2 of 3 rounds per cycle
result: 3/3, 3/3, 3/3, 3/3, 3/3 -- not one silent round in fifteen
pre-patch, same probe: one healthy window then 0/6, fresh-reset baseline 0
Not landable as a direct edit. tannewt pins Zephyr by SHA in west.yml, so this has to go
through adafruit/zephyr plus a pin bump.
Worth considering a bump rather than a single pick: DNS/mDNS churned nine commits upstream
between 2026-08-04 and 2026-08-11, including 748a0b1b023 (multi-homed A/AAAA and DNS-SD
response interface selection), 19289bd7529 (DNS port per family) and d7859a7117a
(getsockname failure handling). A bump costs a wider retest.
Separate from #51, which survives this fix and is a genuine port bug.
Our pinned Zephyr carries a stack-use-after-return in the mDNS responder that kills all
mDNS answering intermittently, with no user code involved. Fixed upstream on 2026-08-06 by
ba0bd94d4e9("Use static storage for listener poll arrays"), which is not in our pin.subsys/net/lib/dns/mdns_responder.cin our pin declares the arrays insideinit_listener():and the retained pointer is dereferenced after the frame dies, at
dispatcher.c:398and inthe
ctx->fds[i].fdreads at dispatcher.c:278-288 and 335-349.Trap for anyone verifying:
net_socket_service_register()itself copies the fds(
svc->pev[i].event = fds[i]), so that function looks safe in isolation. The retention isone level up, via
ctx->dispatcher.fds.Symptom is intermittent, which is the signature: fine while the freed frame happens to be
intact, dead once it is reused. A board can answer nothing from a fresh boot with no Python
object in existence, then answer correctly after the next reset.
Verified on hardware. Applying the upstream commit as a local test patch:
Not landable as a direct edit. tannewt pins Zephyr by SHA in
west.yml, so this has to gothrough
adafruit/zephyrplus a pin bump.Worth considering a bump rather than a single pick: DNS/mDNS churned nine commits upstream
between 2026-08-04 and 2026-08-11, including
748a0b1b023(multi-homed A/AAAA and DNS-SDresponse interface selection),
19289bd7529(DNS port per family) andd7859a7117a(getsockname failure handling). A bump costs a wider retest.
Separate from #51, which survives this fix and is a genuine port bug.