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

xiaoxiang781216 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 fd307ba191f net/mld: validate MLDv2 report record bounds
fd307ba191f is described below

commit fd307ba191fe8ad8a355a54b4410ba37906ba16c
Author: chao an <[email protected]>
AuthorDate: Thu Oct 22 22:37:39 2026 +0800

    net/mld: validate MLDv2 report record bounds
    
    The MLDv2 report handler trusted the attacker-controlled multicast
    address record count and indexed records using a fixed stride.  MLDv2
    records are variable length because they include a source-address list
    and optional auxiliary data.
    
    A malformed report with a large record count or truncated variable-length
    record could make the parser read past the received ICMPv6 packet buffer.
    
    Derive the remaining MLD payload length from the IPv6 receive buffer,
    validate the fixed report header, walk each address record by its true
    encoded length, and reject truncated records or trailing length mismatches
    before reading the multicast address.
    
    Signed-off-by: chao an <[email protected]>
---
 net/mld/mld_report.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/net/mld/mld_report.c b/net/mld/mld_report.c
index 85d9c119b5c..28bb0a1db2d 100644
--- a/net/mld/mld_report.c
+++ b/net/mld/mld_report.c
@@ -27,6 +27,7 @@
 #include <nuttx/config.h>
 
 #include <assert.h>
+#include <stddef.h>
 #include <nuttx/debug.h>
 
 #include <nuttx/wdog.h>
@@ -177,7 +178,12 @@ int mld_report_v1(FAR struct net_driver_s *dev,
 int mld_report_v2(FAR struct net_driver_s *dev,
                   FAR const struct mld_mcast_listen_report_v2_s *report)
 {
+  FAR const uint8_t *end;
+  FAR const uint8_t *ipbuf;
+  FAR const uint8_t *ptr;
+  FAR const uint8_t *start;
   uint16_t naddrec;
+  size_t len;
   int ret = -ENOENT;
   int i;
 
@@ -186,12 +192,56 @@ int mld_report_v2(FAR struct net_driver_s *dev,
 
   MLD_STATINCR(g_netstats.mld.v2report_received);
 
+  ipbuf = (FAR const uint8_t *)IPBUF(0);
+  start = (FAR const uint8_t *)report;
+
+  if (start < ipbuf || start >= ipbuf + dev->d_len)
+    {
+      return -EINVAL;
+    }
+
+  len = dev->d_len - (start - ipbuf);
+
+  if (len < offsetof(struct mld_mcast_listen_report_v2_s, addrec))
+    {
+      return -EINVAL;
+    }
+
   naddrec = NTOHS(report->naddrec);
+  ptr     = (FAR const uint8_t *)report +
+            offsetof(struct mld_mcast_listen_report_v2_s, addrec);
+  end     = (FAR const uint8_t *)report + len;
+
   for (i = 0; i < naddrec; i++)
     {
+      FAR const struct mld_mcast_addrec_v2_s *addrec;
+      size_t offset;
+      size_t addreclen;
+      uint16_t nsources;
+      int status;
+
+      offset = ptr - (FAR const uint8_t *)report;
+      if (len - offset < offsetof(struct mld_mcast_addrec_v2_s, srcaddr))
+        {
+          ret = -EINVAL;
+          break;
+        }
+
+      addrec    = (FAR const struct mld_mcast_addrec_v2_s *)ptr;
+      nsources  = NTOHS(addrec->nsources);
+      addreclen = offsetof(struct mld_mcast_addrec_v2_s, srcaddr) +
+                  (size_t)nsources * sizeof(net_ipv6addr_t) +
+                  (size_t)addrec->auxdatlen * sizeof(uint32_t);
+
+      if (addreclen > len - offset)
+        {
+          ret = -EINVAL;
+          break;
+        }
+
       /* Handle this mcast address in the list */
 
-      int status = mld_report(dev, report->addrec[i].mcast);
+      status = mld_report(dev, addrec->mcast);
       if (status == OK)
         {
           /* Return success if any address in the listed was processed */
@@ -205,6 +255,13 @@ int mld_report_v2(FAR struct net_driver_s *dev,
           ret = status;
           break;
         }
+
+      ptr += addreclen;
+    }
+
+  if (i == naddrec && ptr != end)
+    {
+      ret = -EINVAL;
     }
 
   return ret;

Reply via email to