From 8422531f931a4da17f2bb7cc457fe20cdac718bb Mon Sep 17 00:00:00 2001 From: zhanghongyu Date: Mon, 13 Jul 2026 10:07:04 +0800 Subject: [PATCH] net/udp: fix d_len corruption for 2nd+ SO_REUSEADDR listener In udp_input()'s broadcast/multicast fan-out loop, each iteration calls netdev_iob_replace(dev, iob) to swap in a freshly cloned iob before handing the packet to the next matching connection. That function unconditionally sets dev->d_len = iob->io_pktlen, which is the full frame length (IP + UDP headers + payload), undoing the 'dev->d_len -= udpiplen' done once before the loop to strip the headers off for udp_input_conn(). As a result, every connection after the first sees a d_len that is udpiplen (IP+UDP header length, eg 28 bytes for IPv4) too large. This value flows into udp_datahandler() as buflen (it reads dev->d_len directly) and is stored as the queued packet's declared length in the connection's read-ahead iob chain. Once more than one such oversized entry has queued up in the same chain, the consumer (udp_readahead() in udp_recvfrom.c) parses the following entry's metadata starting at the wrong offset, so whatever byte happens to land on src_addr_size is trusted as-is. That single byte (0-255) is then used as the length in iob_copyout(srcaddr, iob, src_addr_size, ...), which fills a fixed-size stack buffer with no bounds check outside a DEBUGASSERT - compiled out in release builds - so an oversized value overflows that stack buffer. Re-apply the same '-= udpiplen' header-stripping after each netdev_iob_replace() call in the loop, matching what's already done once before the loop for the first connection. Inside udp_input_conn, d_appdata is always set first, and since neither the ICMP nor ICMPv6 process accesses d_appdata, the redundant d_appdata settings have been removed. Signed-off-by: yi chen <94xhn1@gmail.com> --- net/udp/udp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/udp/udp_input.c b/net/udp/udp_input.c index fb98ab6ee5c..c48dd49d126 100644 --- a/net/udp/udp_input.c +++ b/net/udp/udp_input.c @@ -253,7 +253,6 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen) */ dev->d_len -= udpiplen; - dev->d_appdata = IPBUF(udpiplen); #ifdef CONFIG_NET_UDP_CHECKSUMS if ((dev->d_features & NETDEV_RX_CSUM) == 0) @@ -336,6 +335,7 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen) } netdev_iob_replace(dev, iob); + dev->d_len -= udpiplen; udp = IPBUF(iplen); conn = nextconn; }