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;