8686#define UNCOMPRESS_MACBASED (1 << 8)
8787#define UNCOMPRESS_ZEROPAD (1 << 9)
8888
89+ #define HC06_CHECK (ptr , nbytes , endofframe ) \
90+ do { \
91+ if ((ptr) + (nbytes) > endofframe) \
92+ { \
93+ nerr("ERROR: HC06 frame truncated at %s:%d\n", \
94+ __func__, __LINE__); \
95+ return -EINVAL; \
96+ } \
97+ } while (0)
98+
8999/****************************************************************************
90100 * Private Types
91101 ****************************************************************************/
@@ -1166,17 +1176,18 @@ int sixlowpan_compresshdr_hc06(FAR struct radio_driver_s *radio,
11661176 * FRAGN frames.
11671177 *
11681178 * Returned Value:
1169- * None
1179+ * On success returns 0 otherwise a negative error
11701180 *
11711181 ****************************************************************************/
11721182
1173- void sixlowpan_uncompresshdr_hc06 (FAR struct radio_driver_s * radio ,
1174- FAR const void * metadata ,
1175- uint16_t iplen , FAR struct iob_s * iob ,
1176- FAR uint8_t * fptr , FAR uint8_t * bptr )
1183+ int sixlowpan_uncompresshdr_hc06 (FAR struct radio_driver_s * radio ,
1184+ FAR const void * metadata ,
1185+ uint16_t iplen , FAR struct iob_s * iob ,
1186+ FAR uint8_t * fptr , FAR uint8_t * bptr )
11771187{
11781188 FAR struct ipv6_hdr_s * ipv6 = (FAR struct ipv6_hdr_s * )bptr ;
11791189 struct netdev_varaddr_s addr ;
1190+ FAR uint8_t * endofframe ;
11801191 FAR uint8_t * iphc ;
11811192 uint8_t iphc0 ;
11821193 uint8_t iphc1 ;
@@ -1193,6 +1204,13 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
11931204
11941205 g_hc06ptr = iphc + 2 ;
11951206
1207+ /* Compute the end of the IOB frame data. All g_hc06ptr accesses
1208+ * must stay strictly before this pointer. Used by HC06_CHECK()
1209+ * throughout this function to prevent OOB reads on crafted frames.
1210+ */
1211+
1212+ endofframe = fptr + iob -> io_len ;
1213+
11961214 ninfo ("fptr=%p g_frame_hdrlen=%u iphc=%02x:%02x:%02x g_hc06ptr=%p\n" ,
11971215 fptr , g_frame_hdrlen , iphc [0 ], iphc [1 ], iphc [2 ], g_hc06ptr );
11981216
@@ -1201,6 +1219,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
12011219 if ((iphc1 & SIXLOWPAN_IPHC_CID ) != 0 )
12021220 {
12031221 ninfo ("CID flag set. Increase header by one\n" );
1222+ HC06_CHECK (g_hc06ptr , 1 , endofframe );
12041223 g_hc06ptr ++ ;
12051224 }
12061225
@@ -1216,6 +1235,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
12161235
12171236 memcpy (& ipv6 -> tcf , g_hc06ptr + 1 , 3 );
12181237 tmp = * g_hc06ptr ;
1238+ HC06_CHECK (g_hc06ptr , 4 , endofframe );
12191239 g_hc06ptr += 4 ;
12201240
12211241 /* 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,
12381258
12391259 ipv6 -> tcf = (* g_hc06ptr & 0x0f ) | ((* g_hc06ptr >> 2 ) & 0x30 );
12401260 memcpy (& ipv6 -> flow , g_hc06ptr + 1 , 2 );
1261+ HC06_CHECK (g_hc06ptr , 3 , endofframe );
12411262 g_hc06ptr += 3 ;
12421263 }
12431264 }
@@ -1256,6 +1277,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
12561277 ipv6 -> tcf = ((* g_hc06ptr << 6 ) & 0xc0 ) |
12571278 ((* g_hc06ptr >> 2 ) & 0x30 );
12581279 ipv6 -> flow = 0 ;
1280+ HC06_CHECK (g_hc06ptr , 1 , endofframe );
12591281 g_hc06ptr += 1 ;
12601282 }
12611283 else
@@ -1276,6 +1298,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
12761298
12771299 ipv6 -> proto = * g_hc06ptr ;
12781300 ninfo ("Next header inline: %d\n" , ipv6 -> proto );
1301+ HC06_CHECK (g_hc06ptr , 1 , endofframe );
12791302 g_hc06ptr += 1 ;
12801303 }
12811304
@@ -1288,6 +1311,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
12881311 else
12891312 {
12901313 ipv6 -> ttl = * g_hc06ptr ;
1314+ HC06_CHECK (g_hc06ptr , 1 , endofframe );
12911315 g_hc06ptr += 1 ;
12921316 }
12931317
@@ -1301,7 +1325,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13011325 if (ret < 0 )
13021326 {
13031327 nerr ("ERROR: sixlowpan_extract_srcaddr failed: %d\n" , ret );
1304- return ;
1328+ return ret ;
13051329 }
13061330
13071331 if ((iphc1 & SIXLOWPAN_IPHC_SAC ) != 0 )
@@ -1319,7 +1343,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13191343 if (addrcontext == NULL )
13201344 {
13211345 nerr ("ERROR: Address context not found\n" );
1322- return ;
1346+ return - ENOENT ;
13231347 }
13241348 }
13251349
@@ -1330,6 +1354,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13301354 * address.
13311355 */
13321356
1357+ /* Source address: worst case 16 bytes inline */
1358+
1359+ HC06_CHECK (g_hc06ptr , 16 , endofframe );
1360+
13331361 uncompress_addr (& addr ,
13341362 tmp != 0 ? addrcontext -> prefix : NULL ,
13351363 g_unc_ctxconf [tmp ], ipv6 -> srcipaddr );
@@ -1342,6 +1370,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13421370 * address.
13431371 */
13441372
1373+ /* Destination address: worst case 16 bytes inline */
1374+
1375+ HC06_CHECK (g_hc06ptr , 16 , endofframe );
1376+
13451377 uncompress_addr (& addr , g_llprefix , g_unc_llconf [tmp ],
13461378 ipv6 -> srcipaddr );
13471379 }
@@ -1359,7 +1391,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13591391 if (ret < 0 )
13601392 {
13611393 nerr ("ERROR: sixlowpan_extract_srcaddr failed: %d\n" , ret );
1362- return ;
1394+ return ret ;
13631395 }
13641396
13651397 if ((iphc1 & SIXLOWPAN_IPHC_M ) != 0 )
@@ -1388,6 +1420,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
13881420 if (tmp > 0 && tmp < 3 )
13891421 {
13901422 prefix [1 ] = * g_hc06ptr ;
1423+ HC06_CHECK (g_hc06ptr , 1 , endofframe );
13911424 g_hc06ptr ++ ;
13921425 }
13931426
@@ -1415,7 +1448,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
14151448 if (addrcontext == NULL )
14161449 {
14171450 nerr ("ERROR: Address context not found\n" );
1418- return ;
1451+ return - ENOENT ;
14191452 }
14201453
14211454 uncompress_addr (& addr , addrcontext -> prefix , g_unc_ctxconf [tmp ],
@@ -1456,6 +1489,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
14561489 {
14571490 case SIXLOWPAN_NHC_UDP_CS_P_00 :
14581491
1492+ HC06_CHECK (g_hc06ptr , 5 , endofframe );
1493+
14591494 /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */
14601495
14611496 memcpy (& udp -> srcport , g_hc06ptr + 1 , 2 );
@@ -1469,6 +1504,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
14691504
14701505 case SIXLOWPAN_NHC_UDP_CS_P_01 :
14711506
1507+ HC06_CHECK (g_hc06ptr , 4 , endofframe );
1508+
14721509 /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit
14731510 * inline
14741511 */
@@ -1487,6 +1524,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
14871524
14881525 case SIXLOWPAN_NHC_UDP_CS_P_10 :
14891526
1527+ HC06_CHECK (g_hc06ptr , 4 , endofframe );
1528+
14901529 /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit
14911530 * inline
14921531 */
@@ -1505,6 +1544,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
15051544
15061545 case SIXLOWPAN_NHC_UDP_CS_P_11 :
15071546
1547+ HC06_CHECK (g_hc06ptr , 2 , endofframe );
1548+
15081549 /* 1 byte for NHC, 1 byte for ports */
15091550
15101551 udp -> srcport =
@@ -1522,7 +1563,7 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
15221563
15231564 default :
15241565 nerr ("ERROR: Error unsupported UDP compression\n" );
1525- return ;
1566+ return - EINVAL ;
15261567 }
15271568
15281569 if (!checksum_compressed )
@@ -1571,6 +1612,8 @@ void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
15711612 (FAR struct udp_hdr_s * )(bptr + IPv6_HDRLEN );
15721613 memcpy (& udp -> udplen , & ipv6 -> len [0 ], 2 );
15731614 }
1615+
1616+ return OK ;
15741617}
15751618
15761619#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */
0 commit comments