ITADN

`net: dns: dispatcher mutex (server->dispatcher.lock) never initialized — crashes on first real DNS response with CONFIG_ASSERT=y`

#114407ClosedsekyHC 创建于 29 天前
S
sekyHCcommented
### Describe the bug ## Describe the bug `register_dispatcher()` in `subsys/net/lib/dns/resolve.c` populates every field of the per-server `struct dns_socket_dispatcher` (`server->dispatcher`) except `.lock` — a `struct k_mutex` — before handing it to `dns_dispatcher_register()`. That mutex is later locked for real in `dispatcher.c`'s `recv_data()`: ```c dispatcher = table[pev->event.fd].ctx; k_mutex_lock(&dispatcher->lock, K_FOREVER); ``` server->dispatcher.lock is never passed through k_mutex_init() anywhere in the DNS subsystem. It only ever gets zero bits from the memset(ctx, 0, sizeof(*ctx)) in dns_resolve_init_with_svc() (which runs once, on first init, before any servers exist) — that's not equivalent to k_mutex_init(), since it doesn't stamp the mutex's magic field. Grepping the DNS subsystem shows exactly one k_mutex_init() call in the whole directory, and it's for the resolve context's own ctx->lock (a different, sibling mutex), not the dispatcher's. With CONFIG_ASSERT=y, the first real DNS response that reaches recv_data() hits: ``` ASSERTION FAIL [mutex->magic == (("MUTX"[0] << 24) | ("MUTX"[1] << 16) | ("MUTX"[2] << 8) | ("MUTX"[3]))] @ .../kernel/mutex.c:135 k_mutex 0x... locked before initialized, current thread: net_socket_service >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0 ``` With asserts disabled the bug is presumably silent (the mutex's underlying wait-queue logic may still function without the magic tag), which is likely why this hasn't surfaced as an obvious functional bug and gone unreported. I confirmed this is still present on current main, not just v4.4.0 — register_dispatcher() there has the identical set of field assignments with .lock still missing. ### Regression - [ ] This is a regression. ### Steps to reproduce 1. Enable CONFIG_DNS_RESOLVER=y and CONFIG_ASSERT=y. 2. Get the DNS resolver a real, working server (e.g. via DHCP, or dns_resolve_init()/dns_resolve_reconfigure() with a real address) and make sure net_socket_service's worker thread is actually running (see note below — it's easy to accidentally starve this thread, which masks the present bug rather than triggering it). 3. Issue any DNS query that gets a real response (e.g. net dns <hostname> from the net shell, or getaddrinfo()/dns_resolve_name() from application code). 4. The first response processed by dns_dispatcher_svc_handler() → recv_data() → k_mutex_lock(&dispatcher->lock, ...) crashes with the assertion above. Reproduced both on real hardware (ESP32-S3) and in native_sim. Note: on a from-scratch project, this can be masked by an unrelated issue — if net_socket_service's own zvfs_eventfd() call fails at startup (e.g. because CONFIG_ZVFS_EVENTFD_MAX is exhausted by another eventfd consumer), that thread exits immediately and DNS responses never reach recv_data() at all, so this specific mutex bug never gets a chance to fire. Once that separate issue is fixed and the thread runs a real query to completion, this one surfaces immediately. ### Relevant log output ```shell ``` ### Impact Functional Limitation – Some features not working as expected, but system usable. ### Environment * OS: Zephyr (confirmed on v4.4.0 and independently verified still present on current main as of 2026-07) * Toolchain: Zephyr SDK * Board: real hardware — ESP32-S3 (custom board); also reproduced in native_sim * Relevant Kconfig: CONFIG_DNS_RESOLVER=y, CONFIG_ASSERT=y, CONFIG_NET_SOCKETS_SOCKOPT_TLS (unrelated, just what was enabled when this was found) ### Additional Context Add a k_mutex_init() call for the dispatcher's own lock in register_dispatcher(), alongside its other field initializations: ```c static int register_dispatcher(struct dns_resolve_context *ctx, const struct net_socket_service_desc *svc, struct dns_server *server, struct net_sockaddr *local, const struct net_in6_addr *addr6, const struct net_in_addr *addr4) { k_mutex_init(&server->dispatcher.lock); server->dispatcher.type = DNS_SOCKET_RESOLVER; server->dispatcher.cb = dispatcher_cb; ``` This is the single call site both server-list code paths (string-form and net_sockaddr-form) in dns_resolve_init_locked() funnel through per-server, so it only needs to be added once. Happy to open a PR with this change if useful.
关闭于 29 天前 3 条评论