Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ jobs:
exclude-dirs: source/portable/NetworkInterface/STM32

formatting:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check formatting
Expand Down
10 changes: 10 additions & 0 deletions History.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
Documentation and download available at https://www.FreeRTOS.org/

Changes between FreeRTOS-plus-TCP V4.3.2 and V4.3.1 released June 03, 2025:
+ It was possible to cause an out-of-bounds write when processing LLMNR
or mDNS queries with very long DNS names. This issue only affects systems
using Buffer Allocation Scheme 1 with LLMNR or mDNS enabled.
This issue has been fixed by adding checks to prevent out of bounds write.
We would like to thank Paschal Amusuo (@AmPaschal),
James C Davis (@davisjam), Taylor Le Lievre (@tlelievre26), and
Aravind Kumar Machiry (@machiry) of Purdue University for collaborating
on this issue through the coordinated vulnerability disclosure process.

Changes between FreeRTOS-plus-TCP V4.3.1 and V4.3.0 released December 16, 2024:
+ Update README.md with information related to migrating to V4.3.0 and above
for users utilising the STM32 network interface.
Expand Down
2 changes: 1 addition & 1 deletion docs/doxygen/config.doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ PROJECT_NAME = FreeRTOS-Plus-TCP
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = V4.3.0
PROJECT_NUMBER = V4.3.2

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion manifest.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "FreeRTOS-Plus-TCP"
version: "V4.3.1"
version: "V4.3.2"
description:
"Thread safe FreeRTOS TCP/IP stack working on top of the FreeRTOS-Kernel to
implement the TCP/IP protocol. Suitable for microcontrollers."
Expand Down
59 changes: 36 additions & 23 deletions source/FreeRTOS_DNS_Parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,31 +486,30 @@
LLMNRAnswer_t * pxAnswer;
uint8_t * pucNewBuffer = NULL;
size_t uxExtraLength;
size_t uxDataLength = uxBufferLength +
sizeof( UDPHeader_t ) +
sizeof( EthernetHeader_t ) +
uxIPHeaderSizePacket( pxNetworkBuffer );

if( xBufferAllocFixedSize == pdFALSE )
{
size_t uxDataLength = uxBufferLength +
sizeof( UDPHeader_t ) +
sizeof( EthernetHeader_t ) +
uxIPHeaderSizePacket( pxNetworkBuffer );

#if ( ipconfigUSE_IPv6 != 0 )
if( xSet.usType == dnsTYPE_AAAA_HOST )
{
uxExtraLength = sizeof( LLMNRAnswer_t ) + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress );
}
else
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
{
uxExtraLength = sizeof( LLMNRAnswer_t );
}
#else /* ( ipconfigUSE_IPv4 != 0 ) */
#if ( ipconfigUSE_IPv6 != 0 )
if( xSet.usType == dnsTYPE_AAAA_HOST )
{
/* do nothing, coverity happy */
uxExtraLength = sizeof( LLMNRAnswer_t ) + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress );
}
#endif /* ( ipconfigUSE_IPv4 != 0 ) */
else
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
{
uxExtraLength = sizeof( LLMNRAnswer_t );
}
#else /* ( ipconfigUSE_IPv4 != 0 ) */
{
/* do nothing, coverity happy */
}
#endif /* ( ipconfigUSE_IPv4 != 0 ) */

if( xBufferAllocFixedSize == pdFALSE )
{
/* Set the size of the outgoing packet. */
pxNetworkBuffer->xDataLength = uxDataLength;
pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer,
Expand Down Expand Up @@ -539,7 +538,17 @@
}
else
{
pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ uxUDPOffset ] );
/* When xBufferAllocFixedSize is TRUE, check if the buffer size is big enough to
* store the answer. */
if( ( uxDataLength + uxExtraLength ) <= ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER )
{
pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ uxUDPOffset ] );
}
else
{
/* Just to indicate that the message may not be answered. */
pxNetworkBuffer = NULL;
}
}

if( ( pxNetworkBuffer != NULL ) )
Expand Down Expand Up @@ -1210,7 +1219,11 @@
{
/* BufferAllocation_1.c is used, the Network Buffers can contain at least
* ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER. */
configASSERT( uxSizeNeeded < ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER );
if( uxSizeNeeded > ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) )
{
/* The buffer is too small to reply. Drop silently. */
break;
}
}

pxNetworkBuffer->xDataLength = uxSizeNeeded;
Expand Down
23 changes: 14 additions & 9 deletions source/portable/BufferManagement/BufferAllocation_1.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,8 @@ NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedS
BaseType_t xInvalid = pdFALSE;
UBaseType_t uxCount;

/* The current implementation only has a single size memory block, so
* the requested size parameter is not used (yet). */
( void ) xRequestedSizeBytes;

if( xNetworkBufferSemaphore != NULL )
if( ( xNetworkBufferSemaphore != NULL ) &&
( xRequestedSizeBytes <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) )
{
/* If there is a semaphore available, there is a network buffer
* available. */
Expand Down Expand Up @@ -432,10 +429,18 @@ UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
size_t xNewSizeBytes )
{
/* In BufferAllocation_1.c all network buffer are allocated with a
* maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
* network buffer. */
pxNetworkBuffer->xDataLength = xNewSizeBytes;
if( xNewSizeBytes <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) )
{
/* In BufferAllocation_1.c all network buffer are allocated with a
* maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the
* network buffer. */
pxNetworkBuffer->xDataLength = xNewSizeBytes;
}
else
{
pxNetworkBuffer = NULL;
}

return pxNetworkBuffer;
}

Expand Down
5 changes: 1 addition & 4 deletions test/cbmc/proofs/DNS/DNSTreatNBNS/DNS_TreatNBNS_harness.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,7 @@ void harness()

BaseType_t xDataSize;

/* When re-adjusting the buffer, (sizeof( NBNSAnswer_t ) - 2 * sizeof( uint16_t )) more bytes are
* required to be added to the existing buffer. Make sure total bytes doesn't exceed ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER
* when re-resizing. This will prevent hitting an assert if Buffer Allocation 1 is used. */
__CPROVER_assume( ( xDataSize != 0 ) && ( xDataSize < ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER - ( sizeof( NBNSAnswer_t ) - 2 * sizeof( uint16_t ) ) ) ) );
__CPROVER_assume( ( xDataSize > 0 ) && ( xDataSize < ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) );

xNetworkBuffer.pucEthernetBuffer = safeMalloc( xDataSize );
xNetworkBuffer.xDataLength = xDataSize;
Expand Down
3 changes: 2 additions & 1 deletion test/cbmc/proofs/DNS/DNSTreatNBNS/Makefile.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"DEF":
[
"ipconfigUSE_DNS_CACHE={USE_CACHE}",
"ipconfigUSE_NBNS=1"
"ipconfigUSE_NBNS=1",
"ipconfigNETWORK_MTU=586"
]
}
72 changes: 58 additions & 14 deletions test/cbmc/proofs/DNS_ParseDNSReply/Configurations.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"ENTRY": "DNS_ParseDNSReply",
"TEST_PAYLOAD_SIZE": 2,
"TEST_IPV4_PACKET_SIZE": 29,
"TEST_IPV6_PACKET_SIZE": 49,
"TEST_MAX_TEST_UNWIND_LOOP": 8,
"TEST_MIN_TEST_DNS_HEADER": 12,
"TEST_MIN_IPV4_UDP_PACKET_SIZE": 42,
"TEST_MIN_IPV6_UDP_PACKET_SIZE": 62,
"TEST_IPV4_NETWORK_MTU": "__eval {TEST_MIN_IPV4_UDP_PACKET_SIZE} + {TEST_MIN_TEST_DNS_HEADER} + {TEST_MAX_TEST_UNWIND_LOOP}",
"TEST_IPV6_NETWORK_MTU": "__eval {TEST_MIN_IPV6_UDP_PACKET_SIZE} + {TEST_MIN_TEST_DNS_HEADER} + {TEST_MAX_TEST_UNWIND_LOOP}",
"CBMCFLAGS":
[
"--unwind 1",
"--unwindset DNS_ParseDNSReply.0:{TEST_PAYLOAD_SIZE}",
"--unwindset DNS_ReadNameField.0:{TEST_PAYLOAD_SIZE}",
"--unwindset DNS_ReadNameField.1:{TEST_PAYLOAD_SIZE}",
"--unwindset parseDNSAnswer.0:{TEST_PAYLOAD_SIZE}",
"--unwindset strncpy.0:{TEST_PAYLOAD_SIZE}"
"--unwindset strlen.0:{TEST_MAX_TEST_UNWIND_LOOP}",
"--unwindset DNS_ParseDNSReply.0:{TEST_MAX_TEST_UNWIND_LOOP}",
"--unwindset DNS_ReadNameField.0:{TEST_MAX_TEST_UNWIND_LOOP}",
"--unwindset DNS_ReadNameField.1:{TEST_MAX_TEST_UNWIND_LOOP}"
],
"OPT":
[
Expand All @@ -25,21 +27,63 @@
"DEF":
[
{
"IPv4":
"IPv4_FixedNetworkBufferSize":
[
"TEST_PACKET_SIZE={TEST_IPV4_PACKET_SIZE}",
"TEST_MAX_PAYLOAD_SIZE={TEST_MAX_TEST_UNWIND_LOOP}",
"ipconfigUSE_LLMNR=1",
"ipconfigUSE_MDNS=1",
"IS_TESTING_IPV6=0"
"IS_TESTING_IPV6=0",
"IS_BUFFER_ALLOCATE_FIXED=1",
"ipconfigNETWORK_MTU={TEST_IPV4_NETWORK_MTU}",
"ipconfigUSE_TCP=0",
"ipconfigUSE_DHCP=0",
"ipconfigTCP_MSS=536",
"ipconfigDNS_CACHE_NAME_LENGTH={TEST_MAX_TEST_UNWIND_LOOP}"
]
},
{
"IPv6":
"IPv6_FixedNetworkBufferSize":
[
"TEST_PACKET_SIZE={TEST_IPV6_PACKET_SIZE}",
"TEST_MAX_PAYLOAD_SIZE={TEST_MAX_TEST_UNWIND_LOOP}",
"ipconfigUSE_LLMNR=1",
"ipconfigUSE_MDNS=1",
"IS_TESTING_IPV6=1"
"IS_TESTING_IPV6=1",
"IS_BUFFER_ALLOCATE_FIXED=1",
"ipconfigNETWORK_MTU={TEST_IPV6_NETWORK_MTU}",
"ipconfigUSE_TCP=0",
"ipconfigUSE_DHCP=0",
"ipconfigTCP_MSS=536",
"ipconfigDNS_CACHE_NAME_LENGTH={TEST_MAX_TEST_UNWIND_LOOP}"
]
},
{
"IPv4_DynamicNetworkBufferSize":
[
"TEST_MAX_PAYLOAD_SIZE={TEST_MAX_TEST_UNWIND_LOOP}",
"ipconfigUSE_LLMNR=1",
"ipconfigUSE_MDNS=1",
"IS_TESTING_IPV6=0",
"IS_BUFFER_ALLOCATE_FIXED=0",
"ipconfigNETWORK_MTU={TEST_IPV4_NETWORK_MTU}",
"ipconfigUSE_TCP=0",
"ipconfigUSE_DHCP=0",
"ipconfigTCP_MSS=536",
"ipconfigDNS_CACHE_NAME_LENGTH={TEST_MAX_TEST_UNWIND_LOOP}"
]
},
{
"IPv6_DynamicNetworkBufferSize":
[
"TEST_MAX_PAYLOAD_SIZE={TEST_MAX_TEST_UNWIND_LOOP}",
"ipconfigUSE_LLMNR=1",
"ipconfigUSE_MDNS=1",
"IS_TESTING_IPV6=1",
"IS_BUFFER_ALLOCATE_FIXED=0",
"ipconfigNETWORK_MTU={TEST_IPV6_NETWORK_MTU}",
"ipconfigUSE_TCP=0",
"ipconfigUSE_DHCP=0",
"ipconfigTCP_MSS=536",
"ipconfigDNS_CACHE_NAME_LENGTH={TEST_MAX_TEST_UNWIND_LOOP}"
]
}
],
Expand Down
43 changes: 31 additions & 12 deletions test/cbmc/proofs/DNS_ParseDNSReply/DNS_ParseDNSReply_harness.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@

/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_DNS.h"
#include "FreeRTOS_DNS_Parser.h"
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
#include "IPTraceMacroDefaults.h"

#include "cbmc.h"
#include "../../utility/memory_assignments.c"

const BaseType_t xBufferAllocFixedSize = IS_BUFFER_ALLOCATE_FIXED;

/****************************************************************
* Signature of function under test
Expand Down Expand Up @@ -60,12 +62,18 @@ NetworkBufferDescriptor_t * pxUDPPayloadBuffer_to_NetworkBuffer( const void * pv

uint32_t ulChar2u32( const uint8_t * pucPtr )
{
uint32_t ret;

__CPROVER_assert( __CPROVER_r_ok( pucPtr, 4 ), "must be 4 bytes legal address to read" );
return ret;
}

uint16_t usChar2u16( const uint8_t * pucPtr )
{
uint16_t ret;

__CPROVER_assert( __CPROVER_r_ok( pucPtr, 2 ), "must be 2 bytes legal address to read" );
return ret;
}

const char * FreeRTOS_inet_ntop( BaseType_t xAddressFamily,
Expand Down Expand Up @@ -131,11 +139,14 @@ NetworkBufferDescriptor_t * pxDuplicateNetworkBufferWithDescriptor( const Networ
{
NetworkBufferDescriptor_t * pxNetworkBuffer = safeMalloc( sizeof( NetworkBufferDescriptor_t ) );

if( ensure_memory_is_valid( pxNetworkBuffer, xNewLength ) )
if( pxNetworkBuffer != NULL )
{
pxNetworkBuffer->pucEthernetBuffer = safeMalloc( xNewLength );
__CPROVER_assume( pxNetworkBuffer->pucEthernetBuffer );
__CPROVER_assume( pxNetworkBuffer->pucEthernetBuffer != NULL );
pxNetworkBuffer->xDataLength = xNewLength;

pxNetworkBuffer->pxEndPoint = safeMalloc( sizeof( NetworkEndPoint_t ) );
__CPROVER_assume( pxNetworkBuffer->pxEndPoint != NULL );
}

return pxNetworkBuffer;
Expand Down Expand Up @@ -176,23 +187,31 @@ void harness()
uint8_t * pPayloadBuffer;
size_t uxPayloadBufferLength;

__CPROVER_assert( TEST_PACKET_SIZE < CBMC_MAX_OBJECT_SIZE,
"TEST_PACKET_SIZE < CBMC_MAX_OBJECT_SIZE" );

__CPROVER_assume( uxBufferLength < CBMC_MAX_OBJECT_SIZE );
__CPROVER_assume( uxBufferLength <= TEST_PACKET_SIZE );
__CPROVER_assume( uxBufferLength <= ipconfigNETWORK_MTU );
__CPROVER_assume( pxNetworkEndPoint_Temp != NULL );

lIsIPv6Packet = IS_TESTING_IPV6;

xNetworkBuffer.pucEthernetBuffer = safeMalloc( uxBufferLength );
xNetworkBuffer.xDataLength = uxBufferLength;
xNetworkBuffer.pxEndPoint = pxNetworkEndPoint_Temp;
if( xBufferAllocFixedSize != pdFALSE )
{
/* When xBufferAllocFixedSize is true, buffers in all network descriptors
* is big enough to allow all Ethernet packet. */
xNetworkBuffer.pucEthernetBuffer = safeMalloc( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER );
xNetworkBuffer.xDataLength = uxBufferLength;
xNetworkBuffer.pxEndPoint = pxNetworkEndPoint_Temp;
}
else
{
xNetworkBuffer.pucEthernetBuffer = safeMalloc( uxBufferLength );
xNetworkBuffer.xDataLength = uxBufferLength;
xNetworkBuffer.pxEndPoint = pxNetworkEndPoint_Temp;
}

__CPROVER_assume( xNetworkBuffer.pucEthernetBuffer != NULL );

if( lIsIPv6Packet )
{
__CPROVER_assume( uxBufferLength >= ulIpv6UdpOffset ); /* 62 is total size of IPv4 UDP header, including ethernet, IPv6, UDP headers. */
__CPROVER_assume( uxBufferLength >= ulIpv6UdpOffset ); /* 62 is total size of IPv6 UDP header, including ethernet, IPv6, UDP headers. */
pPayloadBuffer = xNetworkBuffer.pucEthernetBuffer + ulIpv6UdpOffset;
uxPayloadBufferLength = uxBufferLength - ulIpv6UdpOffset;
}
Expand Down
Loading
Loading