Skip to content

Commit c6fa778

Browse files
rawalexearchigup
authored andcommitted
Validate RA prefix length bounds
FreeRTOS_CreateIPv6Address() uses the RA-supplied prefix length as a memcpy size: (uxPrefixLength + 7) / 8. With a prefix length > 128, this exceeds the 16-byte IPv6 address buffer. Validate prefix length in both vReceiveRA() and FreeRTOS_CreateIPv6Address() before use.
1 parent 5ed13a2 commit c6fa778

3 files changed

Lines changed: 53 additions & 23 deletions

File tree

source/FreeRTOS_ND.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,30 +1361,52 @@
13611361
/* A loopback IP-address has a prefix of 128. */
13621362
configASSERT( ( uxPrefixLength > 0U ) && ( uxPrefixLength <= ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) );
13631363

1364-
if( uxPrefixLength >= 8U )
1364+
if( ( uxPrefixLength == 0U ) || ( uxPrefixLength > ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) )
1365+
{
1366+
FreeRTOS_printf( ( "Invalid prefix length %u\n",
1367+
( unsigned ) uxPrefixLength ) );
1368+
xResult = pdFAIL;
1369+
}
1370+
else if( uxPrefixLength >= 8U )
13651371
{
13661372
( void ) memcpy( pxIPAddress->ucBytes, pxPrefix->ucBytes, ( uxPrefixLength + 7U ) / 8U );
13671373
}
1368-
1369-
pucSource = ( uint8_t * ) pulRandom;
1370-
uxIndex = uxPrefixLength / 8U;
1371-
1372-
if( ( uxPrefixLength % 8U ) != 0U )
1374+
else
13731375
{
1374-
/* uxHostLen is between 1 and 7 bits long. */
1375-
size_t uxHostLen = 8U - ( uxPrefixLength % 8U );
1376-
uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
1377-
uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
1378-
1379-
pxIPAddress->ucBytes[ uxIndex ] &= ucNetMask;
1380-
pxIPAddress->ucBytes[ uxIndex ] |= ( pucSource[ 0 ] & ( ( uint8_t ) uxHostMask ) );
1381-
pucSource = &( pucSource[ 1 ] );
1382-
uxIndex++;
1376+
/* No bytes to copy for prefix lengths less than 8. */
1377+
FreeRTOS_printf( ( "Prefix length %u < 8, no full bytes to copy\n",
1378+
( unsigned ) uxPrefixLength ) );
13831379
}
13841380

1385-
if( uxIndex < ipSIZE_OF_IPv6_ADDRESS )
1381+
if( xResult == pdPASS )
13861382
{
1387-
( void ) memcpy( &( pxIPAddress->ucBytes[ uxIndex ] ), pucSource, ipSIZE_OF_IPv6_ADDRESS - uxIndex );
1383+
pucSource = ( uint8_t * ) pulRandom;
1384+
uxIndex = uxPrefixLength / 8U;
1385+
1386+
/*
1387+
When uxPrefixLength is 128, uxIndex is calculated as 128 / 8 = 16,
1388+
which is past the end of the 16-byte ucBytes array (valid indices 0-15).
1389+
Add bounds check before writing to ucBytes[uxIndex] in the partial-byte
1390+
prefix block.
1391+
*/
1392+
if((( uxPrefixLength % 8U ) != 0U ) && ( uxIndex < ipSIZE_OF_IPv6_ADDRESS ))
1393+
{
1394+
1395+
/* uxHostLen is between 1 and 7 bits long. */
1396+
size_t uxHostLen = 8U - ( uxPrefixLength % 8U );
1397+
uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
1398+
uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
1399+
1400+
pxIPAddress->ucBytes[ uxIndex ] &= ucNetMask;
1401+
pxIPAddress->ucBytes[ uxIndex ] |= ( pucSource[ 0 ] & ( ( uint8_t ) uxHostMask ) );
1402+
pucSource = &( pucSource[ 1 ] );
1403+
uxIndex++;
1404+
}
1405+
1406+
if( uxIndex < ipSIZE_OF_IPv6_ADDRESS )
1407+
{
1408+
( void ) memcpy( &( pxIPAddress->ucBytes[ uxIndex ] ), pucSource, ipSIZE_OF_IPv6_ADDRESS - uxIndex );
1409+
}
13881410
}
13891411
}
13901412

source/FreeRTOS_RA.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,14 @@
425425
{
426426
if( ( pxEndPoint->bits.bWantRA != ipFALSE_BOOL ) && ( pxEndPoint->xRAData.eRAState == eRAStateWait ) )
427427
{
428+
if( ( pxPrefixOption->ucPrefixLength == 0U ) ||
429+
( pxPrefixOption->ucPrefixLength > ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) )
430+
{
431+
FreeRTOS_printf( ( "vReceiveRA: The prefix length "
432+
"is invalid\n" ) );
433+
break;
434+
}
435+
428436
pxEndPoint->ipv6_settings.uxPrefixLength = pxPrefixOption->ucPrefixLength;
429437
( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxPrefixOption->ucPrefix, ipSIZE_OF_IPv6_ADDRESS );
430438
( void ) memcpy( pxEndPoint->ipv6_settings.xGatewayAddress.ucBytes, pxICMPPacket->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );

test/unit-test/FreeRTOS_RA/FreeRTOS_RA_utest.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,14 +892,14 @@ void test_vReceiveRA_vRAProccess( void )
892892
pxNetworkBuffer = &xNetworkBuffer;
893893
pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket;
894894
pxNetworkBuffer->pxInterface = &xInterface;
895-
pxNetworkBuffer->xDataLength = raHeaderBytesRA + raPrefixOptionlen;
895+
pxNetworkBuffer->xDataLength = raHeaderBytesRA + sizeof( ICMPPrefixOption_IPv6_t );
896896
pxAdvertisement = &xICMPPacket.xAdvertisement;
897897
pxAdvertisement->usLifetime = pdTRUE_UNSIGNED;
898898

899899
pxPrefixOption = &xICMPPacket.xPrefixOption;
900900
pxPrefixOption->ucType = ndICMP_PREFIX_INFORMATION;
901-
/* Only 1 option */
902-
pxPrefixOption->ucLength = 1;
901+
pxPrefixOption->ucLength = 4;
902+
pxPrefixOption->ucPrefixLength = 64;
903903

904904
pxEndPoint->bits.bWantRA = pdTRUE_UNSIGNED;
905905

@@ -929,14 +929,14 @@ void test_vReceiveRA_vRAProcess( void )
929929
pxNetworkBuffer = &xNetworkBuffer;
930930
pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket;
931931
pxNetworkBuffer->pxInterface = &xInterface;
932-
pxNetworkBuffer->xDataLength = raHeaderBytesRA + raPrefixOptionlen;
932+
pxNetworkBuffer->xDataLength = raHeaderBytesRA + sizeof( ICMPPrefixOption_IPv6_t );
933933
pxAdvertisement = &xICMPPacket.xAdvertisement;
934934
pxAdvertisement->usLifetime = pdTRUE_UNSIGNED;
935935

936936
pxPrefixOption = &xICMPPacket.xPrefixOption;
937937
pxPrefixOption->ucType = ndICMP_PREFIX_INFORMATION;
938-
/* Only 1 option */
939-
pxPrefixOption->ucLength = 1;
938+
pxPrefixOption->ucLength = 4;
939+
pxPrefixOption->ucPrefixLength = 64;
940940

941941

942942
pxEndPoint->bits.bWantRA = pdTRUE_UNSIGNED;

0 commit comments

Comments
 (0)