Skip to content

Commit c9c87f0

Browse files
Flickdmmergify[bot]
authored andcommitted
NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 Unit tests to confirm that.. Infinite loop when parsing unknown options in the Destination Options header and Infinite loop when parsing a PadN option in the Destination Options header ... have been patched This patch tests the following functions: Ip6IsOptionValid Cc: Saloni Kasbekar <[email protected]> Cc: Zachary Clark-williams <[email protected]> Signed-off-by: Doug Flick [MSFT] <[email protected]> Reviewed-by: Saloni Kasbekar <[email protected]>
1 parent 4df0229 commit c9c87f0

File tree

3 files changed

+324
-4
lines changed

3 files changed

+324
-4
lines changed

NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
## @file
2-
# Unit test suite for the Ip6Dxe using Google Test
2+
# Unit test suite for the Ip6DxeGoogleTest using Google Test
33
#
44
# Copyright (c) Microsoft Corporation.<BR>
55
# SPDX-License-Identifier: BSD-2-Clause-Patent
66
##
77
[Defines]
88
INF_VERSION = 0x00010017
9-
BASE_NAME = Ip6DxeUnitTest
10-
FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A
9+
BASE_NAME = Ip6DxeGoogleTest
10+
FILE_GUID = AE39981C-B7FE-41A8-A9C2-F41910477CA3
1111
VERSION_STRING = 1.0
1212
MODULE_TYPE = HOST_APPLICATION
1313
#
@@ -16,9 +16,11 @@
1616
# VALID_ARCHITECTURES = IA32 X64 AARCH64
1717
#
1818
[Sources]
19+
../Ip6Option.c
20+
Ip6OptionGoogleTest.h
1921
Ip6DxeGoogleTest.cpp
2022
Ip6OptionGoogleTest.cpp
21-
../Ip6Option.c
23+
Ip6OptionGoogleTest.h
2224

2325
[Packages]
2426
MdePkg/MdePkg.dec

NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp

+278
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern "C" {
1212
#include <Library/DebugLib.h>
1313
#include "../Ip6Impl.h"
1414
#include "../Ip6Option.h"
15+
#include "Ip6OptionGoogleTest.h"
1516
}
1617

1718
/////////////////////////////////////////////////////////////////////////
@@ -127,3 +128,280 @@ TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse)
127128

128129
EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen));
129130
}
131+
132+
////////////////////////////////////////////////////////////////////////
133+
// Ip6IsOptionValid Tests
134+
////////////////////////////////////////////////////////////////////////
135+
136+
// Define a fixture for your tests if needed
137+
class Ip6IsOptionValidTest : public ::testing::Test {
138+
protected:
139+
// Add any setup code if needed
140+
virtual void
141+
SetUp (
142+
)
143+
{
144+
// Initialize any resources or variables
145+
}
146+
147+
// Add any cleanup code if needed
148+
virtual void
149+
TearDown (
150+
)
151+
{
152+
// Clean up any resources or variables
153+
}
154+
};
155+
156+
// Test Description
157+
// Verify that a NULL option is Invalid
158+
TEST_F (Ip6IsOptionValidTest, NullOptionShouldReturnTrue) {
159+
NET_BUF Packet = { 0 };
160+
// we need to define enough of the packet to make the function work
161+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
162+
IP6_SERVICE *IpSb = NULL;
163+
164+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
165+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
166+
EFI_IP6_HEADER Ip6Header = { 0 };
167+
168+
Ip6Header.SourceAddress = SourceAddress;
169+
Ip6Header.DestinationAddress = DestinationAddress;
170+
Packet.Ip.Ip6 = &Ip6Header;
171+
172+
EXPECT_FALSE (Ip6IsOptionValid (IpSb, &Packet, NULL, 0, 0));
173+
}
174+
175+
// Test Description
176+
// Verify that an unknown option with a length of 0 and type of <unknown> does not cause an infinite loop
177+
TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength0) {
178+
NET_BUF Packet = { 0 };
179+
// we need to define enough of the packet to make the function work
180+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
181+
UINT32 DeadCode = 0xDeadC0de;
182+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
183+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
184+
185+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
186+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
187+
EFI_IP6_HEADER Ip6Header = { 0 };
188+
189+
Ip6Header.SourceAddress = SourceAddress;
190+
Ip6Header.DestinationAddress = DestinationAddress;
191+
Packet.Ip.Ip6 = &Ip6Header;
192+
193+
IP6_OPTION_HEADER optionHeader;
194+
195+
optionHeader.Type = 23; // Unknown Option
196+
optionHeader.Length = 0; // This will cause an infinite loop if the function is not working correctly
197+
198+
// This should be a valid option even though the length is 0
199+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
200+
}
201+
202+
// Test Description
203+
// Verify that an unknown option with a length of 1 and type of <unknown> does not cause an infinite loop
204+
TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength1) {
205+
NET_BUF Packet = { 0 };
206+
// we need to define enough of the packet to make the function work
207+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
208+
UINT32 DeadCode = 0xDeadC0de;
209+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
210+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
211+
212+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
213+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
214+
EFI_IP6_HEADER Ip6Header = { 0 };
215+
216+
Ip6Header.SourceAddress = SourceAddress;
217+
Ip6Header.DestinationAddress = DestinationAddress;
218+
Packet.Ip.Ip6 = &Ip6Header;
219+
220+
IP6_OPTION_HEADER optionHeader;
221+
222+
optionHeader.Type = 23; // Unknown Option
223+
optionHeader.Length = 1; // This will cause an infinite loop if the function is not working correctly
224+
225+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
226+
}
227+
228+
// Test Description
229+
// Verify that an unknown option with a length of 2 and type of <unknown> does not cause an infinite loop
230+
TEST_F (Ip6IsOptionValidTest, VerifyIpSkipUnknownOption) {
231+
NET_BUF Packet = { 0 };
232+
// we need to define enough of the packet to make the function work
233+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
234+
UINT32 DeadCode = 0xDeadC0de;
235+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
236+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
237+
238+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
239+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
240+
EFI_IP6_HEADER Ip6Header = { 0 };
241+
242+
Ip6Header.SourceAddress = SourceAddress;
243+
Ip6Header.DestinationAddress = DestinationAddress;
244+
Packet.Ip.Ip6 = &Ip6Header;
245+
246+
IP6_OPTION_HEADER optionHeader;
247+
248+
optionHeader.Type = 23; // Unknown Option
249+
optionHeader.Length = 2; // Valid length for an unknown option
250+
251+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
252+
}
253+
254+
// Test Description
255+
// Verify that Ip6OptionPad1 is valid with a length of 0
256+
TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPad1) {
257+
NET_BUF Packet = { 0 };
258+
// we need to define enough of the packet to make the function work
259+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
260+
UINT32 DeadCode = 0xDeadC0de;
261+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
262+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
263+
264+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
265+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
266+
EFI_IP6_HEADER Ip6Header = { 0 };
267+
268+
Ip6Header.SourceAddress = SourceAddress;
269+
Ip6Header.DestinationAddress = DestinationAddress;
270+
Packet.Ip.Ip6 = &Ip6Header;
271+
272+
IP6_OPTION_HEADER optionHeader;
273+
274+
optionHeader.Type = Ip6OptionPad1;
275+
optionHeader.Length = 0;
276+
277+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
278+
}
279+
280+
// Test Description
281+
// Verify that Ip6OptionPadN doesn't overflow with various lengths
282+
TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPadN) {
283+
NET_BUF Packet = { 0 };
284+
// we need to define enough of the packet to make the function work
285+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
286+
UINT32 DeadCode = 0xDeadC0de;
287+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
288+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
289+
290+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
291+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
292+
EFI_IP6_HEADER Ip6Header = { 0 };
293+
294+
Ip6Header.SourceAddress = SourceAddress;
295+
Ip6Header.DestinationAddress = DestinationAddress;
296+
Packet.Ip.Ip6 = &Ip6Header;
297+
298+
IP6_OPTION_HEADER optionHeader;
299+
300+
optionHeader.Type = Ip6OptionPadN;
301+
optionHeader.Length = 0xFF;
302+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
303+
304+
optionHeader.Length = 0xFE;
305+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
306+
307+
optionHeader.Length = 0xFD;
308+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
309+
310+
optionHeader.Length = 0xFC;
311+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
312+
}
313+
314+
// Test Description
315+
// Verify an unknown option doesn't cause an infinite loop with various lengths
316+
TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLengthAttemptOverflow) {
317+
NET_BUF Packet = { 0 };
318+
// we need to define enough of the packet to make the function work
319+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
320+
UINT32 DeadCode = 0xDeadC0de;
321+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
322+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
323+
324+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
325+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
326+
EFI_IP6_HEADER Ip6Header = { 0 };
327+
328+
Ip6Header.SourceAddress = SourceAddress;
329+
Ip6Header.DestinationAddress = DestinationAddress;
330+
Packet.Ip.Ip6 = &Ip6Header;
331+
332+
IP6_OPTION_HEADER optionHeader;
333+
334+
optionHeader.Type = 23; // Unknown Option
335+
optionHeader.Length = 0xFF;
336+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
337+
338+
optionHeader.Length = 0xFE;
339+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
340+
341+
optionHeader.Length = 0xFD;
342+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
343+
344+
optionHeader.Length = 0xFC;
345+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0));
346+
}
347+
348+
// Test Description
349+
// Verify that the function supports multiple options
350+
TEST_F (Ip6IsOptionValidTest, MultiOptionSupport) {
351+
UINT16 HdrLen;
352+
NET_BUF Packet = { 0 };
353+
// we need to define enough of the packet to make the function work
354+
// The function being tested will pass IpSb to Ip6SendIcmpError which is defined above
355+
UINT32 DeadCode = 0xDeadC0de;
356+
// Don't actually use this pointer, just pass it to the function, nothing will be done with it
357+
IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode;
358+
359+
EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
360+
EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 };
361+
EFI_IP6_HEADER Ip6Header = { 0 };
362+
363+
Ip6Header.SourceAddress = SourceAddress;
364+
Ip6Header.DestinationAddress = DestinationAddress;
365+
Packet.Ip.Ip6 = &Ip6Header;
366+
367+
UINT8 ExtHdr[1024] = { 0 };
368+
UINT8 *Cursor = ExtHdr;
369+
IP6_OPTION_HEADER *Option = (IP6_OPTION_HEADER *)ExtHdr;
370+
371+
// Let's start chaining options
372+
373+
Option->Type = 23; // Unknown Option
374+
Option->Length = 0xFC;
375+
376+
Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC;
377+
378+
Option = (IP6_OPTION_HEADER *)Cursor;
379+
Option->Type = Ip6OptionPad1;
380+
381+
Cursor += sizeof (1);
382+
383+
// Type and length aren't processed, instead it just moves the pointer forward by 4 bytes
384+
Option = (IP6_OPTION_HEADER *)Cursor;
385+
Option->Type = Ip6OptionRouterAlert;
386+
Option->Length = 4;
387+
388+
Cursor += sizeof (IP6_OPTION_HEADER) + 4;
389+
390+
Option = (IP6_OPTION_HEADER *)Cursor;
391+
Option->Type = Ip6OptionPadN;
392+
Option->Length = 0xFC;
393+
394+
Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC;
395+
396+
Option = (IP6_OPTION_HEADER *)Cursor;
397+
Option->Type = Ip6OptionRouterAlert;
398+
Option->Length = 4;
399+
400+
Cursor += sizeof (IP6_OPTION_HEADER) + 4;
401+
402+
// Total 524
403+
404+
HdrLen = (UINT16)(Cursor - ExtHdr);
405+
406+
EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, ExtHdr, HdrLen, 0));
407+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/** @file
2+
Exposes the functions needed to test the Ip6Option module.
3+
4+
Copyright (c) Microsoft Corporation
5+
SPDX-License-Identifier: BSD-2-Clause-Patent
6+
**/
7+
8+
#ifndef IP6_OPTION_HEADER_GOOGLE_TEST_H_
9+
#define IP6_OPTION_HEADER_GOOGLE_TEST_H_
10+
11+
#include <Uefi.h>
12+
#include "../Ip6Impl.h"
13+
14+
/**
15+
Validate the IP6 option format for both the packets we received
16+
and that we will transmit. It will compute the ICMPv6 error message fields
17+
if the option is malformatted.
18+
19+
@param[in] IpSb The IP6 service data.
20+
@param[in] Packet The to be validated packet.
21+
@param[in] Option The first byte of the option.
22+
@param[in] OptionLen The length of the whole option.
23+
@param[in] Pointer Identifies the octet offset within
24+
the invoking packet where the error was detected.
25+
26+
27+
@retval TRUE The option is properly formatted.
28+
@retval FALSE The option is malformatted.
29+
30+
**/
31+
BOOLEAN
32+
Ip6IsOptionValid (
33+
IN IP6_SERVICE *IpSb,
34+
IN NET_BUF *Packet,
35+
IN UINT8 *Option,
36+
IN UINT16 OptionLen,
37+
IN UINT32 Pointer
38+
);
39+
40+
#endif // __IP6_OPTION_HEADER_GOOGLE_TEST_H__

0 commit comments

Comments
 (0)