Skip to content

Commit 38ff200

Browse files
committed
Fix integer wrap around when IPv6 payload length is malformed
1 parent eb4f8bb commit 38ff200

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

source/FreeRTOS_IPv6_Utils.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ BaseType_t prvChecksumIPv6Checks( uint8_t * pucEthernetBuffer,
9292
{
9393
uxExtensionHeaderLength = usGetExtensionHeaderLength( pucEthernetBuffer, uxBufferLength, &pxSet->ucProtocol );
9494

95-
if( uxExtensionHeaderLength >= uxBufferLength )
95+
if( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtensionHeaderLength >= uxBufferLength )
9696
{
9797
/* Error detected when parsing extension header. */
9898
pxSet->usChecksum = ipINVALID_LENGTH;
@@ -108,7 +108,16 @@ BaseType_t prvChecksumIPv6Checks( uint8_t * pucEthernetBuffer,
108108
pxSet->pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtensionHeaderLength ] ) );
109109
pxSet->usPayloadLength = FreeRTOS_ntohs( pxSet->pxIPPacket_IPv6->usPayloadLength );
110110
/* For IPv6, the number of bytes in the protocol is indicated. */
111-
pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength );
111+
if( pxSet->usPayloadLength < uxExtensionHeaderLength )
112+
{
113+
/* Invalid payload length - extension headers exceed payload. */
114+
pxSet->usChecksum = ipINVALID_LENGTH;
115+
xReturn = 4;
116+
}
117+
else
118+
{
119+
pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength );
120+
}
112121

113122
uxNeeded = ( size_t ) pxSet->usPayloadLength;
114123
uxNeeded += ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER;

test/cbmc/proofs/prvChecksumIPv6Checks/prvChecksumIPv6Checks_harness.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,27 @@ void harness()
2121
size_t uxBufferSize;
2222
uint8_t * pucEthernetBuffer;
2323
struct xPacketSummary xSet;
24+
BaseType_t xReturn;
2425

2526
/* We must have ethernet header to get frame type. */
2627
__CPROVER_assume( uxBufferSize >= sizeof( IPPacket_IPv6_t ) && uxBufferSize <= ipconfigNETWORK_MTU );
2728

2829
/* Ethernet buffer is not possible to be NULL. */
2930
pucEthernetBuffer = ( uint8_t * ) safeMalloc( uxBufferSize );
3031
__CPROVER_assume( pucEthernetBuffer != NULL );
32+
__CPROVER_havoc_object( pucEthernetBuffer );
3133

3234
/* This is set before calling prvChecksumIPv6Checks. */
3335
xSet.pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;
3436
xSet.pxIPPacket_IPv6 = ( const IPHeader_IPv6_t * ) ( pucEthernetBuffer + ipSIZE_OF_ETH_HEADER );
3537

36-
prvChecksumIPv6Checks( pucEthernetBuffer,
38+
xReturn = prvChecksumIPv6Checks( pucEthernetBuffer,
3739
uxBufferSize,
3840
&xSet );
41+
42+
if( xReturn == 0 )
43+
{
44+
__CPROVER_assert( ( xSet.usProtocolBytes <= FreeRTOS_ntohs( xSet.pxIPPacket_IPv6->usPayloadLength ) ), "xSet.usProtocolBytes shouldn't be greater than IPv6 usPayloadLength" );
45+
}
46+
3947
}

test/unit-test/FreeRTOS_IPv6_Utils/FreeRTOS_IPv6_Utils_utest.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void test_prvChecksumIPv6Checks_IncompleteIPv6Packet( void )
131131
BaseType_t usReturn;
132132
uint8_t pucEthernetBuffer[ ipconfigTCPv6_MSS ];
133133
IPHeader_IPv6_t * pxIPv6Packet;
134-
size_t uxBufferLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER;
134+
size_t uxBufferLength = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + 4;
135135
struct xPacketSummary xSet;
136136

137137
memset( pucEthernetBuffer, 0, ipconfigTCPv6_MSS );
@@ -205,6 +205,46 @@ void test_prvChecksumIPv6Checks_LargeExtensionHeader( void )
205205
TEST_ASSERT_EQUAL( 3, usReturn );
206206
}
207207

208+
/**
209+
* @brief Prepare a packet with large extension header length.
210+
* - ipIPv6_EXT_HEADER_ROUTING_HEADER
211+
* - ipIPv6_EXT_HEADER_HOP_BY_HOP
212+
* - ipPROTOCOL_TCP
213+
*/
214+
void test_prvChecksumIPv6Checks_IncorrectPayloadLength( void )
215+
{
216+
BaseType_t usReturn;
217+
struct xPacketSummary xSet;
218+
NetworkBufferDescriptor_t * pxNetworkBuffer = prvInitializeNetworkDescriptorWithExtensionHeader( ipPROTOCOL_TCP );
219+
IPHeader_IPv6_t * pxIPv6Header = ( IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] );
220+
size_t uxIndex = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER;
221+
222+
/* Modify the extension header */
223+
pxIPv6Header->ucNextHeader = ipIPv6_EXT_HEADER_HOP_BY_HOP;
224+
pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] = ipIPv6_EXT_HEADER_ROUTING_HEADER;
225+
pxNetworkBuffer->pucEthernetBuffer[ uxIndex + 1 ] = 5U; /* Extension header length is set to 200*8 + 8, which is larger than buffer size. */
226+
uxIndex += 8;
227+
pxNetworkBuffer->pucEthernetBuffer[ uxIndex ] = ipPROTOCOL_TCP;
228+
pxNetworkBuffer->pucEthernetBuffer[ uxIndex + 1 ] = 0;
229+
uxIndex += 8;
230+
231+
xSet.pxIPPacket_IPv6 = ( ( const IPHeader_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
232+
IPHeader_IPv6_t * pxIPPacket_IPv6 = (IPHeader_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer;
233+
234+
/* Incorrect payload length */
235+
pxIPPacket_IPv6->usPayloadLength = FreeRTOS_ntohs(20);
236+
237+
xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_HOP_BY_HOP, 0U, 1 );
238+
xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_HOP_BY_HOP, ipIPv6_EXT_HEADER_ROUTING_HEADER, 1 );
239+
xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_ROUTING_HEADER, ipPROTOCOL_TCP, 2 );
240+
xGetExtensionOrder_ExpectAndReturn( ipIPv6_EXT_HEADER_ROUTING_HEADER, ipPROTOCOL_TCP, 2 );
241+
242+
usReturn = prvChecksumIPv6Checks( pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength, &xSet );
243+
244+
TEST_ASSERT_EQUAL( 4, usReturn );
245+
}
246+
247+
208248
/**
209249
* @brief Prepare a packet have extension with following order.
210250
* - ipIPv6_EXT_HEADER_ROUTING_HEADER

0 commit comments

Comments
 (0)