Skip to content

Commit f6af2b5

Browse files
[V4.2.5] Fix Buffer Over-read (CWE-126), Null Pointer Dereference (CWE-476) and Invalid Pointer Dereference (CWE-822) (#1295)
* Intial version with UTs fixed * Fix missing check for IPv6 version field * Fix integer wrap around when IPv6 payload length is malformed * Fix spell check * Fix unit test CI * Fix formatting * Minor fix * Fix MISRA issues * CI update * Fix formatting * Fix release * [V4.2.5] release notes and version updates * Fix formatting * Update History.txt
1 parent af8dc64 commit f6af2b5

File tree

14 files changed

+523
-190
lines changed

14 files changed

+523
-190
lines changed

.github/workflows/release-candidate.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ on:
1010
description: 'Release Version Number (Eg, v1.0.0-rc1)'
1111
required: true
1212

13+
# Workflow permissions block
14+
permissions:
15+
contents: write # This grants write access to repository content, including pushing commits/tags and creating releases.
16+
1317
jobs:
1418
tag-commit:
1519
name: Tag commit
@@ -32,4 +36,4 @@ jobs:
3236
git tag -d ${{ github.event.inputs.version_number }}
3337
git remote update
3438
git checkout tags/${{ github.event.inputs.version_number }}
35-
git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}
39+
git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}

.github/workflows/release.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ on:
1010
description: 'Release Version Number (Eg, v1.0.0)'
1111
required: true
1212

13+
# Workflow permissions block
14+
permissions:
15+
contents: write # This grants write access to repository content, including pushing commits/tags and creating releases.
16+
1317
jobs:
1418
tag-commit:
1519
name: Tag commit
@@ -140,6 +144,9 @@ jobs:
140144
ref: ${{ github.event.inputs.version_number }}
141145
add_release: "true"
142146
create-release:
147+
permissions:
148+
contents: write
149+
id-token: write
143150
needs:
144151
- create-zip
145152
- deploy-doxygen
@@ -171,6 +178,11 @@ jobs:
171178
asset_path: ./FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip
172179
asset_name: FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip
173180
asset_content_type: application/zip
181+
- name: Backup Release Asset
182+
uses: FreeRTOS/CI-CD-Github-Actions/artifact-backup@main
183+
with:
184+
artifact_path: ./FreeRTOS-Plus-TCP-${{ github.event.inputs.version_number }}.zip
185+
release_tag: ${{ github.event.inputs.version_number }}
174186
cleanup:
175187
needs:
176188
- create-release

History.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
Documentation and download available at https://www.FreeRTOS.org/
22

3+
Changes between FreeRTOS-plus-TCP V4.2.5 and V4.2.4 released October 10, 2025:
4+
+ The implementation lacked sufficient checks to ensure that received packets
5+
meet the minimum size requirements for certain ICMPv6 message types, leading to
6+
out-of-bounds read operations when processing packets smaller than the expected
7+
size. This issue has been fixed by adding checks to prevent out-of-bounds reads.
8+
The implementation lacked sufficient checks to prevent null pointer dereference
9+
when an IPv6 multicast packet is received on a device not configured with a
10+
link-local endpoint. This issue has been fixed by adding checks to prevent
11+
null pointer dereference.
12+
+ The implementation lacked sufficient checks to validate the payload length field
13+
in the IPv6 packet header. This allowed malicious packets with incorrect payload
14+
lengths to cause integer wraparound, resulting in erroneously large calculated
15+
payload length. This inflated payload length bypassed the existing
16+
bounds-checking mechanisms, leading to out-of-bounds read operations. This issue
17+
has been fixed by adding checks to validate the payload length field in the IPv6
18+
packet header.
19+
+ The implementation lacked sufficient checks to validate the IP version field
20+
when a UDP/IPv6 packet is received with ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
21+
disabled. This allowed the processing of packets with an incorrect IP version
22+
field instead of rejecting them early. Subsequent attempts to extract network
23+
buffers from these invalid UDP packets could result in dereferencing of an
24+
invalid pointer due to incorrect pointer arithmetic.
25+
We would like to thank Ivan Gotovchits of Mayhem Security for collaborating on
26+
this issue through the coordinated vulnerability disclosure process.
27+
328
Changes between FreeRTOS-plus-TCP V4.2.4 and V4.2.3 released June 10, 2025:
429
+ Fixed maximum network buffer allocation size check when buffer
530
allocation scheme 1 is used which caused allocation failure on

docs/doxygen/config.doxyfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ PROJECT_NAME = FreeRTOS-Plus-TCP
4848
# could be handy for archiving the generated documentation or if some version
4949
# control system is used.
5050

51-
PROJECT_NUMBER = V4.2.4
51+
PROJECT_NUMBER = V4.2.5
5252

5353
# Using the PROJECT_BRIEF tag one can provide an optional one line description
5454
# for a project that appears at the top of each page and should give viewer a

manifest.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: "FreeRTOS-Plus-TCP"
2-
version: "V4.2.4"
2+
version: "V4.2.5"
33
description:
44
"Thread safe FreeRTOS TCP/IP stack working on top of the FreeRTOS-Kernel to
55
implement the TCP/IP protocol. Suitable for microcontrollers."

source/FreeRTOS_IPv6.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ const struct xIPv6_Address FreeRTOS_in6addr_loopback = { { 0U, 0U, 0U, 0U, 0U, 0
9393
size_t uxBufferLength )
9494
{
9595
BaseType_t xResult = pdFAIL;
96-
uint16_t ucVersionTrafficClass;
9796
uint16_t usPayloadLength;
9897
uint8_t ucNextHeader;
9998
size_t uxMinimumLength;
@@ -116,15 +115,6 @@ const struct xIPv6_Address FreeRTOS_in6addr_loopback = { { 0U, 0U, 0U, 0U, 0U, 0
116115
break;
117116
}
118117

119-
ucVersionTrafficClass = pxIPv6Packet->xIPHeader.ucVersionTrafficClass;
120-
121-
/* Test if the IP-version is 6. */
122-
if( ( ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) != 6U )
123-
{
124-
DEBUG_SET_TRACE_VARIABLE( xLocation, 2 );
125-
break;
126-
}
127-
128118
/* Check if the IPv6-header is transferred. */
129119
if( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ) )
130120
{
@@ -497,6 +487,7 @@ eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxI
497487
const IPv6_Address_t * pxDestinationIPAddress = &( pxIPv6Header->xDestinationAddress );
498488
const IPv6_Address_t * pxSourceIPAddress = &( pxIPv6Header->xSourceAddress );
499489
BaseType_t xHasUnspecifiedAddress = pdFALSE;
490+
uint16_t ucVersionTrafficClass = pxIPv6Header->ucVersionTrafficClass;
500491

501492
/* Drop if packet has unspecified IPv6 address (defined in RFC4291 - sec 2.5.2)
502493
* either in source or destination address. */
@@ -506,10 +497,17 @@ eFrameProcessingResult_t prvAllowIPPacketIPv6( const IPHeader_IPv6_t * const pxI
506497
xHasUnspecifiedAddress = pdTRUE;
507498
}
508499

500+
/* Test if the IP-version is 6. */
501+
if( ( ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) != 6U )
502+
{
503+
/* Can not handle, unknown or invalid header version. */
504+
eReturn = eReleaseBuffer;
505+
FreeRTOS_printf( ( "prvAllowIPPacketIPv6: drop packet, invalid header version: %u\n", ( ucVersionTrafficClass & ( uint8_t ) 0xF0U ) >> 4 ) );
506+
}
509507
/* Is the packet for this IP address? */
510-
if( ( xHasUnspecifiedAddress == pdFALSE ) &&
511-
( pxNetworkBuffer->pxEndPoint != NULL ) &&
512-
( memcmp( pxDestinationIPAddress->ucBytes, pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
508+
else if( ( xHasUnspecifiedAddress == pdFALSE ) &&
509+
( pxNetworkBuffer->pxEndPoint != NULL ) &&
510+
( memcmp( pxDestinationIPAddress->ucBytes, pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes, sizeof( IPv6_Address_t ) ) == 0 ) )
513511
{
514512
eReturn = eProcessBuffer;
515513
}

source/FreeRTOS_IPv6_Utils.c

Lines changed: 12 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;
@@ -107,8 +107,18 @@ BaseType_t prvChecksumIPv6Checks( uint8_t * pucEthernetBuffer,
107107
/* coverity[misra_c_2012_rule_11_3_violation] */
108108
pxSet->pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + uxExtensionHeaderLength ] ) );
109109
pxSet->usPayloadLength = FreeRTOS_ntohs( pxSet->pxIPPacket_IPv6->usPayloadLength );
110+
110111
/* For IPv6, the number of bytes in the protocol is indicated. */
111-
pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength );
112+
if( pxSet->usPayloadLength < uxExtensionHeaderLength )
113+
{
114+
/* Invalid payload length - extension headers exceed payload. */
115+
pxSet->usChecksum = ipINVALID_LENGTH;
116+
xReturn = 4;
117+
}
118+
else
119+
{
120+
pxSet->usProtocolBytes = ( uint16_t ) ( pxSet->usPayloadLength - uxExtensionHeaderLength );
121+
}
112122

113123
uxNeeded = ( size_t ) pxSet->usPayloadLength;
114124
uxNeeded += ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER;

0 commit comments

Comments
 (0)