dns_unpack_name() in subsys/net/lib/dns/dns_pack.c snapshots dest_size = net_buf_tailroom(buf) once and reuses it while appending labels. As buf->len grows, the stale bound no longer matches the remaining space, and the final null terminator is written without a fresh tailroom check. With assertions disabled (default), attacker-controlled labels in a DNS response can drive out-of-bounds writes. Zephyr builds that enable DNS (CONFIG_DNS_RESOLVER) on default assert settings are vulnerable.
Details
Vulnerable code (subsys/net/lib/dns/dns_pack.c:486-554):
int dns_unpack_name(const uint8_t *msg, int maxlen, const uint8_t *src,
struct net_buf *buf, const uint8_t **eol)
{
int dest_size = net_buf_tailroom(buf);
...
label_len = val;
...
if (((buf->data + label_len + 1) >= (buf->data + dest_size)) ||
((curr_src + label_len) >= (msg + maxlen))) {
return -EMSGSIZE;
}
...
if (buf->len > 0) {
net_buf_add_u8(buf, '.'); // advances buf->len
}
net_buf_add_mem(buf, curr_src, label_len); // advances buf->len
...
buf->data[buf->len] = '\0'; // unchecked write
}
Technical details:
- Assertions default off (
include/zephyr/sys/__assert.h:26-149); CONFIG_ASSERT defaults n (subsys/debug/Kconfig:172-205).
- net_buf add helpers rely only on assertions (
lib/net_buf/buf_simple.c:56-74), so they perform unchecked writes when asserts are off.
- Default DNS name buffer is 255 bytes via
CONFIG_DNS_RESOLVER_MAX_QUERY_LEN (subsys/net/lib/dns/resolve.c:72-82, subsys/net/lib/dns/Kconfig:72-88), while message length can be 512 bytes (DNS_RESOLVER_MAX_ANSWER_SIZE default).
PoC (concept)
- Build any Zephyr app with DNS resolver enabled and default
CONFIG_ASSERT=n.
- Send a crafted DNS response with repeated 63-byte labels (e.g., 5 labels), so the textual name length exceeds the 255-byte buffer but remains within the allowed message length.
- As the response is parsed,
dest_size stays stale; net_buf_add_* advances buf->len beyond the buffer, and the final writes overflow ~100–200 bytes depending on label count.
Potential impact
- Out-of-bounds write of attacker-controlled data -> high integrity/availability risk; plausible RCE depending on memory layout.
- Network-reachable, unauthenticated when DNS is enabled.
- Enabling assertions turns the overflow into a crash (DoS) but is not a full fix; code needs live tailroom checks before each write (including the terminator).
Patches
main: #99683
v4.3: #99830
v4.2: #99829
v3.7#99828
For more information
If you have any questions or comments about this advisory:
embargo: 2026-02-16
dns_unpack_name()insubsys/net/lib/dns/dns_pack.csnapshotsdest_size = net_buf_tailroom(buf)once and reuses it while appending labels. Asbuf->lengrows, the stale bound no longer matches the remaining space, and the final null terminator is written without a fresh tailroom check. With assertions disabled (default), attacker-controlled labels in a DNS response can drive out-of-bounds writes. Zephyr builds that enable DNS (CONFIG_DNS_RESOLVER) on default assert settings are vulnerable.Details
Vulnerable code (
subsys/net/lib/dns/dns_pack.c:486-554):Technical details:
include/zephyr/sys/__assert.h:26-149);CONFIG_ASSERTdefaults n (subsys/debug/Kconfig:172-205).lib/net_buf/buf_simple.c:56-74), so they perform unchecked writes when asserts are off.CONFIG_DNS_RESOLVER_MAX_QUERY_LEN(subsys/net/lib/dns/resolve.c:72-82,subsys/net/lib/dns/Kconfig:72-88), while message length can be 512 bytes (DNS_RESOLVER_MAX_ANSWER_SIZEdefault).PoC (concept)
CONFIG_ASSERT=n.dest_sizestays stale;net_buf_add_*advancesbuf->lenbeyond the buffer, and the final writes overflow ~100–200 bytes depending on label count.Potential impact
Patches
main: #99683
v4.3: #99830
v4.2: #99829
v3.7#99828
For more information
If you have any questions or comments about this advisory:
embargo: 2026-02-16