Skip to content

Commit 8eb729c

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 9a2498b commit 8eb729c

3 files changed

Lines changed: 52 additions & 23 deletions

File tree

source/FreeRTOS_ND.c

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,30 +1342,51 @@
13421342
/* A loopback IP-address has a prefix of 128. */
13431343
configASSERT( ( uxPrefixLength > 0U ) && ( uxPrefixLength <= ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) );
13441344

1345-
if( uxPrefixLength >= 8U )
1345+
if( ( uxPrefixLength == 0U ) || ( uxPrefixLength > ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) )
1346+
{
1347+
FreeRTOS_printf( ( "Invalid prefix length %u\n",
1348+
( unsigned ) uxPrefixLength ) );
1349+
xResult = pdFAIL;
1350+
}
1351+
else if( uxPrefixLength >= 8U )
13461352
{
13471353
( void ) memcpy( pxIPAddress->ucBytes, pxPrefix->ucBytes, ( uxPrefixLength + 7U ) / 8U );
13481354
}
1349-
1350-
pucSource = ( uint8_t * ) pulRandom;
1351-
uxIndex = uxPrefixLength / 8U;
1352-
1353-
if( ( uxPrefixLength % 8U ) != 0U )
1355+
else
13541356
{
1355-
/* uxHostLen is between 1 and 7 bits long. */
1356-
size_t uxHostLen = 8U - ( uxPrefixLength % 8U );
1357-
uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
1358-
uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
1359-
1360-
pxIPAddress->ucBytes[ uxIndex ] &= ucNetMask;
1361-
pxIPAddress->ucBytes[ uxIndex ] |= ( pucSource[ 0 ] & ( ( uint8_t ) uxHostMask ) );
1362-
pucSource = &( pucSource[ 1 ] );
1363-
uxIndex++;
1357+
/* No bytes to copy for prefix lengths less than 8. */
1358+
FreeRTOS_printf( ( "Prefix length %u < 8, no full bytes to copy\n",
1359+
( unsigned ) uxPrefixLength ) );
13641360
}
13651361

1366-
if( uxIndex < ipSIZE_OF_IPv6_ADDRESS )
1362+
if( xResult == pdPASS )
13671363
{
1368-
( void ) memcpy( &( pxIPAddress->ucBytes[ uxIndex ] ), pucSource, ipSIZE_OF_IPv6_ADDRESS - uxIndex );
1364+
pucSource = ( uint8_t * ) pulRandom;
1365+
uxIndex = uxPrefixLength / 8U;
1366+
1367+
/*
1368+
* When uxPrefixLength is 128, uxIndex is calculated as 128 / 8 = 16,
1369+
* which is past the end of the 16-byte ucBytes array (valid indices 0-15).
1370+
* Add bounds check before writing to ucBytes[uxIndex] in the partial-byte
1371+
* prefix block.
1372+
*/
1373+
if( ( ( uxPrefixLength % 8U ) != 0U ) && ( uxIndex < ipSIZE_OF_IPv6_ADDRESS ) )
1374+
{
1375+
/* uxHostLen is between 1 and 7 bits long. */
1376+
size_t uxHostLen = 8U - ( uxPrefixLength % 8U );
1377+
uint32_t uxHostMask = ( ( ( uint32_t ) 1U ) << uxHostLen ) - 1U;
1378+
uint8_t ucNetMask = ( uint8_t ) ~( uxHostMask );
1379+
1380+
pxIPAddress->ucBytes[ uxIndex ] &= ucNetMask;
1381+
pxIPAddress->ucBytes[ uxIndex ] |= ( pucSource[ 0 ] & ( ( uint8_t ) uxHostMask ) );
1382+
pucSource = &( pucSource[ 1 ] );
1383+
uxIndex++;
1384+
}
1385+
1386+
if( uxIndex < ipSIZE_OF_IPv6_ADDRESS )
1387+
{
1388+
( void ) memcpy( &( pxIPAddress->ucBytes[ uxIndex ] ), pucSource, ipSIZE_OF_IPv6_ADDRESS - uxIndex );
1389+
}
13691390
}
13701391
}
13711392

source/FreeRTOS_RA.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,14 @@
424424
{
425425
if( ( pxEndPoint->bits.bWantRA != pdFALSE_UNSIGNED ) && ( pxEndPoint->xRAData.eRAState == eRAStateWait ) )
426426
{
427+
if( ( pxPrefixOption->ucPrefixLength == 0U ) ||
428+
( pxPrefixOption->ucPrefixLength > ( 8U * ipSIZE_OF_IPv6_ADDRESS ) ) )
429+
{
430+
FreeRTOS_printf( ( "vReceiveRA: The prefix length "
431+
"is invalid\n" ) );
432+
break;
433+
}
434+
427435
pxEndPoint->ipv6_settings.uxPrefixLength = pxPrefixOption->ucPrefixLength;
428436
( void ) memcpy( pxEndPoint->ipv6_settings.xPrefix.ucBytes, pxPrefixOption->ucPrefix, ipSIZE_OF_IPv6_ADDRESS );
429437
( 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
@@ -894,14 +894,14 @@ void test_vReceiveRA_vRAProccess( void )
894894
pxNetworkBuffer = &xNetworkBuffer;
895895
pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket;
896896
pxNetworkBuffer->pxInterface = &xInterface;
897-
pxNetworkBuffer->xDataLength = raHeaderBytesRA + raPrefixOptionlen;
897+
pxNetworkBuffer->xDataLength = raHeaderBytesRA + sizeof( ICMPPrefixOption_IPv6_t );
898898
pxAdvertisement = &xICMPPacket.xAdvertisement;
899899
pxAdvertisement->usLifetime = pdTRUE_UNSIGNED;
900900

901901
pxPrefixOption = &xICMPPacket.xPrefixOption;
902902
pxPrefixOption->ucType = ndICMP_PREFIX_INFORMATION;
903-
/* Only 1 option */
904-
pxPrefixOption->ucLength = 1;
903+
pxPrefixOption->ucLength = 4;
904+
pxPrefixOption->ucPrefixLength = 64;
905905

906906
pxEndPoint->bits.bWantRA = pdTRUE_UNSIGNED;
907907

@@ -931,14 +931,14 @@ void test_vReceiveRA_vRAProcess( void )
931931
pxNetworkBuffer = &xNetworkBuffer;
932932
pxNetworkBuffer->pucEthernetBuffer = ( uint8_t * ) &xICMPPacket;
933933
pxNetworkBuffer->pxInterface = &xInterface;
934-
pxNetworkBuffer->xDataLength = raHeaderBytesRA + raPrefixOptionlen;
934+
pxNetworkBuffer->xDataLength = raHeaderBytesRA + sizeof( ICMPPrefixOption_IPv6_t );
935935
pxAdvertisement = &xICMPPacket.xAdvertisement;
936936
pxAdvertisement->usLifetime = pdTRUE_UNSIGNED;
937937

938938
pxPrefixOption = &xICMPPacket.xPrefixOption;
939939
pxPrefixOption->ucType = ndICMP_PREFIX_INFORMATION;
940-
/* Only 1 option */
941-
pxPrefixOption->ucLength = 1;
940+
pxPrefixOption->ucLength = 4;
941+
pxPrefixOption->ucPrefixLength = 64;
942942

943943

944944
pxEndPoint->bits.bWantRA = pdTRUE_UNSIGNED;

0 commit comments

Comments
 (0)