VYPR
Medium severity4.8NVD Advisory· Published Jun 16, 2026· Updated Jun 16, 2026

CVE-2026-10639

CVE-2026-10639

Description

Use-after-free in Zephyr's ICMPv4 echo reply processing allows remote DoS via ping.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Use-after-free in Zephyr's ICMPv4 echo reply processing allows remote DoS via ping.

Vulnerability

In Zephyr's native IPv4 stack, icmpv4_handle_echo_request() in subsys/net/ip/icmpv4.c builds an echo-reply packet, passes it to net_try_send_data(), and then calls net_stats_update_icmp_sent(net_pkt_iface(reply)). However, net_try_send_data() transfers ownership and may free the packet before the stats update, causing a use-after-free read of net_pkt_iface(reply). This affects versions from v1.14 through v4.4.0 when CONFIG_NET_STATISTICS_ICMP is enabled [1].

Exploitation

An unauthenticated remote attacker can craft a ping (ICMP echo request) to the target device. The vulnerability is reached via net_icmpv4_input and net_icmp_call_ipv4_handlers. The attacker does not require any credentials or special network position. Exploitation depends on a race window where the reply packet is freed before the stats macro reads its interface pointer. The condition is triggered only if CONFIG_NET_STATISTICS_ICMP is enabled [1].

Impact

Successful exploitation leads to a use-after-free read of the reply packet's memory, and if CONFIG_NET_STATISTICS_PER_INTERFACE is set, a write through a stale pointer. This most likely results in corrupted interface statistics or a remotely triggerable crash (denial of service). The effect is probabilistic due to the race condition [1].

Mitigation

The fix caches the interface pointer from the live received packet before sending and uses it for post-send stats updates. The fix was merged in commit 86e2166 [2] and is planned for release in Zephyr 4.5.0. As of this writing, no official release containing the fix is available; users are advised to apply the patch or disable CONFIG_NET_STATISTICS_ICMP as a workaround [1].

AI Insight generated on Jun 16, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

5
86e21665d464

net: ip: icmpv4: fix use-after-free

https://github.com/zephyrproject-rtos/zephyrTim PamborApr 10, 2026via nvd-ref
1 file changed · +11 9
  • subsys/net/ip/icmpv4.c+11 9 modified
    @@ -429,6 +429,7 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
     {
     	struct net_pkt *reply = NULL;
     	struct net_ipv4_hdr *ip_hdr = hdr->ipv4;
    +	struct net_if *iface = net_pkt_iface(pkt);
     	struct net_in_addr req_src, req_dst;
     	const struct net_in_addr *src;
     	struct net_pkt_cursor backup;
    @@ -459,7 +460,7 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
     		goto drop;
     	}
     
    -	reply = net_pkt_alloc_with_buffer(net_pkt_iface(pkt),
    +	reply = net_pkt_alloc_with_buffer(iface,
     					  net_pkt_ipv4_opts_len(pkt) +
     					  payload_len,
     					  NET_AF_INET, NET_IPPROTO_ICMP,
    @@ -470,8 +471,8 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
     	}
     
     	if (net_ipv4_is_addr_mcast(&req_dst) ||
    -	    net_ipv4_is_addr_bcast(net_pkt_iface(pkt), &req_dst)) {
    -		src = net_if_ipv4_select_src_addr(net_pkt_iface(pkt), &req_src);
    +	    net_ipv4_is_addr_bcast(iface, &req_dst)) {
    +		src = net_if_ipv4_select_src_addr(iface, &req_src);
     
     		if (net_ipv4_is_addr_unspecified(src)) {
     			NET_DBG("DROP: No src address match");
    @@ -511,7 +512,7 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(reply));
    +	net_stats_update_icmp_sent(iface);
     
     	net_pkt_cursor_restore(pkt, &backup);
     	return NET_CONTINUE;
    @@ -520,7 +521,7 @@ static enum net_verdict icmpv4_handle_echo_request(struct net_icmp_ctx *ctx,
     		net_pkt_unref(reply);
     	}
     
    -	net_stats_update_icmp_drop(net_pkt_iface(pkt));
    +	net_stats_update_icmp_drop(iface);
     
     	return NET_DROP;
     }
    @@ -529,6 +530,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code)
     {
     	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
     	int err = -EIO;
    +	struct net_if *iface = net_pkt_iface(orig);
     	struct net_ipv4_hdr *ip_hdr;
     	struct net_in_addr orig_src, orig_dst;
     	struct net_pkt *pkt;
    @@ -558,7 +560,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code)
     	net_ipv4_addr_copy_raw(orig_src.s4_addr, ip_hdr->src);
     	net_ipv4_addr_copy_raw(orig_dst.s4_addr, ip_hdr->dst);
     
    -	if (net_ipv4_is_addr_bcast(net_pkt_iface(orig), &orig_dst)) {
    +	if (net_ipv4_is_addr_bcast(iface, &orig_dst)) {
     		/* We should not send an error to packet that
     		 * were sent to broadcast
     		 */
    @@ -578,7 +580,7 @@ int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code)
     		copy_len = 0;
     	}
     
    -	pkt = net_pkt_alloc_with_buffer(net_pkt_iface(orig),
    +	pkt = net_pkt_alloc_with_buffer(iface,
     					copy_len + NET_ICMPV4_UNUSED_LEN,
     					NET_AF_INET, NET_IPPROTO_ICMP,
     					PKT_WAIT_TIME);
    @@ -607,15 +609,15 @@ int net_icmpv4_send_error(struct net_pkt *orig, uint8_t type, uint8_t code)
     		net_sprint_ipv4_addr(&orig_src));
     
     	if (net_try_send_data(pkt, K_NO_WAIT) >= 0) {
    -		net_stats_update_icmp_sent(net_pkt_iface(orig));
    +		net_stats_update_icmp_sent(iface);
     		return 0;
     	}
     
     drop:
     	net_pkt_unref(pkt);
     
     drop_no_pkt:
    -	net_stats_update_icmp_drop(net_pkt_iface(orig));
    +	net_stats_update_icmp_drop(iface);
     
     	return err;
     
    
ef293d8b5e5d

net: ipv6: nbr: fix use-after-free

https://github.com/zephyrproject-rtos/zephyrTim PamborApr 10, 2026via body-scan-shorthand
1 file changed · +3 3
  • subsys/net/ip/ipv6_nbr.c+3 3 modified
    @@ -1135,7 +1135,7 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src,
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2063,7 +2063,7 @@ int net_ipv6_send_ns(struct net_if *iface,
     
     	net_ipv6_nbr_unlock();
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2135,7 +2135,7 @@ int net_ipv6_send_rs(struct net_if *iface)
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    
a96ab665bd57

net: ipv6: nbr: fix use-after-free

https://github.com/zephyrproject-rtos/zephyrTim PamborApr 10, 2026via body-scan-shorthand
1 file changed · +3 3
  • subsys/net/ip/ipv6_nbr.c+3 3 modified
    @@ -1222,7 +1222,7 @@ int net_ipv6_send_na(struct net_if *iface, const struct net_in6_addr *src,
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2158,7 +2158,7 @@ int net_ipv6_send_ns(struct net_if *iface,
     
     	net_ipv6_nbr_unlock();
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2230,7 +2230,7 @@ int net_ipv6_send_rs(struct net_if *iface)
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    
aaed8332a62b

net: ipv6: nbr: fix use-after-free

https://github.com/zephyrproject-rtos/zephyrTim PamborApr 10, 2026via body-scan-shorthand
1 file changed · +3 3
  • subsys/net/ip/ipv6_nbr.c+3 3 modified
    @@ -1222,7 +1222,7 @@ int net_ipv6_send_na(struct net_if *iface, const struct net_in6_addr *src,
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2177,7 +2177,7 @@ int net_ipv6_send_ns(struct net_if *iface,
     
     	net_ipv6_nbr_unlock();
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2249,7 +2249,7 @@ int net_ipv6_send_rs(struct net_if *iface)
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    
3cab8170460f

net: ipv6: nbr: fix use-after-free

https://github.com/zephyrproject-rtos/zephyrTim PamborApr 10, 2026via body-scan-shorthand
1 file changed · +3 3
  • subsys/net/ip/ipv6_nbr.c+3 3 modified
    @@ -1221,7 +1221,7 @@ int net_ipv6_send_na(struct net_if *iface, const struct in6_addr *src,
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2169,7 +2169,7 @@ int net_ipv6_send_ns(struct net_if *iface,
     
     	net_ipv6_nbr_unlock();
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    @@ -2241,7 +2241,7 @@ int net_ipv6_send_rs(struct net_if *iface)
     		goto drop;
     	}
     
    -	net_stats_update_icmp_sent(net_pkt_iface(pkt));
    +	net_stats_update_icmp_sent(iface);
     	net_stats_update_ipv6_nd_sent(iface);
     
     	return 0;
    

Vulnerability mechanics

Root cause

"Use-after-free: `icmpv4_handle_echo_request()` reads `net_pkt_iface(reply)` to update ICMP statistics after `net_try_send_data()` has transferred ownership of the reply packet to the TX path, which may already have freed it."

Attack vector

An unauthenticated remote attacker triggers the bug by sending an ICMPv4 echo request (ping) to the device, which reaches `icmpv4_handle_echo_request` via `net_icmpv4_input` -> `net_icmp_call_ipv4_handlers` [CWE-416]. After the reply packet is sent via `net_try_send_data`, the TX path may free the `net_pkt` before the subsequent call to `net_pkt_iface(reply)`, causing a use-after-free read of packet memory and, when `CONFIG_NET_STATISTICS_PER_INTERFACE` is enabled, a wild-pointer write through the stale interface pointer. The race window is probabilistic; impact is corrupted interface statistics or a remotely triggerable crash (DoS).

Affected code

The vulnerability is in `icmpv4_handle_echo_request()` in `subsys/net/ip/icmpv4.c`. The function calls `net_try_send_data(reply)`, which transfers ownership of the `reply` packet to the TX path, and then reads `net_pkt_iface(reply)` from the now-freed packet on the next line to update ICMP statistics. The same pattern is also fixed in `net_icmpv4_send_error()` and in three IPv6 neighbor-discovery functions in `subsys/net/ip/ipv6_nbr.c` (``[ref_id=1]``).

What the fix does

The fix in commit `86e2166` [patch_id=6189719] caches the network interface pointer (`struct net_if *iface`) from the live received packet (`pkt`) at the top of `icmpv4_handle_echo_request()`, before any send occurs. All subsequent uses of `net_pkt_iface()` — for packet allocation, address checks, and post-send stats updates — are replaced with the cached `iface`. This eliminates the read of `reply->iface` after `net_try_send_data()` has transferred ownership and the TX path may have freed `reply`. The same caching pattern is applied in `net_icmpv4_send_error()` and in three IPv6 neighbor-discovery functions (`net_ipv6_send_na`, `net_ipv6_send_ns`, `net_ipv6_send_rs`) to fix identical use-after-free bugs [patch_id=6189720][patch_id=6189721][patch_id=6189722].

Preconditions

  • networkThe ICMP echo handler is reachable over the network (default for devices with native IPv4 stack)
  • configCONFIG_NET_STATISTICS_ICMP must be enabled (required to reach the vulnerable code path)

Generated on Jun 16, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.