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 97a50eaf453 net/sixlowpan: Fix sixlowpan_uncompresshdr_hc06()
97a50eaf453 is described below

commit 97a50eaf453469a7c3afc76b40c86e4552d59b97
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Sun May 3 14:52:22 2026 -0300

    net/sixlowpan: Fix sixlowpan_uncompresshdr_hc06()
    
    This commit fixes sixlowpan_uncompresshdr_hc06() to avoid that the
    frame data be bigger than the iob->io_len.
    
    Signed-off-by: Alan C. Assis <[email protected]>
---
 net/sixlowpan/sixlowpan_hc06.c     | 63 ++++++++++++++++++++++++++++++++------
 net/sixlowpan/sixlowpan_input.c    | 10 ++++--
 net/sixlowpan/sixlowpan_internal.h |  8 ++---
 3 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c
index 8f05471ab04..7da821d2798 100644
--- a/net/sixlowpan/sixlowpan_hc06.c
+++ b/net/sixlowpan/sixlowpan_hc06.c
@@ -86,6 +86,16 @@
 #define UNCOMPRESS_MACBASED (1 << 8)
 #define UNCOMPRESS_ZEROPAD  (1 << 9)
 
+#define HC06_CHECK(ptr, nbytes, endofframe)                  \
+  do {                                                       \
+    if ((ptr) + (nbytes) > endofframe)                       \
+      {                                                      \
+        nerr("ERROR: HC06 frame truncated at %s:%d\n",       \
+             __func__, __LINE__);                            \
+        return -EINVAL;                                      \
+      }                                                      \
+  } while (0)
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -1166,17 +1176,18 @@ int sixlowpan_compresshdr_hc06(FAR struct 
radio_driver_s *radio,
  *              FRAGN frames.
  *
  * Returned Value:
- *   None
+ *   On success returns 0 otherwise a negative error
  *
  ****************************************************************************/
 
-void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
-                                  FAR const void *metadata,
-                                  uint16_t iplen, FAR struct iob_s *iob,
-                                  FAR uint8_t *fptr, FAR uint8_t *bptr)
+int sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
+                                 FAR const void *metadata,
+                                 uint16_t iplen, FAR struct iob_s *iob,
+                                 FAR uint8_t *fptr, FAR uint8_t *bptr)
 {
   FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)bptr;
   struct netdev_varaddr_s addr;
+  FAR uint8_t *endofframe;
   FAR uint8_t *iphc;
   uint8_t iphc0;
   uint8_t iphc1;
@@ -1193,6 +1204,13 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
   g_hc06ptr = iphc + 2;
 
+  /* Compute the end of the IOB frame data. All g_hc06ptr accesses
+   * must stay strictly before this pointer. Used by HC06_CHECK()
+   * throughout this function to prevent OOB reads on crafted frames.
+   */
+
+  endofframe = fptr + iob->io_len;
+
   ninfo("fptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n",
          fptr, g_frame_hdrlen, iphc[0], iphc[1], iphc[2], g_hc06ptr);
 
@@ -1201,6 +1219,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
   if ((iphc1 & SIXLOWPAN_IPHC_CID) != 0)
     {
       ninfo("CID flag set. Increase header by one\n");
+      HC06_CHECK(g_hc06ptr, 1, endofframe);
       g_hc06ptr++;
     }
 
@@ -1216,6 +1235,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
           memcpy(&ipv6->tcf, g_hc06ptr + 1, 3);
           tmp        = *g_hc06ptr;
+          HC06_CHECK(g_hc06ptr, 4, endofframe);
           g_hc06ptr += 4;
 
           /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN
@@ -1238,6 +1258,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
           ipv6->tcf = (*g_hc06ptr & 0x0f) | ((*g_hc06ptr >> 2) & 0x30);
           memcpy(&ipv6->flow, g_hc06ptr + 1, 2);
+          HC06_CHECK(g_hc06ptr, 3, endofframe);
           g_hc06ptr  += 3;
         }
     }
@@ -1256,6 +1277,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
           ipv6->tcf   = ((*g_hc06ptr << 6) & 0xc0) |
                         ((*g_hc06ptr >> 2) & 0x30);
           ipv6->flow  = 0;
+          HC06_CHECK(g_hc06ptr, 1, endofframe);
           g_hc06ptr  += 1;
         }
       else
@@ -1276,6 +1298,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
       ipv6->proto = *g_hc06ptr;
       ninfo("Next header inline: %d\n", ipv6->proto);
+      HC06_CHECK(g_hc06ptr, 1, endofframe);
       g_hc06ptr += 1;
     }
 
@@ -1288,6 +1311,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
   else
     {
       ipv6->ttl  = *g_hc06ptr;
+      HC06_CHECK(g_hc06ptr, 1, endofframe);
       g_hc06ptr += 1;
     }
 
@@ -1301,7 +1325,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
   if (ret < 0)
     {
       nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
-      return;
+      return ret;
     }
 
   if ((iphc1 & SIXLOWPAN_IPHC_SAC) != 0)
@@ -1319,7 +1343,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
           if (addrcontext == NULL)
             {
               nerr("ERROR: Address context not found\n");
-              return;
+              return -ENOENT;
             }
         }
 
@@ -1330,6 +1354,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
        * address.
        */
 
+      /* Source address: worst case 16 bytes inline */
+
+      HC06_CHECK(g_hc06ptr, 16, endofframe);
+
       uncompress_addr(&addr,
                       tmp != 0 ? addrcontext->prefix : NULL,
                       g_unc_ctxconf[tmp], ipv6->srcipaddr);
@@ -1342,6 +1370,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
        * address.
        */
 
+      /* Destination address: worst case 16 bytes inline */
+
+      HC06_CHECK(g_hc06ptr, 16, endofframe);
+
       uncompress_addr(&addr, g_llprefix, g_unc_llconf[tmp],
                       ipv6->srcipaddr);
     }
@@ -1359,7 +1391,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
   if (ret < 0)
     {
       nerr("ERROR: sixlowpan_extract_srcaddr failed: %d\n", ret);
-      return;
+      return ret;
     }
 
   if ((iphc1 & SIXLOWPAN_IPHC_M) != 0)
@@ -1388,6 +1420,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
           if (tmp > 0 && tmp < 3)
             {
               prefix[1] = *g_hc06ptr;
+              HC06_CHECK(g_hc06ptr, 1, endofframe);
               g_hc06ptr++;
             }
 
@@ -1415,7 +1448,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
           if (addrcontext == NULL)
             {
               nerr("ERROR: Address context not found\n");
-              return;
+              return -ENOENT;
             }
 
           uncompress_addr(&addr, addrcontext->prefix, g_unc_ctxconf[tmp],
@@ -1456,6 +1489,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
             {
             case SIXLOWPAN_NHC_UDP_CS_P_00:
 
+              HC06_CHECK(g_hc06ptr, 5, endofframe);
+
               /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
 
               memcpy(&udp->srcport, g_hc06ptr + 1, 2);
@@ -1469,6 +1504,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
             case SIXLOWPAN_NHC_UDP_CS_P_01:
 
+              HC06_CHECK(g_hc06ptr, 4, endofframe);
+
               /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit
                * inline
                */
@@ -1487,6 +1524,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
             case SIXLOWPAN_NHC_UDP_CS_P_10:
 
+              HC06_CHECK(g_hc06ptr, 4, endofframe);
+
               /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit
                * inline
                */
@@ -1505,6 +1544,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
             case SIXLOWPAN_NHC_UDP_CS_P_11:
 
+              HC06_CHECK(g_hc06ptr, 2, endofframe);
+
               /* 1 byte for NHC, 1 byte for ports */
 
               udp->srcport =
@@ -1522,7 +1563,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
 
             default:
               nerr("ERROR: Error unsupported UDP compression\n");
-              return;
+              return -EINVAL;
             }
 
           if (!checksum_compressed)
@@ -1571,6 +1612,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct 
radio_driver_s *radio,
                           (FAR struct udp_hdr_s *)(bptr + IPv6_HDRLEN);
       memcpy(&udp->udplen, &ipv6->len[0], 2);
     }
+
+  return OK;
 }
 
 #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index 70711737808..80108dc2d3a 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -457,8 +457,14 @@ static int sixlowpan_frame_process(FAR struct 
radio_driver_s *radio,
       SIXLOWPAN_DISPATCH_IPHC)
     {
       ninfo("IPHC Dispatch\n");
-      sixlowpan_uncompresshdr_hc06(radio, metadata,
-                                   fragsize, iob, fptr, bptr);
+      ret = sixlowpan_uncompresshdr_hc06(radio, metadata,
+                                         fragsize, iob, fptr, bptr);
+      if (ret < 0)
+        {
+          nerr("ERROR: HC06 header decompress failed, dropping frame: %d\n",
+               ret);
+          goto errout_with_reass;
+        }
     }
   else
 #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
diff --git a/net/sixlowpan/sixlowpan_internal.h 
b/net/sixlowpan/sixlowpan_internal.h
index dd053bf1a4a..b74e4cd7eff 100644
--- a/net/sixlowpan/sixlowpan_internal.h
+++ b/net/sixlowpan/sixlowpan_internal.h
@@ -495,10 +495,10 @@ int sixlowpan_compresshdr_hc06(FAR struct radio_driver_s 
*radio,
  ****************************************************************************/
 
 #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
-                                  FAR const void *metadata,
-                                  uint16_t iplen, FAR struct iob_s *iob,
-                                  FAR uint8_t *fptr, FAR uint8_t *bptr);
+int sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
+                                 FAR const void *metadata,
+                                 uint16_t iplen, FAR struct iob_s *iob,
+                                 FAR uint8_t *fptr, FAR uint8_t *bptr);
 #endif
 
 /****************************************************************************

Reply via email to