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-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 75b498c94 netutils/dhcp6c: validate stored option lengths
75b498c94 is described below

commit 75b498c9440649dd68a5766e35c30b62b877d5fc
Author: chao an <[email protected]>
AuthorDate: Thu Oct 22 22:41:08 2026 +0800

    netutils/dhcp6c: validate stored option lengths
    
    The DHCPv6 client result path trusted previously stored IA_NA, IA_PD,
    and DNS option data before copying fixed-size IPv6 addresses into the
    reported client state.  A malicious DHCPv6 reply could provide truncated
    options, or omit DNS data entirely, and later trigger an out-of-bounds
    read or NULL pointer dereference while building the callback result.
    
    Check that stored IA address and prefix options have enough payload for
    the fixed fields being read, and only copy DNS data when a complete IPv6
    address is present.  Skip malformed stored options instead of consuming
    short buffers.
    
    Signed-off-by: chao an <[email protected]>
---
 netutils/dhcp6c/dhcp6c.c | 60 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 17 deletions(-)

diff --git a/netutils/dhcp6c/dhcp6c.c b/netutils/dhcp6c/dhcp6c.c
index 5505f11b3..9c30c1137 100644
--- a/netutils/dhcp6c/dhcp6c.c
+++ b/netutils/dhcp6c/dhcp6c.c
@@ -421,31 +421,57 @@ static void dhcp6c_get_result(FAR void *handle,
     }
 
   s_data = dhcp6c_get_state(handle, STATE_IA_NA, &s_len);
-  dhcpv6_for_each_option(ite, s_data, s_data + s_len, otype, olen, odata)
+  if (s_data != NULL)
     {
-      addr = (FAR void *)(odata - 4);
-      memcpy(&presult->addr, &addr->addr, sizeof(presult->addr));
-      inet_ntop(AF_INET6, &presult->addr, addr_str, sizeof(addr_str));
-      ninfo("IA_NA %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+      dhcpv6_for_each_option(ite, s_data, s_data + s_len,
+                             otype, olen, odata)
+        {
+          if (otype != DHCPV6_OPT_IA_ADDR ||
+              olen < sizeof(*addr) - sizeof(addr->type) -
+                     sizeof(addr->len))
+            {
+              continue;
+            }
+
+          addr = (FAR void *)(odata - 4);
+          memcpy(&presult->addr, &addr->addr, sizeof(presult->addr));
+          inet_ntop(AF_INET6, &presult->addr, addr_str, sizeof(addr_str));
+          ninfo("IA_NA %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+        }
     }
 
   s_data = dhcp6c_get_state(handle, STATE_IA_PD, &s_len);
-  dhcpv6_for_each_option(ite, s_data, s_data + s_len, otype, olen, odata)
+  if (s_data != NULL)
     {
-      pd = (FAR void *)(odata - 4);
-      memcpy(&presult->pd, &pd->addr, sizeof(presult->pd));
-      presult->pl = pd->prefix;
-      netlib_prefix2ipv6netmask(presult->pl, &presult->netmask);
-      inet_ntop(AF_INET6, &presult->pd, addr_str, sizeof(addr_str));
-      ninfo("IA_PD %s for iface %i\n", addr_str, pdhcp6c->ifindex);
-      inet_ntop(AF_INET6, &presult->netmask, addr_str, sizeof(addr_str));
-      ninfo("netmask %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+      dhcpv6_for_each_option(ite, s_data, s_data + s_len,
+                             otype, olen, odata)
+        {
+          if (otype != DHCPV6_OPT_IA_PREFIX ||
+              olen < sizeof(*pd) - sizeof(pd->type) - sizeof(pd->len))
+            {
+              continue;
+            }
+
+          pd = (FAR void *)(odata - 4);
+          memcpy(&presult->pd, &pd->addr, sizeof(presult->pd));
+          presult->pl = pd->prefix;
+          netlib_prefix2ipv6netmask(presult->pl, &presult->netmask);
+          inet_ntop(AF_INET6, &presult->pd, addr_str, sizeof(addr_str));
+          ninfo("IA_PD %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+          inet_ntop(AF_INET6, &presult->netmask, addr_str,
+                    sizeof(addr_str));
+          ninfo("netmask %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+        }
     }
 
   dns = dhcp6c_get_state(handle, STATE_DNS, &s_len);
-  memcpy(&presult->dns, dns, sizeof(presult->dns));
-  inet_ntop(AF_INET6, &presult->dns, addr_str, sizeof(addr_str));
-  ninfo("DNS server %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+  if (dns != NULL && s_len >= sizeof(presult->dns) &&
+      s_len % sizeof(*dns) == 0)
+    {
+      memcpy(&presult->dns, dns, sizeof(presult->dns));
+      inet_ntop(AF_INET6, &presult->dns, addr_str, sizeof(addr_str));
+      ninfo("DNS server %s for iface %i\n", addr_str, pdhcp6c->ifindex);
+    }
 
   presult->t1 = pdhcp6c->t1;
   presult->t2 = pdhcp6c->t2;

Reply via email to