This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 8422531f931 net/udp: fix d_len corruption for 2nd+ SO_REUSEADDR 
listener
8422531f931 is described below

commit 8422531f931a4da17f2bb7cc457fe20cdac718bb
Author: zhanghongyu <[email protected]>
AuthorDate: Mon Jul 13 10:07:04 2026 +0800

    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 <[email protected]>
---
 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;
                 }

Reply via email to