Skip to content

Commit 97a50ea

Browse files
committed
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 <acassis@gmail.com>
1 parent 805169c commit 97a50ea

3 files changed

Lines changed: 65 additions & 16 deletions

File tree

net/sixlowpan/sixlowpan_hc06.c

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@
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 */

net/sixlowpan/sixlowpan_input.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,8 +457,14 @@ static int sixlowpan_frame_process(FAR struct radio_driver_s *radio,
457457
SIXLOWPAN_DISPATCH_IPHC)
458458
{
459459
ninfo("IPHC Dispatch\n");
460-
sixlowpan_uncompresshdr_hc06(radio, metadata,
461-
fragsize, iob, fptr, bptr);
460+
ret = sixlowpan_uncompresshdr_hc06(radio, metadata,
461+
fragsize, iob, fptr, bptr);
462+
if (ret < 0)
463+
{
464+
nerr("ERROR: HC06 header decompress failed, dropping frame: %d\n",
465+
ret);
466+
goto errout_with_reass;
467+
}
462468
}
463469
else
464470
#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */

net/sixlowpan/sixlowpan_internal.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,10 @@ int sixlowpan_compresshdr_hc06(FAR struct radio_driver_s *radio,
495495
****************************************************************************/
496496

497497
#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
498-
void sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
499-
FAR const void *metadata,
500-
uint16_t iplen, FAR struct iob_s *iob,
501-
FAR uint8_t *fptr, FAR uint8_t *bptr);
498+
int sixlowpan_uncompresshdr_hc06(FAR struct radio_driver_s *radio,
499+
FAR const void *metadata,
500+
uint16_t iplen, FAR struct iob_s *iob,
501+
FAR uint8_t *fptr, FAR uint8_t *bptr);
502502
#endif
503503

504504
/****************************************************************************

0 commit comments

Comments
 (0)