:p
atchew
Login
The security patches contained in this series with the exception of "MdePkg/Test: Add gRT_GetTime Google Test Mock" and "NetworkPkg: : Adds a SecurityFix.yaml file" have been reviewed during GHSA-hc6x-cw6p-gj7h infosec review. This patch series contains the following security patches for the security vulnerabilities found by QuarksLab in the EDK II Network Stack: CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read CVE-2023-45230 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer CVE-2023-45231 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read CVE-2023-45232 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') CVE-2023-45233 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') CVE-2023-45234 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer NetworkPkg: Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> MdePkg: Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Zhiguang Liu <zhiguang.liu@intel.com> Doug Flick (8): NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 - Patch NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 - Unit Tests NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Patch NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Patch NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Unit Tests NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Patch NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Unit Tests Douglas Flick [MSFT] (6): NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit Tests NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit Tests MdePkg: Test: Add gRT_GetTime Google Test Mock NetworkPkg: : Adds a SecurityFix.yaml file NetworkPkg/Test/NetworkPkgHostTest.dsc | 105 +++ .../GoogleTest/Dhcp6DxeGoogleTest.inf | 44 + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 44 + .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 48 + .../Library/MockUefiRuntimeServicesTableLib.h | 7 + NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 143 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 78 +- .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 ++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 + NetworkPkg/Ip6Dxe/Ip6Option.h | 89 ++ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 68 ++ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 + NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 612 ++++++++----- NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 373 ++++++-- NetworkPkg/Ip6Dxe/Ip6Option.c | 84 +- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 148 ++- .../MockUefiRuntimeServicesTableLib.cpp | 5 +- .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 20 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 839 ++++++++++++++++++ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 20 + .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 411 +++++++++ NetworkPkg/NetworkPkg.ci.yaml | 118 ++- NetworkPkg/SecurityFixes.yaml | 123 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 574 ++++++++++++ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 19 + 25 files changed, 3686 insertions(+), 401 deletions(-) create mode 100644 NetworkPkg/Test/NetworkPkgHostTest.dsc create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp create mode 100644 NetworkPkg/SecurityFixes.yaml create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114252): https://edk2.groups.io/g/devel/message/114252 Mute This Topic: https://groups.io/mt/103926729/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4535 SECURITY PATCH - Patch TCBZ4535 CVE-2023-45230 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 43 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 78 +++--- NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 409 +++++++++++++++++++---------- NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 373 +++++++++++++++++++++----- 4 files changed, 666 insertions(+), 237 deletions(-) diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S') #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I') +// +// For more information on DHCP options see RFC 8415, Section 21.1 +// +// The format of DHCP options is: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | option-code | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | option-data | +// | (option-len octets) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16)) +#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16)) + +// +// Combined size of Code and Length +// +#define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \ + DHCP6_SIZE_OF_OPT_LEN) + +STATIC_ASSERT ( + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN == 4, + "Combined size of Code and Length must be 4 per RFC 8415" + ); + +// +// Offset to the length is just past the code +// +#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE) +STATIC_ASSERT ( + DHCP6_OPT_LEN_OFFSET (0) == 2, + "Offset of length is + 2 past start of option" + ); + +#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +STATIC_ASSERT ( + DHCP6_OPT_DATA_OFFSET (0) == 4, + "Offset to option data should be +4 from start of option" + ); + #define DHCP6_PACKET_ALL 0 #define DHCP6_PACKET_STATEFUL 1 #define DHCP6_PACKET_STATELESS 2 diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h @@ -XXX,XX +XXX,XX @@ Dhcp6OnTransmitted ( ); /** - Append the appointed option to the buf, and move the buf to the end. + Append the option to Buf, update the length of packet, and move Buf to the end. - @param[in, out] Buf The pointer to buffer. - @param[in] OptType The option type. - @param[in] OptLen The length of option content.s - @param[in] Data The pointer to the option content. - - @return Buf The position to append the next option. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. + @param[in] OptType The option type. + @param[in] OptLen The length of option contents. + @param[in] Data The pointer to the option content. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendOption ( - IN OUT UINT8 *Buf, - IN UINT16 OptType, - IN UINT16 OptLen, - IN UINT8 *Data + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN UINT16 OptType, + IN UINT16 OptLen, + IN UINT8 *Data ); /** - Append the Ia option to Buf, and move Buf to the end. - - @param[in, out] Buf The pointer to the position to append. + Append the appointed Ia option to Buf, update the Ia option length, and move Buf + to the end of the option. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Ia The pointer to the Ia. @param[in] T1 The time of T1. @param[in] T2 The time of T2. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next Ia option. - + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaOption ( - IN OUT UINT8 *Buf, - IN EFI_DHCP6_IA *Ia, - IN UINT32 T1, - IN UINT32 T2, - IN UINT32 MessageType + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN EFI_DHCP6_IA *Ia, + IN UINT32 T1, + IN UINT32 T2, + IN UINT32 MessageType ); /** Append the appointed Elapsed time option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Instance The pointer to the Dhcp6 instance. @param[out] Elapsed The pointer to the elapsed time value in the generated packet. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendETOption ( - IN OUT UINT8 *Buf, - IN DHCP6_INSTANCE *Instance, - OUT UINT16 **Elapsed + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN DHCP6_INSTANCE *Instance, + OUT UINT16 **Elapsed ); /** Set the elapsed time based on the given instance and the pointer to the elapsed time option. - @param[in] Elapsed The pointer to the position to append. - @param[in] Instance The pointer to the Dhcp6 instance. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ VOID SetElapsedTime ( diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent - **/ #include "Dhcp6Impl.h" @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Elapsed, Instance->Config->SolicitRetransmission ); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet); if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE; @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType); + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, + DecIa, + 0, + 0, + Packet->Dhcp6.Header.MessageType + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE; @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // ServerId is extracted from packet, it's network order. // - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType); + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, + RelIa, + 0, + 0, + Packet->Dhcp6.Header.MessageType + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Determine the size/length of packet - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( Instance->IaCb.Ia->State = Dhcp6Releasing; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } if (!RebindRequest) { // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Dhcp6OptServerId ); if (Option == NULL) { - FreePool (Packet); - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto ON_ERROR; } ServerId = (EFI_DHCP6_DUID *)(Option + 2); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing; Status = Dhcp6CallbackUser (Instance, Event, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( if (SendClientId) { Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, OptionRequest->OpCode, OptionRequest->OpLen, OptionRequest->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < OptionCount; Index++) { UserOpt = OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( // Send info-request packet with no state. // Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c @@ -XXX,XX +XXX,XX @@ Dhcp6OnTransmitted ( } /** - Append the option to Buf, and move Buf to the end. + Append the option to Buf, update the length of packet, and move Buf to the end. - @param[in, out] Buf The pointer to the buffer. - @param[in] OptType The option type. - @param[in] OptLen The length of option contents. - @param[in] Data The pointer to the option content. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. + @param[in] OptType The option type. + @param[in] OptLen The length of option contents. + @param[in] Data The pointer to the option content. - @return Buf The position to append the next option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendOption ( - IN OUT UINT8 *Buf, - IN UINT16 OptType, - IN UINT16 OptLen, - IN UINT8 *Data + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN UINT16 OptType, + IN UINT16 OptLen, + IN UINT8 *Data ) { + UINT32 Length; + UINT32 BytesNeeded; + // // The format of Dhcp6 option: // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // - ASSERT (OptLen != 0); + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } - WriteUnaligned16 ((UINT16 *)Buf, OptType); - Buf += 2; - WriteUnaligned16 ((UINT16 *)Buf, OptLen); - Buf += 2; - CopyMem (Buf, Data, NTOHS (OptLen)); - Buf += NTOHS (OptLen); + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } - return Buf; + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (OptLen == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + // + // Calculate the bytes needed for the option + // + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + NTOHS (OptLen); + + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + WriteUnaligned16 ((UINT16 *)*PacketCursor, OptType); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; + WriteUnaligned16 ((UINT16 *)*PacketCursor, OptLen); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; + CopyMem (*PacketCursor, Data, NTOHS (OptLen)); + *PacketCursor += NTOHS (OptLen); + + // Update the packet length by the length of the option + 4 bytes + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed IA Address option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] IaAddr The pointer to the IA Address. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaAddrOption ( - IN OUT UINT8 *Buf, + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, IN EFI_DHCP6_IA_ADDRESS *IaAddr, IN UINT32 MessageType ) { + UINT32 BytesNeeded; + UINT32 Length; + // The format of the IA Address option is: // // 0 1 2 3 @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaAddrOption ( // . . // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (IaAddr == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + BytesNeeded += sizeof (EFI_IPv6_ADDRESS); + // + // Even if the preferred-lifetime is 0, it still needs to store it. + // + BytesNeeded += sizeof (IaAddr->PreferredLifetime); + // + // Even if the valid-lifetime is 0, it still needs to store it. + // + BytesNeeded += sizeof (IaAddr->ValidLifetime); + + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of Ia Address option type // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptIaAddr)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptIaAddr)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; - WriteUnaligned16 ((UINT16 *)Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; - CopyMem (Buf, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); - Buf += sizeof (EFI_IPv6_ADDRESS); + CopyMem (*PacketCursor, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); + *PacketCursor += sizeof (EFI_IPv6_ADDRESS); // // Fill the value of preferred-lifetime and valid-lifetime. @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaAddrOption ( // should set to 0 when initiate a Confirm message. // if (MessageType != Dhcp6MsgConfirm) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->PreferredLifetime)); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->PreferredLifetime)); } - Buf += 4; + *PacketCursor += sizeof (IaAddr->PreferredLifetime); if (MessageType != Dhcp6MsgConfirm) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->ValidLifetime)); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->ValidLifetime)); } - Buf += 4; + *PacketCursor += sizeof (IaAddr->ValidLifetime); - return Buf; + // + // Update the packet length + // + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed Ia option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Ia The pointer to the Ia. @param[in] T1 The time of T1. @param[in] T2 The time of T2. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaOption ( - IN OUT UINT8 *Buf, - IN EFI_DHCP6_IA *Ia, - IN UINT32 T1, - IN UINT32 T2, - IN UINT32 MessageType + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN EFI_DHCP6_IA *Ia, + IN UINT32 T1, + IN UINT32 T2, + IN UINT32 MessageType ) { - UINT8 *AddrOpt; - UINT16 *Len; - UINTN Index; + UINT8 *AddrOpt; + UINT16 *Len; + UINTN Index; + UINT32 BytesNeeded; + UINT32 Length; + EFI_STATUS Status; // // The format of IA_NA and IA_TA option: @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Ia == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + BytesNeeded += sizeof (Ia->Descriptor.IaId); + // + // + N for the IA_NA-options/IA_TA-options + // Dhcp6AppendIaAddrOption will need to check the length for each address + // + if (Ia->Descriptor.Type == Dhcp6OptIana) { + BytesNeeded += sizeof (T1) + sizeof (T2); + } + + // + // Space remaining in the packet + // + Length = (UINT16)(Packet->Size - Packet->Length); + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of Ia option type // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Ia->Descriptor.Type)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Ia->Descriptor.Type)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; // // Fill the len of Ia option later, keep the pointer first // - Len = (UINT16 *)Buf; - Buf += 2; + Len = (UINT16 *)*PacketCursor; + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; // // Fill the value of iaid // - WriteUnaligned32 ((UINT32 *)Buf, HTONL (Ia->Descriptor.IaId)); - Buf += 4; + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (Ia->Descriptor.IaId)); + *PacketCursor += sizeof (Ia->Descriptor.IaId); // // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified. // if (Ia->Descriptor.Type == Dhcp6OptIana) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff)); - Buf += 4; - WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff)); - Buf += 4; + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T1 != 0) ? T1 : 0xffffffff)); + *PacketCursor += sizeof (T1); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T2 != 0) ? T2 : 0xffffffff)); + *PacketCursor += sizeof (T2); } // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaOption ( // for (Index = 0; Index < Ia->IaAddressCount; Index++) { AddrOpt = (UINT8 *)Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS); - Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); + Status = Dhcp6AppendIaAddrOption (Packet, PacketCursor, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); + if (EFI_ERROR (Status)) { + return Status; + } } // // Fill the value of Ia option length // - *Len = HTONS ((UINT16)(Buf - (UINT8 *)Len - 2)); + *Len = HTONS ((UINT16)(*PacketCursor - (UINT8 *)Len - 2)); - return Buf; + // + // Update the packet length + // + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed Elapsed time option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Instance The pointer to the Dhcp6 instance. @param[out] Elapsed The pointer to the elapsed time value in - the generated packet. + the generated packet. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendETOption ( - IN OUT UINT8 *Buf, - IN DHCP6_INSTANCE *Instance, - OUT UINT16 **Elapsed + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN DHCP6_INSTANCE *Instance, + OUT UINT16 **Elapsed ) { + UINT32 BytesNeeded; + UINT32 Length; + // // The format of elapsed time option: // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendETOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Instance == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Elapsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + // + // + 2 for elapsed-time + // + BytesNeeded += sizeof (UINT16); + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of elapsed-time option type. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptElapsedTime)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptElapsedTime)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; // // Fill the len of elapsed-time option, which is fixed. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (2)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (2)); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; // // Fill in elapsed time value with 0 value for now. The actual value is // filled in later just before the packet is transmitted. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (0)); - *Elapsed = (UINT16 *)Buf; - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (0)); + *Elapsed = (UINT16 *)*PacketCursor; + *PacketCursor += sizeof (UINT16); - return Buf; + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114253): https://edk2.groups.io/g/devel/message/114253 Mute This Topic: https://groups.io/mt/103926731/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4535 SECURITY PATCH - Unit Tests TCBZ4535 CVE-2023-45230 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 99 ++++ .../GoogleTest/Dhcp6DxeGoogleTest.inf | 43 ++ .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 20 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 478 ++++++++++++++++++ NetworkPkg/NetworkPkg.ci.yaml | 118 ++--- 5 files changed, 695 insertions(+), 63 deletions(-) create mode 100644 NetworkPkg/Test/NetworkPkgHostTest.dsc create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ +## @file +# NetworkPkgHostTest DSC file used to build host-based unit tests. +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + PLATFORM_NAME = NetworkPkgHostTest + PLATFORM_GUID = 3b68324e-fc07-4d49-9520-9347ede65879 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/NetworkPkg/HostTest + SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64 + BUILD_TARGETS = NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Components] + # + # Build HOST_APPLICATION that tests NetworkPkg + # + NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf + +# Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. +[LibraryClasses] + NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf + VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf + TlsLib|CryptoPkg/Library/TlsLibNull/TlsLibNull.inf +!else + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf +!endif + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + +!if $(TOOL_CHAIN_TAG) == VS2019 or $(TOOL_CHAIN_TAG) == VS2022 +[LibraryClasses.X64] + # Provide StackCookie support lib so that we can link to /GS exports for VS builds + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf +!endif + +[LibraryClasses.common.UEFI_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +[LibraryClasses.common.UEFI_APPLICATION] + DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf +[LibraryClasses.ARM, LibraryClasses.AARCH64] + # + # It is not possible to prevent ARM compiler calls to generic intrinsic functions. + # This library provides the instrinsic functions generated by a given compiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM images. + # +!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019 + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf +!endif + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf +[LibraryClasses.ARM] + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf +[LibraryClasses.RISCV64] + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2 + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType|0x4 diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the Dhcp6Dxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = Dhcp6DxeGoogleTest + FILE_GUID = 1D2A4C65-38C8-4C2F-BB60-B5FA49625AA9 + VERSION_STRING = 1.0 + MODULE_TYPE = HOST_APPLICATION +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# +[Sources] + Dhcp6DxeGoogleTest.cpp + Dhcp6IoGoogleTest.cpp + ../Dhcp6Io.c + ../Dhcp6Utility.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the Dhcp6Dxe module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Tests for Dhcp6Io.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include <Library/BaseMemoryLib.h> + #include "../Dhcp6Impl.h" + #include "../Dhcp6Utility.h" +} + +//////////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////////// + +#define DHCP6_PACKET_MAX_LEN 1500 + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// Symbol Definitions +// These functions are not directly under test - but required to compile +//////////////////////////////////////////////////////////////////////// + +// This definition is used by this test but is also required to compile +// by Dhcp6Io.c +EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = { + { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 } +}; + +EFI_STATUS +EFIAPI +UdpIoSendDatagram ( + IN UDP_IO *UdpIo, + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint OPTIONAL, + IN EFI_IP_ADDRESS *Gateway OPTIONAL, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UdpIoRecvDatagram ( + IN UDP_IO *UdpIo, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context, + IN UINT32 HeadLen + ) +{ + return EFI_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendOptionTest Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that is too small by a duid that is too large +TEST_F (Dhcp6AppendOptionTest, InvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_DHCP6_DUID *UntrustedDuid; + EFI_STATUS Status; + + UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); + ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); + + UntrustedDuid->Length = NTOHS (0xFFFF); + + Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6AppendOptionTest::Packet, + &Cursor, + HTONS (Dhcp6OptServerId), + UntrustedDuid->Length, + UntrustedDuid->Duid + ); + + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); +} + +// Test Description: +// Attempt to append an option to a packet that is large enough +TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_DHCP6_DUID *UntrustedDuid; + EFI_STATUS Status; + UINTN OriginalLength; + + UINT8 Duid[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); + ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); + + UntrustedDuid->Length = NTOHS (sizeof (Duid)); + CopyMem (UntrustedDuid->Duid, Duid, sizeof (Duid)); + + Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6AppendOptionTest::Packet, + &Cursor, + HTONS (Dhcp6OptServerId), + UntrustedDuid->Length, + UntrustedDuid->Duid + ); + + ASSERT_EQ (Status, EFI_SUCCESS); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendOptionTest::Packet->Dhcp6.Option + sizeof (Duid) + 4); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendOptionTest::Packet->Length, OriginalLength + sizeof (Duid) + 4); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendETOption Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendETOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + Packet->Length = sizeof (EFI_DHCP6_HEADER); + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that is too small by a duid that is too large +TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + DHCP6_INSTANCE Instance; + UINT16 ElapsedTimeVal; + UINT16 *ElapsedTime; + + Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; + ElapsedTime = &ElapsedTimeVal; + + Packet->Length = Packet->Size - 2; + + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, + &Instance, // Instance is not used in this function + &ElapsedTime + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +// Test Description: +// Attempt to append an option to a packet that is large enough +TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + DHCP6_INSTANCE Instance; + UINT16 ElapsedTimeVal; + UINT16 *ElapsedTime; + UINTN ExpectedSize; + UINTN OriginalLength; + + Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; + ElapsedTime = &ElapsedTimeVal; + ExpectedSize = 6; + OriginalLength = Packet->Length; + + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, + &Instance, // Instance is not used in this function + &ElapsedTime + ); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendETOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendETOptionTest::Packet->Length, OriginalLength + ExpectedSize); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendIaOption Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendIaOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + EFI_DHCP6_IA *Ia; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + + Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2); + ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL); + + CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); + + Ia->IaAddressCount = 2; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + + if (Ia != NULL) { + FreePool (Ia); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that doesn't have enough space +// for the option header +TEST_F (Dhcp6AppendIaOptionTest, IaNaInvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + + Packet->Length = Packet->Size - 2; + + Ia->Descriptor.Type = Dhcp6OptIana; + Ia->Descriptor.IaId = 0x12345678; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0x12345678, + 0x11111111, + Dhcp6OptIana + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +// Test Description: +// Attempt to append an option to a packet that doesn't have enough space +// for the option header +TEST_F (Dhcp6AppendIaOptionTest, IaTaInvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + + // Use up nearly all the space in the packet + Packet->Length = Packet->Size - 2; + + Ia->Descriptor.Type = Dhcp6OptIata; + Ia->Descriptor.IaId = 0x12345678; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0, + 0, + Dhcp6OptIata + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +TEST_F (Dhcp6AppendIaOptionTest, IaNaValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + UINTN ExpectedSize; + UINTN OriginalLength; + + // + // 2 bytes for the option header type + // + ExpectedSize = 2; + // + // 2 bytes for the option header length + // + ExpectedSize += 2; + // + // 4 bytes for the IAID + // + ExpectedSize += 4; + // + // + 4 bytes for the T1 + // + ExpectedSize += 4; + // + // + 4 bytes for the T2 + // + ExpectedSize += 4; + // + // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + // + 2 bytes for the option header type + // + 2 bytes for the option header length + // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address + // + ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + Ia->Descriptor.Type = Dhcp6OptIana; + Ia->Descriptor.IaId = 0x12345678; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0x12345678, + 0x12345678, + Dhcp6OptIana + ); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); +} + +TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + UINTN ExpectedSize; + UINTN OriginalLength; + + // + // 2 bytes for the option header type + // + ExpectedSize = 2; + // + // 2 bytes for the option header length + // + ExpectedSize += 2; + // + // 4 bytes for the IAID + // + ExpectedSize += 4; + // + // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + // + 2 bytes for the option header type + // + 2 bytes for the option header length + // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address + // + ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + Ia->Descriptor.Type = Dhcp6OptIata; + Ia->Descriptor.IaId = 0x12345678; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0, + 0, + Dhcp6OptIata + ); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); +} diff --git a/NetworkPkg/NetworkPkg.ci.yaml b/NetworkPkg/NetworkPkg.ci.yaml index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/NetworkPkg.ci.yaml +++ b/NetworkPkg/NetworkPkg.ci.yaml @@ -XXX,XX +XXX,XX @@ # SPDX-License-Identifier: BSD-2-Clause-Patent ## { - "LicenseCheck": { - "IgnoreFiles": [] - }, + "LicenseCheck": { "IgnoreFiles": [] }, "EccCheck": { - ## Exception sample looks like below: - ## "ExceptionList": [ - ## "<ErrorID>", "<KeyWord>" - ## ] - "ExceptionList": [ - ], - ## Both file path and directory path are accepted. - "IgnoreFiles": [ - ] - }, - "CompilerPlugin": { - "DscPath": "NetworkPkg.dsc" - }, - "CharEncodingCheck": { - "IgnoreFiles": [] - }, + ## Exception sample looks like below: + ## "ExceptionList": [ + ## "<ErrorID>", "<KeyWord>" + ## ] + "ExceptionList": [], + ## Both file path and directory path are accepted. + "IgnoreFiles": [], + }, + "CompilerPlugin": { "DscPath": "NetworkPkg.dsc" }, + "HostUnitTestCompilerPlugin": { "DscPath": "Test/NetworkPkgHostTest.dsc" }, + "CharEncodingCheck": { "IgnoreFiles": [] }, "DependencyCheck": { - "AcceptableDependencies": [ - "MdePkg/MdePkg.dec", - "MdeModulePkg/MdeModulePkg.dec", - "NetworkPkg/NetworkPkg.dec", - "CryptoPkg/CryptoPkg.dec" - ], - # For host based unit tests - "AcceptableDependencies-HOST_APPLICATION":[], - # For UEFI shell based apps - "AcceptableDependencies-UEFI_APPLICATION":[ - "ShellPkg/ShellPkg.dec" - ], - "IgnoreInf": [] - }, - "DscCompleteCheck": { - "DscPath": "NetworkPkg.dsc", - "IgnoreInf": [] - }, - "GuidCheck": { - "IgnoreGuidName": [], - "IgnoreGuidValue": [], - "IgnoreFoldersAndFiles": [] - }, - "LibraryClassCheck": { - "IgnoreHeaderFile": [] - }, + "AcceptableDependencies": + [ + "MdePkg/MdePkg.dec", + "MdeModulePkg/MdeModulePkg.dec", + "NetworkPkg/NetworkPkg.dec", + "CryptoPkg/CryptoPkg.dec", + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION": [ + "UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec" + ], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION": + ["ShellPkg/ShellPkg.dec"], + "IgnoreInf": [], + }, + "DscCompleteCheck": { "DscPath": "NetworkPkg.dsc", "IgnoreInf": [] }, + "GuidCheck": + { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + }, + "LibraryClassCheck": { "IgnoreHeaderFile": [] }, ## options defined ci/Plugin/SpellCheck "SpellCheck": { - "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log - "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files - "ExtendWords": [], # words to extend to the dictionary for this package - "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore - "AdditionalIncludePaths": [] # Additional paths to spell check (wildcards supported) - }, + "AuditOnly": True, # Fails test but run in AuditOnly mode to collect log + "IgnoreFiles": [], # use gitignore syntax to ignore errors in matching files + "ExtendWords": [], # words to extend to the dictionary for this package + "IgnoreStandardPaths": [], # Standard Plugin defined paths that should be ignore + "AdditionalIncludePaths": [], # Additional paths to spell check (wildcards supported) + }, - "Defines": { - "BLD_*_CONTINUOUS_INTEGRATION": "TRUE", - "BLD_*_NETWORK_ENABLE": "TRUE", - "BLD_*_NETWORK_SNP_ENABLE": "TRUE", - "BLD_*_NETWORK_VLAN_ENABLE": "TRUE", - "BLD_*_NETWORK_IP4_ENABLE": "TRUE", - "BLD_*_NETWORK_IP6_ENABLE": "TRUE", - "BLD_*_NETWORK_TLS_ENABLE": "TRUE", - "BLD_*_NETWORK_HTTP_ENABLE": "FALSE", - "BLD_*_NETWORK_HTTP_BOOT_ENABLE": "TRUE", - "BLD_*_NETWORK_ISCSI_ENABLE": "TRUE", - } + "Defines": + { + "BLD_*_CONTINUOUS_INTEGRATION": "TRUE", + "BLD_*_NETWORK_ENABLE": "TRUE", + "BLD_*_NETWORK_SNP_ENABLE": "TRUE", + "BLD_*_NETWORK_VLAN_ENABLE": "TRUE", + "BLD_*_NETWORK_IP4_ENABLE": "TRUE", + "BLD_*_NETWORK_IP6_ENABLE": "TRUE", + "BLD_*_NETWORK_TLS_ENABLE": "TRUE", + "BLD_*_NETWORK_HTTP_ENABLE": "FALSE", + "BLD_*_NETWORK_HTTP_BOOT_ENABLE": "TRUE", + "BLD_*_NETWORK_ISCSI_ENABLE": "TRUE", + }, } -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114254): https://edk2.groups.io/g/devel/message/114254 Mute This Topic: https://groups.io/mt/103926732/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 SECURITY PATCH - Patch TCBZ4534 CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 138 +++++++++++++++++++--- NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 203 +++++++++++++++++++++----------- 2 files changed, 256 insertions(+), 85 deletions(-) diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S') #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I') +#define DHCP6_PACKET_ALL 0 +#define DHCP6_PACKET_STATEFUL 1 +#define DHCP6_PACKET_STATELESS 2 + +#define DHCP6_BASE_PACKET_SIZE 1024 + +#define DHCP6_PORT_CLIENT 546 +#define DHCP6_PORT_SERVER 547 + +#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) + +#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE) +#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE) + // // For more information on DHCP options see RFC 8415, Section 21.1 // @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; // | (option-len octets) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // -#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16)) -#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16)) +#define DHCP6_SIZE_OF_OPT_CODE (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode)) +#define DHCP6_SIZE_OF_OPT_LEN (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen)) -// // Combined size of Code and Length -// #define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \ DHCP6_SIZE_OF_OPT_LEN) @@ -XXX,XX +XXX,XX @@ STATIC_ASSERT ( "Combined size of Code and Length must be 4 per RFC 8415" ); -// // Offset to the length is just past the code -// -#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE) +#define DHCP6_OFFSET_OF_OPT_LEN(a) (a + DHCP6_SIZE_OF_OPT_CODE) STATIC_ASSERT ( - DHCP6_OPT_LEN_OFFSET (0) == 2, + DHCP6_OFFSET_OF_OPT_LEN (0) == 2, "Offset of length is + 2 past start of option" ); -#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +#define DHCP6_OFFSET_OF_OPT_DATA(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) STATIC_ASSERT ( - DHCP6_OPT_DATA_OFFSET (0) == 4, + DHCP6_OFFSET_OF_OPT_DATA (0) == 4, "Offset to option data should be +4 from start of option" ); +// +// Identity Association options (both NA (Non-Temporary) and TA (Temporary Association)) +// are defined in RFC 8415 and are a deriviation of a TLV stucture +// For more information on IA_NA see Section 21.4 +// For more information on IA_TA see Section 21.5 +// +// +// The format of IA_NA and IA_TA option: +// +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | OPTION_IA_NA | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | IAID (4 octets) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | T1 (only for IA_NA) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | T2 (only for IA_NA) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . IA_NA-options/IA_TA-options . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_SIZE_OF_IAID (sizeof(UINT32)) +#define DHCP6_SIZE_OF_TIME_INTERVAL (sizeof(UINT32)) -#define DHCP6_PACKET_ALL 0 -#define DHCP6_PACKET_STATEFUL 1 -#define DHCP6_PACKET_STATELESS 2 +// Combined size of IAID, T1, and T2 +#define DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 (DHCP6_SIZE_OF_IAID + \ + DHCP6_SIZE_OF_TIME_INTERVAL + \ + DHCP6_SIZE_OF_TIME_INTERVAL) +STATIC_ASSERT ( + DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 == 12, + "Combined size of IAID, T1, T2 must be 12 per RFC 8415" + ); -#define DHCP6_BASE_PACKET_SIZE 1024 +// This is the size of IA_TA without options +#define DHCP6_MIN_SIZE_OF_IA_TA (DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_IAID) +STATIC_ASSERT ( + DHCP6_MIN_SIZE_OF_IA_TA == 8, + "Minimum combined size of IA_TA per RFC 8415" + ); -#define DHCP6_PORT_CLIENT 546 -#define DHCP6_PORT_SERVER 547 +// Offset to a IA_TA inner option +#define DHCP6_OFFSET_OF_IA_TA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_TA) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_TA_INNER_OPT (0) == 8, + "Offset of IA_TA Inner option is + 8 past start of option" + ); -#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) +// This is the size of IA_NA without options (16) +#define DHCP6_MIN_SIZE_OF_IA_NA DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 +STATIC_ASSERT ( + DHCP6_MIN_SIZE_OF_IA_NA == 16, + "Minimum combined size of IA_TA per RFC 8415" + ); -#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE) -#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE) +#define DHCP6_OFFSET_OF_IA_NA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_NA) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_INNER_OPT (0) == 16, + "Offset of IA_NA Inner option is + 16 past start of option" + ); + +#define DHCP6_OFFSET_OF_IA_NA_T1(a) (a + \ + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_IAID) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_T1 (0) == 8, + "Offset of IA_NA Inner option is + 8 past start of option" + ); + +#define DHCP6_OFFSET_OF_IA_NA_T2(a) (a + \ + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN +\ + DHCP6_SIZE_OF_IAID + \ + DHCP6_SIZE_OF_TIME_INTERVAL) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_T2 (0) == 12, + "Offset of IA_NA Inner option is + 12 past start of option" + ); + +// +// For more information see RFC 8415 Section 21.13 +// +// The format of the Status Code Option: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | OPTION_STATUS_CODE | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | status-code | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | +// . . +// . status-message . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_OFFSET_OF_STATUS_CODE(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_STATUS_CODE (0) == 4, + "Offset of status is + 4 past start of option" + ); extern EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress; extern EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate; diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( // The inner options still start with 2 bytes option-code and 2 bytes option-len. // if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { - T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 8))); - T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 12))); + T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T1 (Option)))); + T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T2 (Option)))); // // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2, // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( return EFI_DEVICE_ERROR; } - IaInnerOpt = Option + 16; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 12); + IaInnerOpt = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option); + IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_COMBINED_IAID_T1_T2); } else { - T1 = 0; - T2 = 0; - IaInnerOpt = Option + 8; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 4); + T1 = 0; + T2 = 0; + + IaInnerOpt = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option); + IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_IAID); } // @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); if (Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( return Status; } +/** + Seeks the Inner Options from a DHCP6 Option + + @param[in] IaType The type of the IA option. + @param[in] Option The pointer to the DHCP6 Option. + @param[in] OptionLen The length of the DHCP6 Option. + @param[out] IaInnerOpt The pointer to the IA inner option. + @param[out] IaInnerLen The length of the IA inner option. + + @retval EFI_SUCCESS Seek the inner option successfully. + @retval EFI_DEVICE_ERROR The OptionLen is invalid. On Error, + the pointers are not modified +**/ +EFI_STATUS +Dhcp6SeekInnerOptionSafe ( + IN UINT16 IaType, + IN UINT8 *Option, + IN UINT32 OptionLen, + OUT UINT8 **IaInnerOpt, + OUT UINT16 *IaInnerLen + ) +{ + UINT16 IaInnerLenTmp; + UINT8 *IaInnerOptTmp; + + if (Option == NULL) { + ASSERT (Option != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaInnerOpt == NULL) { + ASSERT (IaInnerOpt != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaInnerLen == NULL) { + ASSERT (IaInnerLen != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaType == Dhcp6OptIana) { + // Verify we have a fully formed IA_NA + if (OptionLen < DHCP6_MIN_SIZE_OF_IA_NA) { + return EFI_DEVICE_ERROR; + } + + // + IaInnerOptTmp = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option); + + // Verify the IaInnerLen is valid. + IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)DHCP6_OFFSET_OF_OPT_LEN (Option))); + if (IaInnerLenTmp < DHCP6_SIZE_OF_COMBINED_IAID_T1_T2) { + return EFI_DEVICE_ERROR; + } + + IaInnerLenTmp -= DHCP6_SIZE_OF_COMBINED_IAID_T1_T2; + } else if (IaType == Dhcp6OptIata) { + // Verify the OptionLen is valid. + if (OptionLen < DHCP6_MIN_SIZE_OF_IA_TA) { + return EFI_DEVICE_ERROR; + } + + IaInnerOptTmp = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option); + + // Verify the IaInnerLen is valid. + IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))); + if (IaInnerLenTmp < DHCP6_SIZE_OF_IAID) { + return EFI_DEVICE_ERROR; + } + + IaInnerLenTmp -= DHCP6_SIZE_OF_IAID; + } else { + return EFI_DEVICE_ERROR; + } + + *IaInnerOpt = IaInnerOptTmp; + *IaInnerLen = IaInnerLenTmp; + + return EFI_SUCCESS; +} + /** Seek StatusCode Option in package. A Status Code option may appear in the options field of a DHCP message and/or in the options field of another option. @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( UINT8 *IaInnerOpt; UINT16 IaInnerLen; UINT16 StsCode; + UINT32 OptionLen; + + // OptionLen is the length of the Options excluding the DHCP header. + // Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last + // byte of the Option[] field. + OptionLen = Packet->Length - sizeof (Packet->Dhcp6.Header); // // Seek StatusCode option directly in DHCP message body. That is, search in @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + OptionLen, Dhcp6OptStatusCode ); if (*Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_STATUS_CODE (*Option)))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekIaOption ( Packet->Dhcp6.Option, - Packet->Length - sizeof (EFI_DHCP6_HEADER), + OptionLen, &Instance->Config->IaDescriptor ); if (*Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( } // - // The format of the IA_NA option is: + // Calculate the distance from Packet->Dhcp6.Option to the IA option. // - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | OPTION_IA_NA | option-len | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | IAID (4 octets) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | T1 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | T2 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // . IA_NA-options . - // . . - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Packet->Size and Packet->Length are both UINT32 type, and Packet->Size is + // the size of the whole packet, including the DHCP header, and Packet->Length + // is the length of the DHCP message body, excluding the DHCP header. // - // The format of the IA_TA option is: + // (*Option - Packet->Dhcp6.Option) is the number of bytes from the start of + // DHCP6 option area to the start of the IA option. // - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | OPTION_IA_TA | option-len | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | IAID (4 octets) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // . IA_TA-options . - // . . - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Dhcp6SeekInnerOptionSafe() is searching starting from the start of the + // IA option to the end of the DHCP6 option area, thus subtract the space + // up until this option // + OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option); // - // sizeof (option-code + option-len + IaId) = 8 - // sizeof (option-code + option-len + IaId + T1) = 12 - // sizeof (option-code + option-len + IaId + T1 + T2) = 16 + // Seek the inner option // - // The inner options still start with 2 bytes option-code and 2 bytes option-len. - // - if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { - IaInnerOpt = *Option + 16; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 12); - } else { - IaInnerOpt = *Option + 8; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 4); + if (EFI_ERROR ( + Dhcp6SeekInnerOptionSafe ( + Instance->Config->IaDescriptor.Type, + *Option, + OptionLen, + &IaInnerOpt, + &IaInnerLen + ) + )) + { + return EFI_DEVICE_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); if (*Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (*Option))))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( // Option = Dhcp6SeekOption ( Instance->AdSelect->Dhcp6.Option, - Instance->AdSelect->Length - 4, + Instance->AdSelect->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( // Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( // Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6HandleReplyMsg ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptRapidCommit ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleReplyMsg ( // // Any error status code option is found. // - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (Option))))); switch (StsCode) { case Dhcp6StsUnspecFail: // @@ -XXX,XX +XXX,XX @@ Dhcp6SelectAdvertiseMsg ( // Option = Dhcp6SeekOption ( AdSelect->Dhcp6.Option, - AdSelect->Length - 4, + AdSelect->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerUnicast ); @@ -XXX,XX +XXX,XX @@ Dhcp6SelectAdvertiseMsg ( return EFI_OUT_OF_RESOURCES; } - CopyMem (Instance->Unicast, Option + 4, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (Instance->Unicast, DHCP6_OFFSET_OF_OPT_DATA (Option), sizeof (EFI_IPv6_ADDRESS)); } // @@ -XXX,XX +XXX,XX @@ Dhcp6HandleAdvertiseMsg ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptRapidCommit ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleAdvertiseMsg ( CopyMem (Instance->AdSelect, Packet, Packet->Size); if (Option != NULL) { - Instance->AdPref = *(Option + 4); + Instance->AdPref = *(DHCP6_OFFSET_OF_OPT_DATA (Option)); } } else { // @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateful ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN, Dhcp6OptClientId ); - if ((Option == NULL) || (CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0)) { + if ((Option == NULL) || (CompareMem (DHCP6_OFFSET_OF_OPT_DATA (Option), ClientId->Duid, ClientId->Length) != 0)) { goto ON_CONTINUE; } @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateful ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN, Dhcp6OptServerId ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateless ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114255): https://edk2.groups.io/g/devel/message/114255 Mute This Topic: https://groups.io/mt/103926733/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 SECURITY PATCH - Unit Tests TCBZ4534 CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../GoogleTest/Dhcp6DxeGoogleTest.inf | 1 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 2 +- .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 365 +++++++++++++++++- 5 files changed, 424 insertions(+), 3 deletions(-) create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Defines] SKUID_IDENTIFIER = DEFAULT !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + [Packages] MdePkg/MdePkg.dec UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ [Defines] [Sources] Dhcp6DxeGoogleTest.cpp Dhcp6IoGoogleTest.cpp + Dhcp6IoGoogleTest.h ../Dhcp6Io.c ../Dhcp6Utility.c diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as header for private functions under test in Dhcp6Io.c + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef DHCP6_IO_GOOGLE_TEST_H_ +#define DHCP6_IO_GOOGLE_TEST_H_ + +//////////////////////////////////////////////////////////////////////////////// +// These are the functions that are being unit tested +//////////////////////////////////////////////////////////////////////////////// + +#include <Uefi.h> + +/** + Seeks the Inner Options from a DHCP6 Option + + @param[in] IaType The type of the IA option. + @param[in] Option The pointer to the DHCP6 Option. + @param[in] OptionLen The length of the DHCP6 Option. + @param[out] IaInnerOpt The pointer to the IA inner option. + @param[out] IaInnerLen The length of the IA inner option. + + @retval EFI_SUCCESS Seek the inner option successfully. + @retval EFI_DEVICE_ERROR The OptionLen is invalid. +*/ +EFI_STATUS +Dhcp6SeekInnerOptionSafe ( + UINT16 IaType, + UINT8 *Option, + UINT32 OptionLen, + UINT8 **IaInnerOpt, + UINT16 *IaInnerLen + ); + +/** + Seek StatusCode Option in package. A Status Code option may appear in the + options field of a DHCP message and/or in the options field of another option. + See details in section 22.13, RFC3315. + + @param[in] Instance The pointer to the Dhcp6 instance. + @param[in] Packet The pointer to reply messages. + @param[out] Option The pointer to status code option. + + @retval EFI_SUCCESS Seek status code option successfully. + @retval EFI_DEVICE_ERROR An unexpected error. + +**/ +EFI_STATUS +Dhcp6SeekStsOption ( + IN DHCP6_INSTANCE *Instance, + IN EFI_DHCP6_PACKET *Packet, + OUT UINT8 **Option + ); + +#endif // DHCP6_IO_GOOGLE_TEST_H diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // IA option to the end of the DHCP6 option area, thus subtract the space // up until this option // - OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option); + OptionLen = OptionLen - (UINT32)(*Option - Packet->Dhcp6.Option); // // Seek the inner option diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ extern "C" { #include <Library/BaseMemoryLib.h> #include "../Dhcp6Impl.h" #include "../Dhcp6Utility.h" + #include "Dhcp6IoGoogleTest.h" } //////////////////////////////////////////////////////////////////////// @@ -XXX,XX +XXX,XX @@ extern "C" { #define DHCP6_PACKET_MAX_LEN 1500 +// This definition is used by this test but is also required to compile +// by Dhcp6Io.c +#define DHCPV6_OPTION_IA_NA 3 +#define DHCPV6_OPTION_IA_TA 4 + +#define SEARCH_PATTERN 0xDEADC0DE +#define SEARCH_PATTERN_LEN sizeof(SEARCH_PATTERN) + //////////////////////////////////////////////////////////////////////// +// Test structures for IA_NA and IA_TA options +//////////////////////////////////////////////////////////////////////// +typedef struct { + UINT16 Code; + UINT16 Len; + UINT32 IAID; +} DHCPv6_OPTION; + +typedef struct { + DHCPv6_OPTION Header; + UINT32 T1; + UINT32 T2; + UINT8 InnerOptions[0]; +} DHCPv6_OPTION_IA_NA; + +typedef struct { + DHCPv6_OPTION Header; + UINT8 InnerOptions[0]; +} DHCPv6_OPTION_IA_TA; + //////////////////////////////////////////////////////////////////////// // Symbol Definitions // These functions are not directly under test - but required to compile @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { Status = Dhcp6AppendETOption ( Dhcp6AppendETOptionTest::Packet, &Cursor, - &Instance, // Instance is not used in this function + &Instance, // Instance is not used in this function &ElapsedTime ); @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { Status = Dhcp6AppendETOption ( Dhcp6AppendETOptionTest::Packet, &Cursor, - &Instance, // Instance is not used in this function + &Instance, // Instance is not used in this function &ElapsedTime ); @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { // verify that the status is EFI_SUCCESS ASSERT_EQ (Status, EFI_SUCCESS); } + +//////////////////////////////////////////////////////////////////////// +// Dhcp6SeekInnerOptionSafe Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Dhcp6SeekInnerOptionSafeTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IANA option is found. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAValidOptionExpectSuccess) { + EFI_STATUS Result; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIana; + OptionPtr->Header.Len = HTONS (4 + 12); // Valid length has to be more than 12 + OptionPtr->Header.IAID = 0x12345678; + OptionPtr->T1 = 0x11111111; + OptionPtr->T2 = 0x22222222; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Result = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Result, EFI_SUCCESS); + ASSERT_EQ (InnerOptionLength, 4); + ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_DEIVCE_ERROR when the IANA option size is invalid. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAInvalidSizeExpectFail) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIana; + OptionPtr->Header.Len = HTONS (4); // Set the length to lower than expected (12) + OptionPtr->Header.IAID = 0x12345678; + OptionPtr->T1 = 0x11111111; + OptionPtr->T2 = 0x22222222; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + // Set the InnerOptionLength to be less than the size of the option + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); + + // Now set the OptionLength to be less than the size of the option + OptionLength = sizeof (DHCPv6_OPTION_IA_NA) - 1; + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option is found +TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAValidOptionExpectSuccess) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIata; + OptionPtr->Header.Len = HTONS (4 + 4); // Valid length has to be more than 4 + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_SUCCESS); + ASSERT_EQ (InnerOptionLength, 4); + ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAInvalidSizeExpectFail) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIata; + OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); + + // Now lets try modifying the OptionLength to be less than the size of the option + OptionLength = sizeof (DHCPv6_OPTION_IA_TA) - 1; + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that any other Option Type fails +TEST_F (Dhcp6SeekInnerOptionSafeTest, InvalidOption) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Result; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = 0xC0DE; + OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Result = Dhcp6SeekInnerOptionSafe (0xC0DE, Option, OptionLength, &InnerOptionPtr, &InnerOptionLength); + ASSERT_EQ (Result, EFI_DEVICE_ERROR); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6SeekStsOption Tests +//////////////////////////////////////////////////////////////////////// + +#define PACKET_SIZE (1500) + +class Dhcp6SeekStsOptionTest : public ::testing::Test { +public: + DHCP6_INSTANCE Instance = { 0 }; + EFI_DHCP6_PACKET *Packet = NULL; + EFI_DHCP6_CONFIG_DATA Config = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Allocate a packet + Packet = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + ASSERT_NE (Packet, nullptr); + + // Initialize the packet + Packet->Size = PACKET_SIZE; + + Instance.Config = &Config; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + FreePool (Packet); + } +}; + +// Test Description: +// This test verifies that Dhcp6SeekStsOption returns EFI_DEVICE_ERROR when the option is invalid +// This verifies that the calling function is working as expected +TEST_F (Dhcp6SeekStsOptionTest, SeekIATAOptionExpectFail) { + EFI_STATUS Status; + UINT8 *Option = NULL; + UINT32 SearchPattern = SEARCH_PATTERN; + UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; + UINT16 *Len = NULL; + EFI_DHCP6_IA Ia = { 0 }; + + Ia.Descriptor.Type = DHCPV6_OPTION_IA_TA; + Ia.IaAddressCount = 1; + Ia.IaAddress[0].PreferredLifetime = 0xDEADBEEF; + Ia.IaAddress[0].ValidLifetime = 0xDEADAAAA; + Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + + Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; + + // Let's append the option to the packet + Status = Dhcp6AppendOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + Dhcp6OptStatusCode, + SearchPatternLength, + (UINT8 *)&SearchPattern + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + // Inner option length - this will be overwritten later + Len = (UINT16 *)(Option + 2); + + // Fill in the inner IA option + Status = Dhcp6AppendIaOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + &Ia, + 0x12345678, + 0x11111111, + 0x22222222 + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + // overwrite the len of inner Ia option + *Len = HTONS (3); + + Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_TA; + + Option = NULL; + Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); + + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. +TEST_F (Dhcp6SeekStsOptionTest, SeekIANAOptionExpectSuccess) { + EFI_STATUS Status = EFI_NOT_FOUND; + UINT8 *Option = NULL; + UINT32 SearchPattern = SEARCH_PATTERN; + UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; + EFI_DHCP6_IA Ia = { 0 }; + + Ia.Descriptor.Type = DHCPV6_OPTION_IA_NA; + Ia.IaAddressCount = 1; + Ia.IaAddress[0].PreferredLifetime = 0x11111111; + Ia.IaAddress[0].ValidLifetime = 0x22222222; + Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; + Packet->Length = sizeof (EFI_DHCP6_HEADER); + + Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + Dhcp6OptStatusCode, + SearchPatternLength, + (UINT8 *)&SearchPattern + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + Status = Dhcp6AppendIaOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + &Ia, + 0x12345678, + 0x11111111, + 0x22222222 + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_NA; + + Option = NULL; + Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); + + ASSERT_EQ (Status, EFI_SUCCESS); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114256): https://edk2.groups.io/g/devel/message/114256 Mute This Topic: https://groups.io/mt/103926734/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 SECURITY PATCH - Patch TCBZ4536 CVE-2023-45231 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Ip6Dxe/Ip6Option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.c +++ b/NetworkPkg/Ip6Dxe/Ip6Option.c @@ -XXX,XX +XXX,XX @@ Ip6IsNDOptionValid ( return FALSE; } + // + // Cannot process truncated options. + // Cannot process options with a length of 0 as there is no Type field. + // + if (OptionLen < sizeof (IP6_OPTION_HEADER)) { + return FALSE; + } + Offset = 0; // -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114257): https://edk2.groups.io/g/devel/message/114257 Mute This Topic: https://groups.io/mt/103926735/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 SECURITY PATCH - Unit Tests TCBZ4536 CVE-2023-45231 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 42 ++++++ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 20 +++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 129 ++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # Build HOST_APPLICATION that tests NetworkPkg # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf + NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the Ip6Dxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = Ip6DxeUnitTest + FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A + VERSION_STRING = 1.0 + MODULE_TYPE = HOST_APPLICATION +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# +[Sources] + Ip6DxeGoogleTest.cpp + Ip6OptionGoogleTest.cpp + ../Ip6Option.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the Ip6Dxe module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Tests for Ip6Option.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include "../Ip6Impl.h" + #include "../Ip6Option.h" +} + +///////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////// + +#define IP6_PREFIX_INFO_OPTION_DATA_LEN 32 +#define OPTION_HEADER_IP6_PREFIX_DATA_LEN (sizeof (IP6_OPTION_HEADER) + IP6_PREFIX_INFO_OPTION_DATA_LEN) + +//////////////////////////////////////////////////////////////////////// +// Symbol Definitions +// These functions are not directly under test - but required to compile +//////////////////////////////////////////////////////////////////////// +UINT32 mIp6Id; + +EFI_STATUS +Ip6SendIcmpError ( + IN IP6_SERVICE *IpSb, + IN NET_BUF *Packet, + IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL, + IN EFI_IPv6_ADDRESS *DestinationAddress, + IN UINT8 Type, + IN UINT8 Code, + IN UINT32 *Pointer OPTIONAL + ) +{ + // .. + return EFI_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////// +// Ip6OptionValidation Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Ip6OptionValidationTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +// Test Description: +// Null option should return false +TEST_F (Ip6OptionValidationTest, NullOptionShouldReturnFalse) { + UINT8 *option = nullptr; + UINT16 optionLen = 10; // Provide a suitable length + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Truncated option should return false +TEST_F (Ip6OptionValidationTest, TruncatedOptionShouldReturnFalse) { + UINT8 option[] = { 0x01 }; // Provide a truncated option + UINT16 optionLen = 1; + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with zero length should return false +TEST_F (Ip6OptionValidationTest, OptionWithZeroLengthShouldReturnFalse) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 0; + UINT8 option[sizeof (IP6_OPTION_HEADER)]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + UINT16 optionLen = sizeof (IP6_OPTION_HEADER); + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with valid length should return true +TEST_F (Ip6OptionValidationTest, ValidPrefixInfoOptionShouldReturnTrue) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 4; // Length 4 * 8 = 32 + UINT8 option[OPTION_HEADER_IP6_PREFIX_DATA_LEN]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + + EXPECT_TRUE (Ip6IsNDOptionValid (option, IP6_PREFIX_INFO_OPTION_DATA_LEN)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with invalid length should return false +TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 3; // Length 3 * 8 = 24 (Invalid) + UINT8 option[sizeof (IP6_OPTION_HEADER)]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + UINT16 optionLen = sizeof (IP6_OPTION_HEADER); + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114258): https://edk2.groups.io/g/devel/message/114258 Mute This Topic: https://groups.io/mt/103926736/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 SECURITY PATCH - Patch TCBZ4537 CVE-2023-45232 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') TCBZ4538 CVE-2023-45233 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Ip6Dxe/Ip6Option.h | 89 +++++++++++++++++++++++++++++++++++ NetworkPkg/Ip6Dxe/Ip6Option.c | 76 +++++++++++++++++++++++++----- 2 files changed, 154 insertions(+), 11 deletions(-) diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.h b/NetworkPkg/Ip6Dxe/Ip6Option.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.h +++ b/NetworkPkg/Ip6Dxe/Ip6Option.h @@ -XXX,XX +XXX,XX @@ #define IP6_FRAGMENT_OFFSET_MASK (~0x3) +// +// Per RFC8200 Section 4.2 +// +// Two of the currently-defined extension headers -- the Hop-by-Hop +// Options header and the Destination Options header -- carry a variable +// number of type-length-value (TLV) encoded "options", of the following +// format: +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - +// | Option Type | Opt Data Len | Option Data +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - +// +// Option Type 8-bit identifier of the type of option. +// +// Opt Data Len 8-bit unsigned integer. Length of the Option +// Data field of this option, in octets. +// +// Option Data Variable-length field. Option-Type-specific +// data. +// +#define IP6_SIZE_OF_OPT_TYPE (sizeof(UINT8)) +#define IP6_SIZE_OF_OPT_LEN (sizeof(UINT8)) +#define IP6_COMBINED_SIZE_OF_OPT_TAG_AND_LEN (IP6_SIZE_OF_OPT_TYPE + IP6_SIZE_OF_OPT_LEN) +#define IP6_OFFSET_OF_OPT_LEN(a) (a + IP6_SIZE_OF_OPT_TYPE) +STATIC_ASSERT ( + IP6_OFFSET_OF_OPT_LEN (0) == 1, + "The Length field should be 1 octet (8 bits) past the start of the option" + ); + +#define IP6_NEXT_OPTION_OFFSET(offset, length) (offset + IP6_COMBINED_SIZE_OF_OPT_TAG_AND_LEN + length) +STATIC_ASSERT ( + IP6_NEXT_OPTION_OFFSET (0, 0) == 2, + "The next option is minimally the combined size of the option tag and length" + ); + +// +// For more information see RFC 8200, Section 4.3, 4.4, and 4.6 +// +// This example format is from section 4.6 +// This does not apply to fragment headers +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Next Header | Hdr Ext Len | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// | | +// . . +// . Header-Specific Data . +// . . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Next Header 8-bit selector. Identifies the type of +// header immediately following the extension +// header. Uses the same values as the IPv4 +// Protocol field [IANA-PN]. +// +// Hdr Ext Len 8-bit unsigned integer. Length of the +// Destination Options header in 8-octet units, +// not including the first 8 octets. + +// +// These defines apply to the following: +// 1. Hop by Hop +// 2. Routing +// 3. Destination +// +#define IP6_SIZE_OF_EXT_NEXT_HDR (sizeof(UINT8)) +#define IP6_SIZE_OF_HDR_EXT_LEN (sizeof(UINT8)) + +#define IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN (IP6_SIZE_OF_EXT_NEXT_HDR + IP6_SIZE_OF_HDR_EXT_LEN) +STATIC_ASSERT ( + IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN == 2, + "The combined size of Next Header and Len is two 8 bit fields" + ); + +// +// The "+ 1" in this calculation is because of the "not including the first 8 octets" +// part of the definition (meaning the value of 0 represents 64 bits) +// +#define IP6_HDR_EXT_LEN(a) (((UINT16)(UINT8)(a) + 1) * 8) + +// This is the maxmimum length permissible by a extension header +// Length is UINT8 of 8 octets not including the first 8 octets +#define IP6_MAX_EXT_DATA_LENGTH (IP6_HDR_EXT_LEN (MAX_UINT8) - IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN) +STATIC_ASSERT ( + IP6_MAX_EXT_DATA_LENGTH == 2046, + "Maximum data length is ((MAX_UINT8 + 1) * 8) - 2" + ); + typedef struct _IP6_FRAGMENT_HEADER { UINT8 NextHeader; UINT8 Reserved; diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.c +++ b/NetworkPkg/Ip6Dxe/Ip6Option.c @@ -XXX,XX +XXX,XX @@ @param[in] IpSb The IP6 service data. @param[in] Packet The to be validated packet. @param[in] Option The first byte of the option. - @param[in] OptionLen The length of the whole option. + @param[in] OptionLen The length of all options, expressed in byte length of octets. + Maximum length is 2046 bytes or ((n + 1) * 8) - 2 where n is 255. @param[in] Pointer Identifies the octet offset within the invoking packet where the error was detected. @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( IN IP6_SERVICE *IpSb, IN NET_BUF *Packet, IN UINT8 *Option, - IN UINT8 OptionLen, + IN UINT16 OptionLen, IN UINT32 Pointer ) { - UINT8 Offset; - UINT8 OptionType; + UINT16 Offset; + UINT8 OptionType; + UINT8 OptDataLen; + + if (Option == NULL) { + ASSERT (Option != NULL); + return FALSE; + } + + if ((OptionLen <= 0) || (OptionLen > IP6_MAX_EXT_DATA_LENGTH)) { + ASSERT (OptionLen > 0 && OptionLen <= IP6_MAX_EXT_DATA_LENGTH); + return FALSE; + } + + if (Packet == NULL) { + ASSERT (Packet != NULL); + return FALSE; + } + + if (IpSb == NULL) { + ASSERT (IpSb != NULL); + return FALSE; + } Offset = 0; @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( // // It is a PadN option // - Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2); + OptDataLen = *(IP6_OFFSET_OF_OPT_LEN (Option + Offset)); + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); break; case Ip6OptionRouterAlert: // @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( // switch (OptionType & Ip6OptionMask) { case Ip6OptionSkip: - Offset = (UINT8)(Offset + *(Option + Offset + 1)); + OptDataLen = *(IP6_OFFSET_OF_OPT_LEN (Option + Offset)); + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); break; case Ip6OptionDiscard: return FALSE; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( UINT32 Pointer; UINT32 Offset; UINT8 *Option; - UINT8 OptionLen; + UINT16 OptionLen; BOOLEAN Flag; UINT8 CountD; UINT8 CountA; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // Fall through // case IP6_DESTINATION: + // + // See https://www.rfc-editor.org/rfc/rfc2460#section-4.2 page 23 + // + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Next Header | Hdr Ext Len | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // . . + // . Options . + // . . + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // + // Next Header 8-bit selector. Identifies the type of header + // immediately following the Destination Options + // header. Uses the same values as the IPv4 + // Protocol field [RFC-1700 et seq.]. + // + // Hdr Ext Len 8-bit unsigned integer. Length of the + // Destination Options header in 8-octet units, not + // including the first 8 octets. + // + // Options Variable-length field, of length such that the + // complete Destination Options header is an + // integer multiple of 8 octets long. Contains one + // or more TLV-encoded options, as described in + // section 4.2. + // + if (*NextHeader == IP6_DESTINATION) { CountD++; } @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( Offset++; Option = ExtHdrs + Offset; - OptionLen = (UINT8)((*Option + 1) * 8 - 2); + OptionLen = IP6_HDR_EXT_LEN (*Option) - IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN; Option++; Offset++; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // // Ignore the routing header and proceed to process the next header. // - Offset = Offset + (RoutingHead->HeaderLen + 1) * 8; + Offset = Offset + IP6_HDR_EXT_LEN (RoutingHead->HeaderLen); if (UnFragmentLen != NULL) { *UnFragmentLen = Offset; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // to the packet's source address, pointing to the unrecognized routing // type. // - Pointer = Offset + 2 + sizeof (EFI_IP6_HEADER); + Pointer = Offset + IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN + sizeof (EFI_IP6_HEADER); if ((IpSb != NULL) && (Packet != NULL) && !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) { @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // // RFC2402, Payload length is specified in 32-bit words, minus "2". // - OptionLen = (UINT8)((*Option + 2) * 4); + OptionLen = ((UINT16)(*Option + 2) * 4); Offset = Offset + OptionLen; break; -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114259): https://edk2.groups.io/g/devel/message/114259 Mute This Topic: https://groups.io/mt/103926738/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 SECURITY PATCH - Unit Tests TCBZ4537 CVE-2023-45232 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') TCBZ4538 CVE-2023-45233 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 10 +- .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 +++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 282 ++++++++++++++++++ 3 files changed, 328 insertions(+), 4 deletions(-) create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ ## @file -# Unit test suite for the Ip6Dxe using Google Test +# Unit test suite for the Ip6DxeGoogleTest using Google Test # # Copyright (c) Microsoft Corporation.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent ## [Defines] INF_VERSION = 0x00010017 - BASE_NAME = Ip6DxeUnitTest - FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A + BASE_NAME = Ip6DxeGoogleTest + FILE_GUID = AE39981C-B7FE-41A8-A9C2-F41910477CA3 VERSION_STRING = 1.0 MODULE_TYPE = HOST_APPLICATION # @@ -XXX,XX +XXX,XX @@ [Defines] # VALID_ARCHITECTURES = IA32 X64 AARCH64 # [Sources] + ../Ip6Option.c + Ip6OptionGoogleTest.h Ip6DxeGoogleTest.cpp Ip6OptionGoogleTest.cpp - ../Ip6Option.c + Ip6OptionGoogleTest.h [Packages] MdePkg/MdePkg.dec diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + Exposes the functions needed to test the Ip6Option module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef EFI_IP6_OPTION_GOOGLE_TEST_H_ +#define EFI_IP6_OPTION_GOOGLE_TEST_H_ + +#include <Uefi.h> +#include "../Ip6Impl.h" + +/** + Validate the IP6 option format for both the packets we received + and that we will transmit. It will compute the ICMPv6 error message fields + if the option is malformatted. + + @param[in] IpSb The IP6 service data. + @param[in] Packet The to be validated packet. + @param[in] Option The first byte of the option. + @param[in] OptionLen The length of the whole option. + @param[in] Pointer Identifies the octet offset within + the invoking packet where the error was detected. + + + @retval TRUE The option is properly formatted. + @retval FALSE The option is malformatted. + +**/ +BOOLEAN +Ip6IsOptionValid ( + IN IP6_SERVICE *IpSb, + IN NET_BUF *Packet, + IN UINT8 *Option, + IN UINT16 OptionLen, + IN UINT32 Pointer + ); + +#endif // __EFI_IP6_OPTION_GOOGLE_TEST_H__ diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ extern "C" { #include <Library/DebugLib.h> #include "../Ip6Impl.h" #include "../Ip6Option.h" + #include "Ip6OptionGoogleTest.h" } ///////////////////////////////////////////////////////////////////////// @@ -XXX,XX +XXX,XX @@ TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse) EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); } + +//////////////////////////////////////////////////////////////////////// +// Ip6IsOptionValid Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Ip6IsOptionValidTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Ip6IsOptionValidTest Tests +/////////////////////////////////////////////////////////////////////////////// + +// Test Description +// Verify that a NULL option is Invalid +TEST_F (Ip6IsOptionValidTest, NullOptionShouldReturnTrue) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + IP6_SERVICE *IpSb = NULL; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + EXPECT_FALSE (Ip6IsOptionValid (IpSb, &Packet, NULL, 0, 0)); +} + +// Test Description +// Verify that an unknown option with a length of 0 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength0) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 0; // This will cause an infinite loop if the function is not working correctly + + // This should be a valid option even though the length is 0 + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that an unknown option with a length of 1 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength1) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 1; // This will cause an infinite loop if the function is not working correctly + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that an unknown option with a length of 2 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyIpSkipUnknownOption) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 2; // Valid length for an unknown option + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that Ip6OptionPad1 is valid with a length of 0 +TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPad1) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPad1; + optionHeader.Length = 0; + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that Ip6OptionPadN doesn't overflow with various lengths +TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPadN) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPadN; + optionHeader.Length = 0xFF; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFE; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFD; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFC; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify an unknown option doesn't cause an infinite loop with various lengths +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLengthAttemptOverflow) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 0xFF; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFE; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFD; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFC; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that the function supports multiple options +TEST_F (Ip6IsOptionValidTest, MultiOptionSupport) { + UINT16 HdrLen; + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + UINT8 ExtHdr[1024] = { 0 }; + UINT8 *Cursor = ExtHdr; + IP6_OPTION_HEADER *Option = (IP6_OPTION_HEADER *)ExtHdr; + + // Let's start chaining options + + Option->Type = 23; // Unknown Option + Option->Length = 0xFC; + + Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionPad1; + + Cursor += sizeof (1); + + // Type and length aren't processed, instead it just moves the pointer forward by 4 bytes + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionRouterAlert; + Option->Length = 4; + + Cursor += sizeof (IP6_OPTION_HEADER) + 4; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionPadN; + Option->Length = 0xFC; + + Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionRouterAlert; + Option->Length = 4; + + Cursor += sizeof (IP6_OPTION_HEADER) + 4; + + // Total 524 + + HdrLen = (UINT16)(Cursor - ExtHdr); + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, ExtHdr, HdrLen, 0)); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114260): https://edk2.groups.io/g/devel/message/114260 Mute This Topic: https://groups.io/mt/103926739/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 SECURITY PATCH - Patch TCBZ4539 CVE-2023-45234 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 71 +++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -XXX,XX +XXX,XX @@ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent @@ -XXX,XX +XXX,XX @@ PxeBcSelectDhcp6Offer ( } } +/** + Cache the DHCPv6 DNS Server addresses + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. + + @retval EFI_SUCCESS Cache the DHCPv6 DNS Server address successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_DEVICE_ERROR The DNS Server Address Length provided by a untrusted + option is not a multiple of 16 bytes (sizeof (EFI_IPv6_ADDRESS)). +**/ +EFI_STATUS +PxeBcCacheDnsServerAddresses ( + IN PXEBC_PRIVATE_DATA *Private, + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ) +{ + UINT16 DnsServerLen; + + DnsServerLen = NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen); + // + // Make sure that the number is nonzero + // + if (DnsServerLen == 0) { + return EFI_DEVICE_ERROR; + } + + // + // Make sure the DnsServerlen is a multiple of EFI_IPv6_ADDRESS (16) + // + if (DnsServerLen % sizeof (EFI_IPv6_ADDRESS) != 0) { + return EFI_DEVICE_ERROR; + } + + // + // This code is currently written to only support a single DNS Server instead + // of multiple such as is spec defined (RFC3646, Section 3). The proper behavior + // would be to allocate the full space requested, CopyMem all of the data, + // and then add a DnsServerCount field to Private and update additional code + // that depends on this. + // + // To support multiple DNS servers the `AllocationSize` would need to be changed to DnsServerLen + // + // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886 + // + Private->DnsServer = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS)); + if (Private->DnsServer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Intentionally only copy over the first server address. + // To support multiple DNS servers, the `Length` would need to be changed to DnsServerLen + // + CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); + + return EFI_SUCCESS; +} + /** Handle the DHCPv6 offer packet. @@ -XXX,XX +XXX,XX @@ PxeBcHandleDhcp6Offer ( UINT32 SelectIndex; UINT32 Index; + ASSERT (Private != NULL); ASSERT (Private->SelectIndex > 0); SelectIndex = (UINT32)(Private->SelectIndex - 1); ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); @@ -XXX,XX +XXX,XX @@ PxeBcHandleDhcp6Offer ( Status = EFI_SUCCESS; // - // First try to cache DNS server address if DHCP6 offer provides. + // First try to cache DNS server addresses if DHCP6 offer provides. // if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { - Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); - if (Private->DnsServer == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = PxeBcCacheDnsServerAddresses (Private, Cache6); + if (EFI_ERROR (Status)) { + return Status; } - - CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); } if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114261): https://edk2.groups.io/g/devel/message/114261 Mute This Topic: https://groups.io/mt/103926740/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 SECURITY PATCH - Unit Tests TCBZ4539 CVE-2023-45234 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 48 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 50 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 300 ++++++++++++++++++ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 19 ++ 5 files changed, 418 insertions(+) create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf + NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the UefiPxeBcDxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] +INF_VERSION = 0x00010005 +BASE_NAME = UefiPxeBcDxeGoogleTest +FILE_GUID = 77D45C64-EC1E-4174-887B-886E89FD1EDF +MODULE_TYPE = HOST_APPLICATION +VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + UefiPxeBcDxeGoogleTest.cpp + PxeBcDhcp6GoogleTest.cpp + PxeBcDhcp6GoogleTest.h + ../PxeBcDhcp6.c + ../PxeBcSupport.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + gEfiDns6ServiceBindingProtocolGuid + gEfiDns6ProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + This file exposes the internal interfaces which may be unit tested + for the PxeBcDhcp6Dxe driver. + + Copyright (c) Microsoft Corporation.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef PXE_BC_DHCP6_GOOGLE_TEST_H_ +#define PXE_BC_DHCP6_GOOGLE_TEST_H_ + +// +// Minimal includes needed to compile +// +#include <Uefi.h> +#include "../PxeBcImpl.h" + +/** + Handle the DHCPv6 offer packet. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. + @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet. + +**/ +EFI_STATUS +PxeBcHandleDhcp6Offer ( + IN PXEBC_PRIVATE_DATA *Private + ); + +/** + Cache the DHCPv6 Server address + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. + + @retval EFI_SUCCESS Cache the DHCPv6 Server address successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_DEVICE_ERROR Failed to cache the DHCPv6 Server address. +**/ +EFI_STATUS +PxeBcCacheDnsServerAddresses ( + IN PXEBC_PRIVATE_DATA *Private, + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ); + +#endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Host based unit test for PxeBcDhcp6.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include "../PxeBcImpl.h" + #include "../PxeBcDhcp6.h" + #include "PxeBcDhcp6GoogleTest.h" +} + +/////////////////////////////////////////////////////////////////////////////// +// Definitions +/////////////////////////////////////////////////////////////////////////////// + +#define PACKET_SIZE (1500) + +typedef struct { + UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03) + UINT16 OptionLen; // The length of the option (e.g., 16 bytes) + UINT8 ServerId[16]; // The 16-byte DHCPv6 Server Identifier +} DHCP6_OPTION_SERVER_ID; + +/////////////////////////////////////////////////////////////////////////////// +/// Symbol Definitions +/////////////////////////////////////////////////////////////////////////////// + +EFI_STATUS +MockUdpWrite ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp OPTIONAL, + IN EFI_IP_ADDRESS *SrcIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +MockUdpRead ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL, + IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +MockConfigure ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +// Needed by PxeBcSupport +EFI_STATUS +EFIAPI +QueueDpc ( + IN EFI_TPL DpcTpl, + IN EFI_DPC_PROCEDURE DpcProcedure, + IN VOID *DpcContext OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcHandleDhcp6OfferTest Tests +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcHandleDhcp6OfferTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + EFI_PXE_BASE_CODE_MODE Mode = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + + // Need to setup the EFI_PXE_BASE_CODE_MODE + Private.PxeBc.Mode = &Mode; + + // for this test it doesn't really matter what the Dhcpv6 ack is set to + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +// Note: +// Testing PxeBcHandleDhcp6Offer() is difficult because it depends on a +// properly setup Private structure. Attempting to properly test this function +// without a signficant refactor is a fools errand. Instead, we will test +// that we can prevent an overflow in the function. +TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) { + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337); + + ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR); +} + +class PxeBcCacheDnsServerAddressesTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + } +}; + +// Test Description +// Test that we cache the DNS server address from the DHCPv6 offer packet +TEST_F (PxeBcCacheDnsServerAddressesTest, BasicUsageTest) { + UINT8 SearchPattern[16] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF }; + EFI_DHCP6_PACKET_OPTION *Option; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Option = (EFI_DHCP6_PACKET_OPTION *)AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + sizeof (SearchPattern)); + ASSERT_NE (Option, nullptr); + + Option->OpCode = DHCP6_OPT_SERVER_ID; + Option->OpLen = NTOHS (sizeof (SearchPattern)); + CopyMem (Option->Data, SearchPattern, sizeof (SearchPattern)); + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; + + Private.DnsServer = nullptr; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS); + ASSERT_NE (Private.DnsServer, nullptr); + ASSERT_EQ (CompareMem (Private.DnsServer, SearchPattern, sizeof (SearchPattern)), 0); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } + + if (Option) { + FreePool (Option); + } +} +// Test Description +// Test that we can prevent an overflow in the function +TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptOverflowTest) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR); + ASSERT_EQ (Private.DnsServer, nullptr); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} + +// Test Description +// Test that we can prevent an underflow in the function +TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptUnderflowTest) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (2); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR); + ASSERT_EQ (Private.DnsServer, nullptr); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} + +// Test Description +// Test that we can handle recursive dns (multiple dns entries) +TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + + EFI_IPv6_ADDRESS addresses[2] = { + // 2001:db8:85a3::8a2e:370:7334 + { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }, + // fe80::d478:91c3:ecd7:4ff9 + { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x78, 0x91, 0xc3, 0xec, 0xd7, 0x4f, 0xf9 } + }; + + CopyMem (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, &addresses, sizeof (addresses)); + + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (sizeof (addresses)); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS); + + ASSERT_NE (Private.DnsServer, nullptr); + + // + // This is expected to fail until DnsServer supports multiple DNS servers + // + // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886 + // + // Disabling: + // ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the UefiPxeBcDxe module. + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114262): https://edk2.groups.io/g/devel/message/114262 Mute This Topic: https://groups.io/mt/103926741/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
This adds support for GetTime Google Test Mock Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Zhiguang Liu <zhiguang.liu@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- .../GoogleTest/Library/MockUefiRuntimeServicesTableLib.h | 7 +++++++ .../MockUefiRuntimeServicesTableLib.cpp | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h b/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h +++ b/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h @@ -XXX,XX +XXX,XX @@ struct MockUefiRuntimeServicesTableLib { IN UINTN DataSize, IN VOID *Data) ); + + MOCK_FUNCTION_DECLARATION ( + EFI_STATUS, + gRT_GetTime, + (OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL) + ); }; #endif diff --git a/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp b/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp +++ b/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp @@ -XXX,XX +XXX,XX @@ MOCK_INTERFACE_DEFINITION (MockUefiRuntimeServicesTableLib); MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_GetVariable, 5, EFIAPI); MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_SetVariable, 5, EFIAPI); +MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_GetTime, 2, EFIAPI); static EFI_RUNTIME_SERVICES localRt = { - { 0 }, // EFI_TABLE_HEADER + { 0 }, // EFI_TABLE_HEADER - NULL, // EFI_GET_TIME + gRT_GetTime, // EFI_GET_TIME NULL, // EFI_SET_TIME NULL, // EFI_GET_WAKEUP_TIME NULL, // EFI_SET_WAKEUP_TIME -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114263): https://edk2.groups.io/g/devel/message/114263 Mute This Topic: https://groups.io/mt/103926742/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 SECURITY PATCH - Patch TCBZ4540 CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 ++++++ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 77 ++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h @@ -XXX,XX +XXX,XX @@ #define PXEBC_ADDR_START_DELIMITER '[' #define PXEBC_ADDR_END_DELIMITER ']' +// +// A DUID consists of a 2-octet type code represented in network byte +// order, followed by a variable number of octets that make up the +// actual identifier. The length of the DUID (not including the type +// code) is at least 1 octet and at most 128 octets. +// +#define PXEBC_MIN_SIZE_OF_DUID (sizeof(UINT16) + 1) +#define PXEBC_MAX_SIZE_OF_DUID (sizeof(UINT16) + 128) + +// +// This define represents the combineds code and length field from +// https://datatracker.ietf.org/doc/html/rfc3315#section-22.1 +// +#define PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN \ + (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode) + \ + sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen)) + #define GET_NEXT_DHCP6_OPTION(Opt) \ (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \ sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( EFI_STATUS Status; EFI_DHCP6_PACKET *IndexOffer; UINT8 *Option; + UINTN DiscoverLenNeeded; PxeBc = &Private->PxeBc; Request = Private->Dhcp6Request; @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( return EFI_DEVICE_ERROR; } - Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); + DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); + Discover = AllocateZeroPool (DiscoverLenNeeded); if (Discover == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( DHCP6_OPT_SERVER_ID ); if (Option == NULL) { - return EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; + goto ON_ERROR; } // // Add Server ID Option. // OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen); - CopyMem (DiscoverOpt, Option, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + + // + // Check that the minimum and maximum requirements are met + // + if ((OpLen < PXEBC_MIN_SIZE_OF_DUID) || (OpLen > PXEBC_MAX_SIZE_OF_DUID)) { + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + + // + // Check that the option length is valid. + // + if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + CopyMem (DiscoverOpt, Option, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } while (RequestLen < Request->Length) { @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( (OpCode != DHCP6_OPT_SERVER_ID) ) { + // + // Check that the option length is valid. + // + if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // // Copy all the options except IA option and Server ID // - CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } - RequestOpt += (OpLen + 4); - RequestLen += (OpLen + 4); + RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } // @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( UINT16 OpLen; UINT32 Xid; EFI_STATUS Status; + UINTN DiscoverLenNeeded; PxeBc = &Private->PxeBc; Mode = PxeBc->Mode; @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( return EFI_DEVICE_ERROR; } - Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); + DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); + Discover = AllocateZeroPool (DiscoverLenNeeded); if (Discover == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( DiscoverLen = sizeof (EFI_DHCP6_HEADER); RequestLen = DiscoverLen; + // + // The request packet is generated by the UEFI network stack. In the DHCP4 DORA and DHCP6 SARR sequence, + // the first (discover in DHCP4 and solicit in DHCP6) and third (request in both DHCP4 and DHCP6) are + // generated by the DHCP client (the UEFI network stack in this case). By the time this function executes, + // the DHCP sequence already has been executed once (see UEFI Specification Figures 24.2 and 24.3), with + // Private->Dhcp6Request being a cached copy of the DHCP6 request packet that UEFI network stack previously + // generated and sent. + // + // Therefore while this code looks like it could overflow, in practice it's not possible. + // while (RequestLen < Request->Length) { OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode); OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen); if ((OpCode != EFI_DHCP6_IA_TYPE_NA) && (OpCode != EFI_DHCP6_IA_TYPE_TA)) { + if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // // Copy all the options except IA option. // - CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } - RequestOpt += (OpLen + 4); - RequestLen += (OpLen + 4); + RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } Status = PxeBc->UdpWrite ( -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114264): https://edk2.groups.io/g/devel/message/114264 Mute This Topic: https://groups.io/mt/103926743/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 SECURITY PATCH - Unit Tests TCBZ4540 CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 5 +- .../GoogleTest/PxeBcDhcp6GoogleTest.h | 18 ++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 278 +++++++++++++++++- 3 files changed, 298 insertions(+), 3 deletions(-) diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf - NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf + NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf { + <LibraryClasses> + UefiRuntimeServicesTableLib|MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.inf + } # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h @@ -XXX,XX +XXX,XX @@ PxeBcCacheDnsServerAddresses ( IN PXEBC_DHCP6_PACKET_CACHE *Cache6 ); +/** + Build and send out the request packet for the bootfile, and parse the reply. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Index PxeBc option boot item type. + + @retval EFI_SUCCESS Successfully discovered the boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover the boot file. + +**/ +EFI_STATUS +PxeBcRequestBootService ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ); + #endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp @@ -XXX,XX +XXX,XX @@ Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ -#include <gtest/gtest.h> +#include <Library/GoogleTestLib.h> +#include <GoogleTest/Library/MockUefiLib.h> +#include <GoogleTest/Library/MockUefiRuntimeServicesTableLib.h> extern "C" { #include <Uefi.h> @@ -XXX,XX +XXX,XX @@ extern "C" { // Definitions /////////////////////////////////////////////////////////////////////////////// -#define PACKET_SIZE (1500) +#define PACKET_SIZE (1500) +#define REQUEST_OPTION_LENGTH (120) typedef struct { UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03) @@ -XXX,XX +XXX,XX @@ MockConfigure ( } // Needed by PxeBcSupport +EFI_STATUS +PxeBcDns6 ( + IN PXEBC_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + return EFI_SUCCESS; +} + +UINT32 +PxeBcBuildDhcp6Options ( + IN PXEBC_PRIVATE_DATA *Private, + OUT EFI_DHCP6_PACKET_OPTION **OptList, + IN UINT8 *Buffer + ) +{ + return EFI_SUCCESS; +} + EFI_STATUS EFIAPI QueueDpc ( @@ -XXX,XX +XXX,XX @@ TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) { ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR); } +/////////////////////////////////////////////////////////////////////////////// +// PxeBcCacheDnsServerAddresses Tests +/////////////////////////////////////////////////////////////////////////////// + class PxeBcCacheDnsServerAddressesTest : public ::testing::Test { public: PXEBC_PRIVATE_DATA Private = { 0 }; @@ -XXX,XX +XXX,XX @@ TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) { FreePool (Private.DnsServer); } } + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcRequestBootServiceTest Test Cases +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcRequestBootServiceTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +TEST_F (PxeBcRequestBootServiceTest, ServerDiscoverBasicUsageTest) { + PxeBcRequestBootServiceTest::Private.OfferBuffer[0].Dhcp6.OfferType = PxeOfferTypeProxyBinl; + + DHCP6_OPTION_SERVER_ID Server = { 0 }; + + Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID); + Server.OptionLen = HTONS (16); // valid length + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer[Index].Dhcp6.Packet.Offer; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &Server, sizeof (Server)); + Cursor += sizeof (Server); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS); +} + +TEST_F (PxeBcRequestBootServiceTest, AttemptDiscoverOverFlowExpectFailure) { + PxeBcRequestBootServiceTest::Private.OfferBuffer[0].Dhcp6.OfferType = PxeOfferTypeProxyBinl; + + DHCP6_OPTION_SERVER_ID Server = { 0 }; + + Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID); + Server.OptionLen = HTONS (1500); // This length would overflow without a check + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer[Index].Dhcp6.Packet.Offer; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &Server, sizeof (Server)); + Cursor += sizeof (Server); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + // This is going to be stopped by the duid overflow check + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_INVALID_PARAMETER); +} + +TEST_F (PxeBcRequestBootServiceTest, RequestBasicUsageTest) { + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = 0; // valid length + + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request[Index]; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS); +} + +TEST_F (PxeBcRequestBootServiceTest, AttemptRequestOverFlowExpectFailure) { + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = 1500; // this length would overflow without a check + + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request[Index]; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_OUT_OF_RESOURCES); +} + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcDhcp6Discover Test +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcDhcp6DiscoverTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + +protected: + MockUefiRuntimeServicesTableLib RtServicesMock; + + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +// Test Description +// This will cause an overflow by an untrusted packet during the option parsing +TEST_F (PxeBcDhcp6DiscoverTest, BasicOverflowTest) { + EFI_IPv6_ADDRESS DestIp = { 0 }; + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = HTONS (0xFFFF); // overflow + + UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + Private.Dhcp6Request->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request); + + EXPECT_CALL (RtServicesMock, gRT_GetTime) + .WillOnce (::testing::Return (0)); + + ASSERT_EQ ( + PxeBcDhcp6Discover ( + &(PxeBcDhcp6DiscoverTest::Private), + 0, + NULL, + FALSE, + (EFI_IP_ADDRESS *)&DestIp + ), + EFI_OUT_OF_RESOURCES + ); +} + +// Test Description +// This will test that we can handle a packet with a valid option length +TEST_F (PxeBcDhcp6DiscoverTest, BasicUsageTest) { + EFI_IPv6_ADDRESS DestIp = { 0 }; + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = HTONS (0x30); + + UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + Private.Dhcp6Request->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request); + + EXPECT_CALL (RtServicesMock, gRT_GetTime) + .WillOnce (::testing::Return (0)); + + ASSERT_EQ ( + PxeBcDhcp6Discover ( + &(PxeBcDhcp6DiscoverTest::Private), + 0, + NULL, + FALSE, + (EFI_IP_ADDRESS *)&DestIp + ), + EFI_SUCCESS + ); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114265): https://edk2.groups.io/g/devel/message/114265 Mute This Topic: https://groups.io/mt/103926744/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
This creates / adds a security file that tracks the security fixes found in this package and can be used to find the fixes that were applied. Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/SecurityFixes.yaml | 123 ++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 NetworkPkg/SecurityFixes.yaml diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/SecurityFixes.yaml @@ -XXX,XX +XXX,XX @@ +## @file +# Security Fixes for SecurityPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +CVE_2023_45229: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit Tests" + cve: CVE-2023-45229 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 01 - edk2/NetworkPkg: Out-of-bounds read when processing IA_NA/IA_TA options in a DHCPv6 Advertise message" + note: + files_impacted: + - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c + - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4534 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45229 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45230: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit Tests" + cve: CVE-2023-45230 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 02 - edk2/NetworkPkg: Buffer overflow in the DHCPv6 client via a long Server ID option" + note: + files_impacted: + - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c + - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4535 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45230 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45231: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Unit Tests" + cve: CVE-2023-45231 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 03 - edk2/NetworkPkg: Out-of-bounds read when handling a ND Redirect message with truncated options" + note: + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4536 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45231 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45232: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" + cve: CVE-2023-45232 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 04 - edk2/NetworkPkg: Infinite loop when parsing unknown options in the Destination Options header" + note: + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + - NetworkPkg/Ip6Dxe/Ip6Option.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4537 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45232 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45233: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" + cve: CVE-2023-45233 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 05 - edk2/NetworkPkg: Infinite loop when parsing a PadN option in the Destination Options header " + note: This was fixed along with CVE-2023-45233 + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + - NetworkPkg/Ip6Dxe/Ip6Option.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4538 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45233 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45234: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Unit Tests" + cve: CVE-2023-45234 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 06 - edk2/NetworkPkg: Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise message" + note: + files_impacted: + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4539 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45234 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45235: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Unit Tests" + cve: CVE-2023-45235 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 07 - edk2/NetworkPkg: Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message" + note: + files_impacted: + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4540 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45235 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114266): https://edk2.groups.io/g/devel/message/114266 Mute This Topic: https://groups.io/mt/103926745/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
The security patches contained in this series with the exception of "MdePkg/Test: Add gRT_GetTime Google Test Mock" and "NetworkPkg: : Adds a SecurityFix.yaml file" have been reviewed during GHSA-hc6x-cw6p-gj7h infosec review. This patch series contains the following security patches for the security vulnerabilities found by QuarksLab in the EDK II Network Stack: CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read CVE-2023-45230 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer CVE-2023-45231 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read CVE-2023-45232 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') CVE-2023-45233 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') CVE-2023-45234 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer NetworkPkg: Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> MdePkg: Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Zhiguang Liu <zhiguang.liu@intel.com> Doug Flick (8): NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 Patch NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 Unit Tests NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Patch NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Patch NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Unit Tests NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Patch NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Unit Tests Douglas Flick [MSFT] (7): NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch NetworkPkg: : Add Unit tests to CI and create Host Test DSC NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit Tests NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit Tests MdePkg: Test: Add gRT_GetTime Google Test Mock NetworkPkg: : Adds a SecurityFix.yaml file NetworkPkg/Test/NetworkPkgHostTest.dsc | 105 +++ .../GoogleTest/Dhcp6DxeGoogleTest.inf | 44 + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 44 + .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 48 + .../Library/MockUefiRuntimeServicesTableLib.h | 7 + NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 143 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 78 +- .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 ++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 + NetworkPkg/Ip6Dxe/Ip6Nd.h | 35 + NetworkPkg/Ip6Dxe/Ip6Option.h | 71 ++ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 68 ++ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 + NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 612 ++++++++----- NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 373 ++++++-- NetworkPkg/Ip6Dxe/Ip6Option.c | 84 +- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 148 ++- .../MockUefiRuntimeServicesTableLib.cpp | 5 +- .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 20 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 839 ++++++++++++++++++ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 20 + .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 407 +++++++++ NetworkPkg/NetworkPkg.ci.yaml | 7 +- NetworkPkg/SecurityFixes.yaml | 123 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 574 ++++++++++++ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 19 + 26 files changed, 3650 insertions(+), 339 deletions(-) create mode 100644 NetworkPkg/Test/NetworkPkgHostTest.dsc create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp create mode 100644 NetworkPkg/SecurityFixes.yaml create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114462): https://edk2.groups.io/g/devel/message/114462 Mute This Topic: https://groups.io/mt/103964975/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4535 Bug Details: PixieFail Bug #2 CVE-2023-45230 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Changes Overview: > -UINT8 * > +EFI_STATUS > Dhcp6AppendOption ( > - IN OUT UINT8 *Buf, > - IN UINT16 OptType, > - IN UINT16 OptLen, > - IN UINT8 *Data > + IN OUT EFI_DHCP6_PACKET *Packet, > + IN OUT UINT8 **PacketCursor, > + IN UINT16 OptType, > + IN UINT16 OptLen, > + IN UINT8 *Data > ); Dhcp6AppendOption() and variants can return errors now. All callsites are adapted accordingly. It gets passed in EFI_DHCP6_PACKET as additional parameter ... > + // > + // Verify the PacketCursor is within the packet > + // > + if ( (*PacketCursor < Packet->Dhcp6.Option) > + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) > + { > + return EFI_INVALID_PARAMETER; > + } ... so it can look at Packet->Size when checking buffer space. Also to allow Packet->Length updates. Lots of checks added. Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 43 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 78 +++--- NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 409 +++++++++++++++++++---------- NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 373 +++++++++++++++++++++----- 4 files changed, 666 insertions(+), 237 deletions(-) diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S') #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I') +// +// For more information on DHCP options see RFC 8415, Section 21.1 +// +// The format of DHCP options is: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | option-code | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | option-data | +// | (option-len octets) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16)) +#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16)) + +// +// Combined size of Code and Length +// +#define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \ + DHCP6_SIZE_OF_OPT_LEN) + +STATIC_ASSERT ( + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN == 4, + "Combined size of Code and Length must be 4 per RFC 8415" + ); + +// +// Offset to the length is just past the code +// +#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE) +STATIC_ASSERT ( + DHCP6_OPT_LEN_OFFSET (0) == 2, + "Offset of length is + 2 past start of option" + ); + +#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +STATIC_ASSERT ( + DHCP6_OPT_DATA_OFFSET (0) == 4, + "Offset to option data should be +4 from start of option" + ); + #define DHCP6_PACKET_ALL 0 #define DHCP6_PACKET_STATEFUL 1 #define DHCP6_PACKET_STATELESS 2 diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h @@ -XXX,XX +XXX,XX @@ Dhcp6OnTransmitted ( ); /** - Append the appointed option to the buf, and move the buf to the end. + Append the option to Buf, update the length of packet, and move Buf to the end. - @param[in, out] Buf The pointer to buffer. - @param[in] OptType The option type. - @param[in] OptLen The length of option content.s - @param[in] Data The pointer to the option content. - - @return Buf The position to append the next option. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. + @param[in] OptType The option type. + @param[in] OptLen The length of option contents. + @param[in] Data The pointer to the option content. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendOption ( - IN OUT UINT8 *Buf, - IN UINT16 OptType, - IN UINT16 OptLen, - IN UINT8 *Data + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN UINT16 OptType, + IN UINT16 OptLen, + IN UINT8 *Data ); /** - Append the Ia option to Buf, and move Buf to the end. - - @param[in, out] Buf The pointer to the position to append. + Append the appointed Ia option to Buf, update the Ia option length, and move Buf + to the end of the option. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Ia The pointer to the Ia. @param[in] T1 The time of T1. @param[in] T2 The time of T2. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next Ia option. - + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaOption ( - IN OUT UINT8 *Buf, - IN EFI_DHCP6_IA *Ia, - IN UINT32 T1, - IN UINT32 T2, - IN UINT32 MessageType + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN EFI_DHCP6_IA *Ia, + IN UINT32 T1, + IN UINT32 T2, + IN UINT32 MessageType ); /** Append the appointed Elapsed time option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Instance The pointer to the Dhcp6 instance. @param[out] Elapsed The pointer to the elapsed time value in the generated packet. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendETOption ( - IN OUT UINT8 *Buf, - IN DHCP6_INSTANCE *Instance, - OUT UINT16 **Elapsed + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN DHCP6_INSTANCE *Instance, + OUT UINT16 **Elapsed ); /** Set the elapsed time based on the given instance and the pointer to the elapsed time option. - @param[in] Elapsed The pointer to the position to append. - @param[in] Instance The pointer to the Dhcp6 instance. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ VOID SetElapsedTime ( diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent - **/ #include "Dhcp6Impl.h" @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendSolicitMsg ( Elapsed, Instance->Config->SolicitRetransmission ); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet); if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE; @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType); + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, + DecIa, + 0, + 0, + Packet->Dhcp6.Header.MessageType + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE; @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // ServerId is extracted from packet, it's network order. // - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType); + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, + RelIa, + 0, + 0, + Packet->Dhcp6.Header.MessageType + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - // - // Determine the size/length of packet - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( Instance->IaCb.Ia->State = Dhcp6Releasing; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } if (!RebindRequest) { // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Dhcp6OptServerId ); if (Option == NULL) { - FreePool (Packet); - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto ON_ERROR; } ServerId = (EFI_DHCP6_DUID *)(Option + 2); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptServerId), ServerId->Length, ServerId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing; Status = Dhcp6CallbackUser (Instance, Event, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( if (SendClientId) { Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, OptionRequest->OpCode, OptionRequest->OpLen, OptionRequest->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < OptionCount; Index++) { UserOpt = OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // @@ -XXX,XX +XXX,XX @@ Dhcp6SendInfoRequestMsg ( // Send info-request packet with no state. // Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( // Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); if (Packet == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; } Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( Cursor = Packet->Dhcp6.Option; Length = HTONS (ClientId->Length); - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, HTONS (Dhcp6OptClientId), Length, ClientId->Duid ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendETOption ( - Cursor, + Status = Dhcp6AppendETOption ( + Packet, + &Cursor, Instance, &Elapsed ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } - Cursor = Dhcp6AppendIaOption ( - Cursor, + Status = Dhcp6AppendIaOption ( + Packet, + &Cursor, Instance->IaCb.Ia, Instance->IaCb.T1, Instance->IaCb.T2, Packet->Dhcp6.Header.MessageType ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } // // Append user-defined when configurate Dhcp6 service. // for (Index = 0; Index < Instance->Config->OptionCount; Index++) { UserOpt = Instance->Config->OptionList[Index]; - Cursor = Dhcp6AppendOption ( - Cursor, + Status = Dhcp6AppendOption ( + Packet, + &Cursor, UserOpt->OpCode, UserOpt->OpLen, UserOpt->Data ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } - // - // Determine the size/length of packet. - // - Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); ASSERT (Packet->Size > Packet->Length + 8); // // Callback to user with the packet to be sent and check the user's feedback. // Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SendConfirmMsg ( Instance->StartTime = 0; Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); - if (EFI_ERROR (Status)) { - FreePool (Packet); - return Status; + goto ON_ERROR; } // // Enqueue the sent packet for the retransmission in case reply timeout. // return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); + +ON_ERROR: + + if (Packet) { + FreePool (Packet); + } + + return Status; } /** diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c @@ -XXX,XX +XXX,XX @@ Dhcp6OnTransmitted ( } /** - Append the option to Buf, and move Buf to the end. + Append the option to Buf, update the length of packet, and move Buf to the end. - @param[in, out] Buf The pointer to the buffer. - @param[in] OptType The option type. - @param[in] OptLen The length of option contents. - @param[in] Data The pointer to the option content. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. + @param[in] OptType The option type. + @param[in] OptLen The length of option contents. + @param[in] Data The pointer to the option content. - @return Buf The position to append the next option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendOption ( - IN OUT UINT8 *Buf, - IN UINT16 OptType, - IN UINT16 OptLen, - IN UINT8 *Data + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN UINT16 OptType, + IN UINT16 OptLen, + IN UINT8 *Data ) { + UINT32 Length; + UINT32 BytesNeeded; + // // The format of Dhcp6 option: // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // - ASSERT (OptLen != 0); + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } - WriteUnaligned16 ((UINT16 *)Buf, OptType); - Buf += 2; - WriteUnaligned16 ((UINT16 *)Buf, OptLen); - Buf += 2; - CopyMem (Buf, Data, NTOHS (OptLen)); - Buf += NTOHS (OptLen); + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } - return Buf; + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (OptLen == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + // + // Calculate the bytes needed for the option + // + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + NTOHS (OptLen); + + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + WriteUnaligned16 ((UINT16 *)*PacketCursor, OptType); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; + WriteUnaligned16 ((UINT16 *)*PacketCursor, OptLen); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; + CopyMem (*PacketCursor, Data, NTOHS (OptLen)); + *PacketCursor += NTOHS (OptLen); + + // Update the packet length by the length of the option + 4 bytes + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed IA Address option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] IaAddr The pointer to the IA Address. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaAddrOption ( - IN OUT UINT8 *Buf, + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, IN EFI_DHCP6_IA_ADDRESS *IaAddr, IN UINT32 MessageType ) { + UINT32 BytesNeeded; + UINT32 Length; + // The format of the IA Address option is: // // 0 1 2 3 @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaAddrOption ( // . . // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (IaAddr == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + BytesNeeded += sizeof (EFI_IPv6_ADDRESS); + // + // Even if the preferred-lifetime is 0, it still needs to store it. + // + BytesNeeded += sizeof (IaAddr->PreferredLifetime); + // + // Even if the valid-lifetime is 0, it still needs to store it. + // + BytesNeeded += sizeof (IaAddr->ValidLifetime); + + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of Ia Address option type // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptIaAddr)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptIaAddr)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; - WriteUnaligned16 ((UINT16 *)Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; - CopyMem (Buf, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); - Buf += sizeof (EFI_IPv6_ADDRESS); + CopyMem (*PacketCursor, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); + *PacketCursor += sizeof (EFI_IPv6_ADDRESS); // // Fill the value of preferred-lifetime and valid-lifetime. @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaAddrOption ( // should set to 0 when initiate a Confirm message. // if (MessageType != Dhcp6MsgConfirm) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->PreferredLifetime)); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->PreferredLifetime)); } - Buf += 4; + *PacketCursor += sizeof (IaAddr->PreferredLifetime); if (MessageType != Dhcp6MsgConfirm) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->ValidLifetime)); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->ValidLifetime)); } - Buf += 4; + *PacketCursor += sizeof (IaAddr->ValidLifetime); - return Buf; + // + // Update the packet length + // + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed Ia option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + will be updated. + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Ia The pointer to the Ia. @param[in] T1 The time of T1. @param[in] T2 The time of T2. @param[in] MessageType Message type of DHCP6 package. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendIaOption ( - IN OUT UINT8 *Buf, - IN EFI_DHCP6_IA *Ia, - IN UINT32 T1, - IN UINT32 T2, - IN UINT32 MessageType + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN EFI_DHCP6_IA *Ia, + IN UINT32 T1, + IN UINT32 T2, + IN UINT32 MessageType ) { - UINT8 *AddrOpt; - UINT16 *Len; - UINTN Index; + UINT8 *AddrOpt; + UINT16 *Len; + UINTN Index; + UINT32 BytesNeeded; + UINT32 Length; + EFI_STATUS Status; // // The format of IA_NA and IA_TA option: @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Ia == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + BytesNeeded += sizeof (Ia->Descriptor.IaId); + // + // + N for the IA_NA-options/IA_TA-options + // Dhcp6AppendIaAddrOption will need to check the length for each address + // + if (Ia->Descriptor.Type == Dhcp6OptIana) { + BytesNeeded += sizeof (T1) + sizeof (T2); + } + + // + // Space remaining in the packet + // + Length = (UINT16)(Packet->Size - Packet->Length); + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of Ia option type // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Ia->Descriptor.Type)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Ia->Descriptor.Type)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; // // Fill the len of Ia option later, keep the pointer first // - Len = (UINT16 *)Buf; - Buf += 2; + Len = (UINT16 *)*PacketCursor; + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; // // Fill the value of iaid // - WriteUnaligned32 ((UINT32 *)Buf, HTONL (Ia->Descriptor.IaId)); - Buf += 4; + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (Ia->Descriptor.IaId)); + *PacketCursor += sizeof (Ia->Descriptor.IaId); // // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified. // if (Ia->Descriptor.Type == Dhcp6OptIana) { - WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff)); - Buf += 4; - WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff)); - Buf += 4; + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T1 != 0) ? T1 : 0xffffffff)); + *PacketCursor += sizeof (T1); + WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T2 != 0) ? T2 : 0xffffffff)); + *PacketCursor += sizeof (T2); } // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendIaOption ( // for (Index = 0; Index < Ia->IaAddressCount; Index++) { AddrOpt = (UINT8 *)Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS); - Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); + Status = Dhcp6AppendIaAddrOption (Packet, PacketCursor, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); + if (EFI_ERROR (Status)) { + return Status; + } } // // Fill the value of Ia option length // - *Len = HTONS ((UINT16)(Buf - (UINT8 *)Len - 2)); + *Len = HTONS ((UINT16)(*PacketCursor - (UINT8 *)Len - 2)); - return Buf; + // + // Update the packet length + // + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** Append the appointed Elapsed time option to Buf, and move Buf to the end. - @param[in, out] Buf The pointer to the position to append. + @param[in, out] Packet A pointer to the packet, on success Packet->Length + @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor + will be moved to the end of the option. @param[in] Instance The pointer to the Dhcp6 instance. @param[out] Elapsed The pointer to the elapsed time value in - the generated packet. + the generated packet. - @return Buf The position to append the next Ia option. + @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. + @retval EFI_SUCCESS The option is appended successfully. **/ -UINT8 * +EFI_STATUS Dhcp6AppendETOption ( - IN OUT UINT8 *Buf, - IN DHCP6_INSTANCE *Instance, - OUT UINT16 **Elapsed + IN OUT EFI_DHCP6_PACKET *Packet, + IN OUT UINT8 **PacketCursor, + IN DHCP6_INSTANCE *Instance, + OUT UINT16 **Elapsed ) { + UINT32 BytesNeeded; + UINT32 Length; + // // The format of elapsed time option: // @@ -XXX,XX +XXX,XX @@ Dhcp6AppendETOption ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // + // + // Verify the arguments are valid + // + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Instance == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Elapsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Verify the PacketCursor is within the packet + // + if ( (*PacketCursor < Packet->Dhcp6.Option) + || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) + { + return EFI_INVALID_PARAMETER; + } + + BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; + // + // + 2 for elapsed-time + // + BytesNeeded += sizeof (UINT16); + // + // Space remaining in the packet + // + Length = Packet->Size - Packet->Length; + if (Length < BytesNeeded) { + return EFI_BUFFER_TOO_SMALL; + } + // // Fill the value of elapsed-time option type. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptElapsedTime)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptElapsedTime)); + *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; // // Fill the len of elapsed-time option, which is fixed. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (2)); - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (2)); + *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; // // Fill in elapsed time value with 0 value for now. The actual value is // filled in later just before the packet is transmitted. // - WriteUnaligned16 ((UINT16 *)Buf, HTONS (0)); - *Elapsed = (UINT16 *)Buf; - Buf += 2; + WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (0)); + *Elapsed = (UINT16 *)*PacketCursor; + *PacketCursor += sizeof (UINT16); - return Buf; + Packet->Length += BytesNeeded; + + return EFI_SUCCESS; } /** -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114463): https://edk2.groups.io/g/devel/message/114463 Mute This Topic: https://groups.io/mt/103964976/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
Adds Host Based testing to the NetworkPkg Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 98 ++++++++++++++++++++++++++ NetworkPkg/NetworkPkg.ci.yaml | 7 +- 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 NetworkPkg/Test/NetworkPkgHostTest.dsc diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ +## @file +# NetworkPkgHostTest DSC file used to build host-based unit tests. +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + PLATFORM_NAME = NetworkPkgHostTest + PLATFORM_GUID = 3b68324e-fc07-4d49-9520-9347ede65879 + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/NetworkPkg/HostTest + SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64 + BUILD_TARGETS = NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc +[Packages] + MdePkg/MdePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + +[Components] + # + # Build HOST_APPLICATION that tests NetworkPkg + # + +# Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. +[LibraryClasses] + NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf + VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf +!ifdef CONTINUOUS_INTEGRATION + BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf + TlsLib|CryptoPkg/Library/TlsLibNull/TlsLibNull.inf +!else + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf +!endif + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + +!if $(TOOL_CHAIN_TAG) == VS2019 or $(TOOL_CHAIN_TAG) == VS2022 +[LibraryClasses.X64] + # Provide StackCookie support lib so that we can link to /GS exports for VS builds + RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf +!endif + +[LibraryClasses.common.UEFI_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf +[LibraryClasses.common.UEFI_APPLICATION] + DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf +[LibraryClasses.ARM, LibraryClasses.AARCH64] + # + # It is not possible to prevent ARM compiler calls to generic intrinsic functions. + # This library provides the instrinsic functions generated by a given compiler. + # [LibraryClasses.ARM] and NULL mean link this library into all ARM images. + # +!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019 + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf +!endif + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf +[LibraryClasses.ARM] + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf +[LibraryClasses.RISCV64] + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + +[PcdsFixedAtBuild] + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2 + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType|0x4 diff --git a/NetworkPkg/NetworkPkg.ci.yaml b/NetworkPkg/NetworkPkg.ci.yaml index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/NetworkPkg.ci.yaml +++ b/NetworkPkg/NetworkPkg.ci.yaml @@ -XXX,XX +XXX,XX @@ "CompilerPlugin": { "DscPath": "NetworkPkg.dsc" }, + "HostUnitTestCompilerPlugin": { + "DscPath": "Test/NetworkPkgHostTest.dsc" + }, "CharEncodingCheck": { "IgnoreFiles": [] }, @@ -XXX,XX +XXX,XX @@ "CryptoPkg/CryptoPkg.dec" ], # For host based unit tests - "AcceptableDependencies-HOST_APPLICATION":[], + "AcceptableDependencies-HOST_APPLICATION":[ + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + ], # For UEFI shell based apps "AcceptableDependencies-UEFI_APPLICATION":[ "ShellPkg/ShellPkg.dec" -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114464): https://edk2.groups.io/g/devel/message/114464 Mute This Topic: https://groups.io/mt/103964977/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4535 Confirms that reported issue... "Buffer overflow in the DHCPv6 client via a long Server ID option" ..has been corrected by the provided patch. Tests the following functions to ensure they appropriately handle untrusted data (either too long or too small) to prevent a buffer overflow: Dhcp6AppendOption Dhcp6AppendETOption Dhcp6AppendIaOption Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../GoogleTest/Dhcp6DxeGoogleTest.inf | 43 ++ .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 20 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 478 ++++++++++++++++++ 4 files changed, 542 insertions(+) create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # # Build HOST_APPLICATION that tests NetworkPkg # + NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the Dhcp6Dxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = Dhcp6DxeGoogleTest + FILE_GUID = 1D2A4C65-38C8-4C2F-BB60-B5FA49625AA9 + VERSION_STRING = 1.0 + MODULE_TYPE = HOST_APPLICATION +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# +[Sources] + Dhcp6DxeGoogleTest.cpp + Dhcp6IoGoogleTest.cpp + ../Dhcp6Io.c + ../Dhcp6Utility.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the Dhcp6Dxe module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Tests for Dhcp6Io.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include <Library/BaseMemoryLib.h> + #include "../Dhcp6Impl.h" + #include "../Dhcp6Utility.h" +} + +//////////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////////// + +#define DHCP6_PACKET_MAX_LEN 1500 + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// Symbol Definitions +// These functions are not directly under test - but required to compile +//////////////////////////////////////////////////////////////////////// + +// This definition is used by this test but is also required to compile +// by Dhcp6Io.c +EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = { + { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 } +}; + +EFI_STATUS +EFIAPI +UdpIoSendDatagram ( + IN UDP_IO *UdpIo, + IN NET_BUF *Packet, + IN UDP_END_POINT *EndPoint OPTIONAL, + IN EFI_IP_ADDRESS *Gateway OPTIONAL, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UdpIoRecvDatagram ( + IN UDP_IO *UdpIo, + IN UDP_IO_CALLBACK CallBack, + IN VOID *Context, + IN UINT32 HeadLen + ) +{ + return EFI_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendOptionTest Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that is too small by a duid that is too large +TEST_F (Dhcp6AppendOptionTest, InvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_DHCP6_DUID *UntrustedDuid; + EFI_STATUS Status; + + UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); + ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); + + UntrustedDuid->Length = NTOHS (0xFFFF); + + Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6AppendOptionTest::Packet, + &Cursor, + HTONS (Dhcp6OptServerId), + UntrustedDuid->Length, + UntrustedDuid->Duid + ); + + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); +} + +// Test Description: +// Attempt to append an option to a packet that is large enough +TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_DHCP6_DUID *UntrustedDuid; + EFI_STATUS Status; + UINTN OriginalLength; + + UINT8 Duid[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); + ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); + + UntrustedDuid->Length = NTOHS (sizeof (Duid)); + CopyMem (UntrustedDuid->Duid, Duid, sizeof (Duid)); + + Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6AppendOptionTest::Packet, + &Cursor, + HTONS (Dhcp6OptServerId), + UntrustedDuid->Length, + UntrustedDuid->Duid + ); + + ASSERT_EQ (Status, EFI_SUCCESS); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendOptionTest::Packet->Dhcp6.Option + sizeof (Duid) + 4); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendOptionTest::Packet->Length, OriginalLength + sizeof (Duid) + 4); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendETOption Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendETOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + Packet->Length = sizeof (EFI_DHCP6_HEADER); + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that is too small by a duid that is too large +TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + DHCP6_INSTANCE Instance; + UINT16 ElapsedTimeVal; + UINT16 *ElapsedTime; + + Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; + ElapsedTime = &ElapsedTimeVal; + + Packet->Length = Packet->Size - 2; + + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, + &Instance, // Instance is not used in this function + &ElapsedTime + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +// Test Description: +// Attempt to append an option to a packet that is large enough +TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + DHCP6_INSTANCE Instance; + UINT16 ElapsedTimeVal; + UINT16 *ElapsedTime; + UINTN ExpectedSize; + UINTN OriginalLength; + + Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; + ElapsedTime = &ElapsedTimeVal; + ExpectedSize = 6; + OriginalLength = Packet->Length; + + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, + &Instance, // Instance is not used in this function + &ElapsedTime + ); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendETOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendETOptionTest::Packet->Length, OriginalLength + ExpectedSize); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6AppendIaOption Tests +//////////////////////////////////////////////////////////////////////// + +class Dhcp6AppendIaOptionTest : public ::testing::Test { +public: + UINT8 *Buffer = NULL; + EFI_DHCP6_PACKET *Packet; + EFI_DHCP6_IA *Ia; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); + ASSERT_NE (Buffer, (UINT8 *)NULL); + + Packet = (EFI_DHCP6_PACKET *)Buffer; + Packet->Size = DHCP6_PACKET_MAX_LEN; + + Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2); + ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL); + + CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); + + Ia->IaAddressCount = 2; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + if (Buffer != NULL) { + FreePool (Buffer); + } + + if (Ia != NULL) { + FreePool (Ia); + } + } +}; + +// Test Description: +// Attempt to append an option to a packet that doesn't have enough space +// for the option header +TEST_F (Dhcp6AppendIaOptionTest, IaNaInvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + + Packet->Length = Packet->Size - 2; + + Ia->Descriptor.Type = Dhcp6OptIana; + Ia->Descriptor.IaId = 0x12345678; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0x12345678, + 0x11111111, + Dhcp6OptIana + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +// Test Description: +// Attempt to append an option to a packet that doesn't have enough space +// for the option header +TEST_F (Dhcp6AppendIaOptionTest, IaTaInvalidDataExpectBufferTooSmall) { + UINT8 *Cursor; + EFI_STATUS Status; + + // Use up nearly all the space in the packet + Packet->Length = Packet->Size - 2; + + Ia->Descriptor.Type = Dhcp6OptIata; + Ia->Descriptor.IaId = 0x12345678; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0, + 0, + Dhcp6OptIata + ); + + // verify that we error out because the packet is too small for the option header + ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); + + // reset the length + Packet->Length = sizeof (EFI_DHCP6_HEADER); +} + +TEST_F (Dhcp6AppendIaOptionTest, IaNaValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + UINTN ExpectedSize; + UINTN OriginalLength; + + // + // 2 bytes for the option header type + // + ExpectedSize = 2; + // + // 2 bytes for the option header length + // + ExpectedSize += 2; + // + // 4 bytes for the IAID + // + ExpectedSize += 4; + // + // + 4 bytes for the T1 + // + ExpectedSize += 4; + // + // + 4 bytes for the T2 + // + ExpectedSize += 4; + // + // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + // + 2 bytes for the option header type + // + 2 bytes for the option header length + // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address + // + ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + Ia->Descriptor.Type = Dhcp6OptIana; + Ia->Descriptor.IaId = 0x12345678; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0x12345678, + 0x12345678, + Dhcp6OptIana + ); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); +} + +TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { + UINT8 *Cursor; + EFI_STATUS Status; + UINTN ExpectedSize; + UINTN OriginalLength; + + // + // 2 bytes for the option header type + // + ExpectedSize = 2; + // + // 2 bytes for the option header length + // + ExpectedSize += 2; + // + // 4 bytes for the IAID + // + ExpectedSize += 4; + // + // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + // + 2 bytes for the option header type + // + 2 bytes for the option header length + // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address + // + ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; + + Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + OriginalLength = Packet->Length; + + Ia->Descriptor.Type = Dhcp6OptIata; + Ia->Descriptor.IaId = 0x12345678; + + Status = Dhcp6AppendIaOption ( + Dhcp6AppendIaOptionTest::Packet, + &Cursor, + Ia, + 0, + 0, + Dhcp6OptIata + ); + + // verify that the pointer to cursor moved by the expected amount + ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); + + // verify that the length of the packet is now the expected amount + ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); + + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114465): https://edk2.groups.io/g/devel/message/114465 Mute This Topic: https://groups.io/mt/103964978/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 Bug Details: PixieFail Bug #1 CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Change Overview: Introduce Dhcp6SeekInnerOptionSafe which performs checks before seeking the Inner Option from a DHCP6 Option. > > EFI_STATUS > Dhcp6SeekInnerOptionSafe ( > IN UINT16 IaType, > IN UINT8 *Option, > IN UINT32 OptionLen, > OUT UINT8 **IaInnerOpt, > OUT UINT16 *IaInnerLen > ); > Lots of code cleanup to improve code readability. Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 138 +++++++++++++++++++--- NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 203 +++++++++++++++++++++----------- 2 files changed, 256 insertions(+), 85 deletions(-) diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S') #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I') +#define DHCP6_PACKET_ALL 0 +#define DHCP6_PACKET_STATEFUL 1 +#define DHCP6_PACKET_STATELESS 2 + +#define DHCP6_BASE_PACKET_SIZE 1024 + +#define DHCP6_PORT_CLIENT 546 +#define DHCP6_PORT_SERVER 547 + +#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) + +#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE) +#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE) + // // For more information on DHCP options see RFC 8415, Section 21.1 // @@ -XXX,XX +XXX,XX @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE; // | (option-len octets) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // -#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16)) -#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16)) +#define DHCP6_SIZE_OF_OPT_CODE (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode)) +#define DHCP6_SIZE_OF_OPT_LEN (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen)) -// // Combined size of Code and Length -// #define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \ DHCP6_SIZE_OF_OPT_LEN) @@ -XXX,XX +XXX,XX @@ STATIC_ASSERT ( "Combined size of Code and Length must be 4 per RFC 8415" ); -// // Offset to the length is just past the code -// -#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE) +#define DHCP6_OFFSET_OF_OPT_LEN(a) (a + DHCP6_SIZE_OF_OPT_CODE) STATIC_ASSERT ( - DHCP6_OPT_LEN_OFFSET (0) == 2, + DHCP6_OFFSET_OF_OPT_LEN (0) == 2, "Offset of length is + 2 past start of option" ); -#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +#define DHCP6_OFFSET_OF_OPT_DATA(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) STATIC_ASSERT ( - DHCP6_OPT_DATA_OFFSET (0) == 4, + DHCP6_OFFSET_OF_OPT_DATA (0) == 4, "Offset to option data should be +4 from start of option" ); +// +// Identity Association options (both NA (Non-Temporary) and TA (Temporary Association)) +// are defined in RFC 8415 and are a deriviation of a TLV stucture +// For more information on IA_NA see Section 21.4 +// For more information on IA_TA see Section 21.5 +// +// +// The format of IA_NA and IA_TA option: +// +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | OPTION_IA_NA | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | IAID (4 octets) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | T1 (only for IA_NA) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | T2 (only for IA_NA) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// . IA_NA-options/IA_TA-options . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_SIZE_OF_IAID (sizeof(UINT32)) +#define DHCP6_SIZE_OF_TIME_INTERVAL (sizeof(UINT32)) -#define DHCP6_PACKET_ALL 0 -#define DHCP6_PACKET_STATEFUL 1 -#define DHCP6_PACKET_STATELESS 2 +// Combined size of IAID, T1, and T2 +#define DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 (DHCP6_SIZE_OF_IAID + \ + DHCP6_SIZE_OF_TIME_INTERVAL + \ + DHCP6_SIZE_OF_TIME_INTERVAL) +STATIC_ASSERT ( + DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 == 12, + "Combined size of IAID, T1, T2 must be 12 per RFC 8415" + ); -#define DHCP6_BASE_PACKET_SIZE 1024 +// This is the size of IA_TA without options +#define DHCP6_MIN_SIZE_OF_IA_TA (DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_IAID) +STATIC_ASSERT ( + DHCP6_MIN_SIZE_OF_IA_TA == 8, + "Minimum combined size of IA_TA per RFC 8415" + ); -#define DHCP6_PORT_CLIENT 546 -#define DHCP6_PORT_SERVER 547 +// Offset to a IA_TA inner option +#define DHCP6_OFFSET_OF_IA_TA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_TA) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_TA_INNER_OPT (0) == 8, + "Offset of IA_TA Inner option is + 8 past start of option" + ); -#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) +// This is the size of IA_NA without options (16) +#define DHCP6_MIN_SIZE_OF_IA_NA DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 +STATIC_ASSERT ( + DHCP6_MIN_SIZE_OF_IA_NA == 16, + "Minimum combined size of IA_TA per RFC 8415" + ); -#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE) -#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE) +#define DHCP6_OFFSET_OF_IA_NA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_NA) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_INNER_OPT (0) == 16, + "Offset of IA_NA Inner option is + 16 past start of option" + ); + +#define DHCP6_OFFSET_OF_IA_NA_T1(a) (a + \ + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \ + DHCP6_SIZE_OF_IAID) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_T1 (0) == 8, + "Offset of IA_NA Inner option is + 8 past start of option" + ); + +#define DHCP6_OFFSET_OF_IA_NA_T2(a) (a + \ + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN +\ + DHCP6_SIZE_OF_IAID + \ + DHCP6_SIZE_OF_TIME_INTERVAL) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_IA_NA_T2 (0) == 12, + "Offset of IA_NA Inner option is + 12 past start of option" + ); + +// +// For more information see RFC 8415 Section 21.13 +// +// The format of the Status Code Option: +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | OPTION_STATUS_CODE | option-len | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | status-code | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | +// . . +// . status-message . +// . . +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +#define DHCP6_OFFSET_OF_STATUS_CODE(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN) +STATIC_ASSERT ( + DHCP6_OFFSET_OF_STATUS_CODE (0) == 4, + "Offset of status is + 4 past start of option" + ); extern EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress; extern EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate; diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( // The inner options still start with 2 bytes option-code and 2 bytes option-len. // if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { - T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 8))); - T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 12))); + T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T1 (Option)))); + T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T2 (Option)))); // // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2, // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( return EFI_DEVICE_ERROR; } - IaInnerOpt = Option + 16; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 12); + IaInnerOpt = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option); + IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_COMBINED_IAID_T1_T2); } else { - T1 = 0; - T2 = 0; - IaInnerOpt = Option + 8; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 4); + T1 = 0; + T2 = 0; + + IaInnerOpt = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option); + IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_IAID); } // @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); if (Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6UpdateIaInfo ( return Status; } +/** + Seeks the Inner Options from a DHCP6 Option + + @param[in] IaType The type of the IA option. + @param[in] Option The pointer to the DHCP6 Option. + @param[in] OptionLen The length of the DHCP6 Option. + @param[out] IaInnerOpt The pointer to the IA inner option. + @param[out] IaInnerLen The length of the IA inner option. + + @retval EFI_SUCCESS Seek the inner option successfully. + @retval EFI_DEVICE_ERROR The OptionLen is invalid. On Error, + the pointers are not modified +**/ +EFI_STATUS +Dhcp6SeekInnerOptionSafe ( + IN UINT16 IaType, + IN UINT8 *Option, + IN UINT32 OptionLen, + OUT UINT8 **IaInnerOpt, + OUT UINT16 *IaInnerLen + ) +{ + UINT16 IaInnerLenTmp; + UINT8 *IaInnerOptTmp; + + if (Option == NULL) { + ASSERT (Option != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaInnerOpt == NULL) { + ASSERT (IaInnerOpt != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaInnerLen == NULL) { + ASSERT (IaInnerLen != NULL); + return EFI_DEVICE_ERROR; + } + + if (IaType == Dhcp6OptIana) { + // Verify we have a fully formed IA_NA + if (OptionLen < DHCP6_MIN_SIZE_OF_IA_NA) { + return EFI_DEVICE_ERROR; + } + + // + IaInnerOptTmp = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option); + + // Verify the IaInnerLen is valid. + IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)DHCP6_OFFSET_OF_OPT_LEN (Option))); + if (IaInnerLenTmp < DHCP6_SIZE_OF_COMBINED_IAID_T1_T2) { + return EFI_DEVICE_ERROR; + } + + IaInnerLenTmp -= DHCP6_SIZE_OF_COMBINED_IAID_T1_T2; + } else if (IaType == Dhcp6OptIata) { + // Verify the OptionLen is valid. + if (OptionLen < DHCP6_MIN_SIZE_OF_IA_TA) { + return EFI_DEVICE_ERROR; + } + + IaInnerOptTmp = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option); + + // Verify the IaInnerLen is valid. + IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))); + if (IaInnerLenTmp < DHCP6_SIZE_OF_IAID) { + return EFI_DEVICE_ERROR; + } + + IaInnerLenTmp -= DHCP6_SIZE_OF_IAID; + } else { + return EFI_DEVICE_ERROR; + } + + *IaInnerOpt = IaInnerOptTmp; + *IaInnerLen = IaInnerLenTmp; + + return EFI_SUCCESS; +} + /** Seek StatusCode Option in package. A Status Code option may appear in the options field of a DHCP message and/or in the options field of another option. @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( UINT8 *IaInnerOpt; UINT16 IaInnerLen; UINT16 StsCode; + UINT32 OptionLen; + + // OptionLen is the length of the Options excluding the DHCP header. + // Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last + // byte of the Option[] field. + OptionLen = Packet->Length - sizeof (Packet->Dhcp6.Header); // // Seek StatusCode option directly in DHCP message body. That is, search in @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + OptionLen, Dhcp6OptStatusCode ); if (*Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_STATUS_CODE (*Option)))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekIaOption ( Packet->Dhcp6.Option, - Packet->Length - sizeof (EFI_DHCP6_HEADER), + OptionLen, &Instance->Config->IaDescriptor ); if (*Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( } // - // The format of the IA_NA option is: + // Calculate the distance from Packet->Dhcp6.Option to the IA option. // - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | OPTION_IA_NA | option-len | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | IAID (4 octets) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | T1 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | T2 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // . IA_NA-options . - // . . - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Packet->Size and Packet->Length are both UINT32 type, and Packet->Size is + // the size of the whole packet, including the DHCP header, and Packet->Length + // is the length of the DHCP message body, excluding the DHCP header. // - // The format of the IA_TA option is: + // (*Option - Packet->Dhcp6.Option) is the number of bytes from the start of + // DHCP6 option area to the start of the IA option. // - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | OPTION_IA_TA | option-len | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | IAID (4 octets) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // . IA_TA-options . - // . . - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // Dhcp6SeekInnerOptionSafe() is searching starting from the start of the + // IA option to the end of the DHCP6 option area, thus subtract the space + // up until this option // + OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option); // - // sizeof (option-code + option-len + IaId) = 8 - // sizeof (option-code + option-len + IaId + T1) = 12 - // sizeof (option-code + option-len + IaId + T1 + T2) = 16 + // Seek the inner option // - // The inner options still start with 2 bytes option-code and 2 bytes option-len. - // - if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { - IaInnerOpt = *Option + 16; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 12); - } else { - IaInnerOpt = *Option + 8; - IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 4); + if (EFI_ERROR ( + Dhcp6SeekInnerOptionSafe ( + Instance->Config->IaDescriptor.Type, + *Option, + OptionLen, + &IaInnerOpt, + &IaInnerLen + ) + )) + { + return EFI_DEVICE_ERROR; } // @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); if (*Option != NULL) { - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (*Option))))); if (StsCode != Dhcp6StsSuccess) { return EFI_DEVICE_ERROR; } @@ -XXX,XX +XXX,XX @@ Dhcp6SendRequestMsg ( // Option = Dhcp6SeekOption ( Instance->AdSelect->Dhcp6.Option, - Instance->AdSelect->Length - 4, + Instance->AdSelect->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendDeclineMsg ( // Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendReleaseMsg ( // Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6SendRenewRebindMsg ( Option = Dhcp6SeekOption ( LastReply->Dhcp6.Option, - LastReply->Length - 4, + LastReply->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); if (Option == NULL) { @@ -XXX,XX +XXX,XX @@ Dhcp6HandleReplyMsg ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptRapidCommit ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleReplyMsg ( // // Any error status code option is found. // - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4))); + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (Option))))); switch (StsCode) { case Dhcp6StsUnspecFail: // @@ -XXX,XX +XXX,XX @@ Dhcp6SelectAdvertiseMsg ( // Option = Dhcp6SeekOption ( AdSelect->Dhcp6.Option, - AdSelect->Length - 4, + AdSelect->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerUnicast ); @@ -XXX,XX +XXX,XX @@ Dhcp6SelectAdvertiseMsg ( return EFI_OUT_OF_RESOURCES; } - CopyMem (Instance->Unicast, Option + 4, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (Instance->Unicast, DHCP6_OFFSET_OF_OPT_DATA (Option), sizeof (EFI_IPv6_ADDRESS)); } // @@ -XXX,XX +XXX,XX @@ Dhcp6HandleAdvertiseMsg ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptRapidCommit ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleAdvertiseMsg ( CopyMem (Instance->AdSelect, Packet, Packet->Size); if (Option != NULL) { - Instance->AdPref = *(Option + 4); + Instance->AdPref = *(DHCP6_OFFSET_OF_OPT_DATA (Option)); } } else { // @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateful ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN, Dhcp6OptClientId ); - if ((Option == NULL) || (CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0)) { + if ((Option == NULL) || (CompareMem (DHCP6_OFFSET_OF_OPT_DATA (Option), ClientId->Duid, ClientId->Length) != 0)) { goto ON_CONTINUE; } @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateful ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN, Dhcp6OptServerId ); @@ -XXX,XX +XXX,XX @@ Dhcp6HandleStateless ( // Option = Dhcp6SeekOption ( Packet->Dhcp6.Option, - Packet->Length - 4, + Packet->Length - sizeof (EFI_DHCP6_HEADER), Dhcp6OptServerId ); -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114466): https://edk2.groups.io/g/devel/message/114466 Mute This Topic: https://groups.io/mt/103964979/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 These tests confirm that the report bug... "Out-of-bounds read when processing IA_NA/IA_TA options in a DHCPv6 Advertise message" ..has been patched. The following functions are tested to confirm an out of bounds read is patched and that the correct statuses are returned: Dhcp6SeekInnerOptionSafe Dhcp6SeekStsOption TCBZ4534 CVE-2023-45229 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../GoogleTest/Dhcp6DxeGoogleTest.inf | 1 + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 +++ NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 2 +- .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 365 +++++++++++++++++- 5 files changed, 424 insertions(+), 3 deletions(-) create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Defines] SKUID_IDENTIFIER = DEFAULT !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc + [Packages] MdePkg/MdePkg.dec UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ [Defines] [Sources] Dhcp6DxeGoogleTest.cpp Dhcp6IoGoogleTest.cpp + Dhcp6IoGoogleTest.h ../Dhcp6Io.c ../Dhcp6Utility.c diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as header for private functions under test in Dhcp6Io.c + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef DHCP6_IO_GOOGLE_TEST_H_ +#define DHCP6_IO_GOOGLE_TEST_H_ + +//////////////////////////////////////////////////////////////////////////////// +// These are the functions that are being unit tested +//////////////////////////////////////////////////////////////////////////////// + +#include <Uefi.h> + +/** + Seeks the Inner Options from a DHCP6 Option + + @param[in] IaType The type of the IA option. + @param[in] Option The pointer to the DHCP6 Option. + @param[in] OptionLen The length of the DHCP6 Option. + @param[out] IaInnerOpt The pointer to the IA inner option. + @param[out] IaInnerLen The length of the IA inner option. + + @retval EFI_SUCCESS Seek the inner option successfully. + @retval EFI_DEVICE_ERROR The OptionLen is invalid. +*/ +EFI_STATUS +Dhcp6SeekInnerOptionSafe ( + UINT16 IaType, + UINT8 *Option, + UINT32 OptionLen, + UINT8 **IaInnerOpt, + UINT16 *IaInnerLen + ); + +/** + Seek StatusCode Option in package. A Status Code option may appear in the + options field of a DHCP message and/or in the options field of another option. + See details in section 22.13, RFC3315. + + @param[in] Instance The pointer to the Dhcp6 instance. + @param[in] Packet The pointer to reply messages. + @param[out] Option The pointer to status code option. + + @retval EFI_SUCCESS Seek status code option successfully. + @retval EFI_DEVICE_ERROR An unexpected error. + +**/ +EFI_STATUS +Dhcp6SeekStsOption ( + IN DHCP6_INSTANCE *Instance, + IN EFI_DHCP6_PACKET *Packet, + OUT UINT8 **Option + ); + +#endif // DHCP6_IO_GOOGLE_TEST_H diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -XXX,XX +XXX,XX @@ Dhcp6SeekStsOption ( // IA option to the end of the DHCP6 option area, thus subtract the space // up until this option // - OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option); + OptionLen = OptionLen - (UINT32)(*Option - Packet->Dhcp6.Option); // // Seek the inner option diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ extern "C" { #include <Library/BaseMemoryLib.h> #include "../Dhcp6Impl.h" #include "../Dhcp6Utility.h" + #include "Dhcp6IoGoogleTest.h" } //////////////////////////////////////////////////////////////////////// @@ -XXX,XX +XXX,XX @@ extern "C" { #define DHCP6_PACKET_MAX_LEN 1500 +// This definition is used by this test but is also required to compile +// by Dhcp6Io.c +#define DHCPV6_OPTION_IA_NA 3 +#define DHCPV6_OPTION_IA_TA 4 + +#define SEARCH_PATTERN 0xDEADC0DE +#define SEARCH_PATTERN_LEN sizeof(SEARCH_PATTERN) + //////////////////////////////////////////////////////////////////////// +// Test structures for IA_NA and IA_TA options +//////////////////////////////////////////////////////////////////////// +typedef struct { + UINT16 Code; + UINT16 Len; + UINT32 IAID; +} DHCPv6_OPTION; + +typedef struct { + DHCPv6_OPTION Header; + UINT32 T1; + UINT32 T2; + UINT8 InnerOptions[0]; +} DHCPv6_OPTION_IA_NA; + +typedef struct { + DHCPv6_OPTION Header; + UINT8 InnerOptions[0]; +} DHCPv6_OPTION_IA_TA; + //////////////////////////////////////////////////////////////////////// // Symbol Definitions // These functions are not directly under test - but required to compile @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { Status = Dhcp6AppendETOption ( Dhcp6AppendETOptionTest::Packet, &Cursor, - &Instance, // Instance is not used in this function + &Instance, // Instance is not used in this function &ElapsedTime ); @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { Status = Dhcp6AppendETOption ( Dhcp6AppendETOptionTest::Packet, &Cursor, - &Instance, // Instance is not used in this function + &Instance, // Instance is not used in this function &ElapsedTime ); @@ -XXX,XX +XXX,XX @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { // verify that the status is EFI_SUCCESS ASSERT_EQ (Status, EFI_SUCCESS); } + +//////////////////////////////////////////////////////////////////////// +// Dhcp6SeekInnerOptionSafe Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Dhcp6SeekInnerOptionSafeTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IANA option is found. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAValidOptionExpectSuccess) { + EFI_STATUS Result; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIana; + OptionPtr->Header.Len = HTONS (4 + 12); // Valid length has to be more than 12 + OptionPtr->Header.IAID = 0x12345678; + OptionPtr->T1 = 0x11111111; + OptionPtr->T2 = 0x22222222; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Result = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Result, EFI_SUCCESS); + ASSERT_EQ (InnerOptionLength, 4); + ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_DEIVCE_ERROR when the IANA option size is invalid. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAInvalidSizeExpectFail) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIana; + OptionPtr->Header.Len = HTONS (4); // Set the length to lower than expected (12) + OptionPtr->Header.IAID = 0x12345678; + OptionPtr->T1 = 0x11111111; + OptionPtr->T2 = 0x22222222; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + // Set the InnerOptionLength to be less than the size of the option + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); + + // Now set the OptionLength to be less than the size of the option + OptionLength = sizeof (DHCPv6_OPTION_IA_NA) - 1; + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIana, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option is found +TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAValidOptionExpectSuccess) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIata; + OptionPtr->Header.Len = HTONS (4 + 4); // Valid length has to be more than 4 + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_SUCCESS); + ASSERT_EQ (InnerOptionLength, 4); + ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. +TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAInvalidSizeExpectFail) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Status; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = Dhcp6OptIata; + OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); + + // Now lets try modifying the OptionLength to be less than the size of the option + OptionLength = sizeof (DHCPv6_OPTION_IA_TA) - 1; + Status = Dhcp6SeekInnerOptionSafe ( + Dhcp6OptIata, + Option, + OptionLength, + &InnerOptionPtr, + &InnerOptionLength + ); + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that any other Option Type fails +TEST_F (Dhcp6SeekInnerOptionSafeTest, InvalidOption) { + // Lets add an inner option of bytes we expect to find + EFI_STATUS Result; + UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; + UINT32 OptionLength = sizeof (Option); + DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; + UINT32 SearchPattern = SEARCH_PATTERN; + + UINTN SearchPatternLength = SEARCH_PATTERN_LEN; + UINT8 *InnerOptionPtr = NULL; + UINT16 InnerOptionLength = 0; + + OptionPtr->Header.Code = 0xC0DE; + OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) + OptionPtr->Header.IAID = 0x12345678; + CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); + + Result = Dhcp6SeekInnerOptionSafe (0xC0DE, Option, OptionLength, &InnerOptionPtr, &InnerOptionLength); + ASSERT_EQ (Result, EFI_DEVICE_ERROR); +} + +//////////////////////////////////////////////////////////////////////// +// Dhcp6SeekStsOption Tests +//////////////////////////////////////////////////////////////////////// + +#define PACKET_SIZE (1500) + +class Dhcp6SeekStsOptionTest : public ::testing::Test { +public: + DHCP6_INSTANCE Instance = { 0 }; + EFI_DHCP6_PACKET *Packet = NULL; + EFI_DHCP6_CONFIG_DATA Config = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Allocate a packet + Packet = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + ASSERT_NE (Packet, nullptr); + + // Initialize the packet + Packet->Size = PACKET_SIZE; + + Instance.Config = &Config; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + FreePool (Packet); + } +}; + +// Test Description: +// This test verifies that Dhcp6SeekStsOption returns EFI_DEVICE_ERROR when the option is invalid +// This verifies that the calling function is working as expected +TEST_F (Dhcp6SeekStsOptionTest, SeekIATAOptionExpectFail) { + EFI_STATUS Status; + UINT8 *Option = NULL; + UINT32 SearchPattern = SEARCH_PATTERN; + UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; + UINT16 *Len = NULL; + EFI_DHCP6_IA Ia = { 0 }; + + Ia.Descriptor.Type = DHCPV6_OPTION_IA_TA; + Ia.IaAddressCount = 1; + Ia.IaAddress[0].PreferredLifetime = 0xDEADBEEF; + Ia.IaAddress[0].ValidLifetime = 0xDEADAAAA; + Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; + + Packet->Length = sizeof (EFI_DHCP6_HEADER); + + Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; + + // Let's append the option to the packet + Status = Dhcp6AppendOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + Dhcp6OptStatusCode, + SearchPatternLength, + (UINT8 *)&SearchPattern + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + // Inner option length - this will be overwritten later + Len = (UINT16 *)(Option + 2); + + // Fill in the inner IA option + Status = Dhcp6AppendIaOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + &Ia, + 0x12345678, + 0x11111111, + 0x22222222 + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + // overwrite the len of inner Ia option + *Len = HTONS (3); + + Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_TA; + + Option = NULL; + Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); + + ASSERT_EQ (Status, EFI_DEVICE_ERROR); +} + +// Test Description: +// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. +TEST_F (Dhcp6SeekStsOptionTest, SeekIANAOptionExpectSuccess) { + EFI_STATUS Status = EFI_NOT_FOUND; + UINT8 *Option = NULL; + UINT32 SearchPattern = SEARCH_PATTERN; + UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; + EFI_DHCP6_IA Ia = { 0 }; + + Ia.Descriptor.Type = DHCPV6_OPTION_IA_NA; + Ia.IaAddressCount = 1; + Ia.IaAddress[0].PreferredLifetime = 0x11111111; + Ia.IaAddress[0].ValidLifetime = 0x22222222; + Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; + Packet->Length = sizeof (EFI_DHCP6_HEADER); + + Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; + + Status = Dhcp6AppendOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + Dhcp6OptStatusCode, + SearchPatternLength, + (UINT8 *)&SearchPattern + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + Status = Dhcp6AppendIaOption ( + Dhcp6SeekStsOptionTest::Packet, + &Option, + &Ia, + 0x12345678, + 0x11111111, + 0x22222222 + ); + ASSERT_EQ (Status, EFI_SUCCESS); + + Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_NA; + + Option = NULL; + Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); + + ASSERT_EQ (Status, EFI_SUCCESS); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114467): https://edk2.groups.io/g/devel/message/114467 Mute This Topic: https://groups.io/mt/103964980/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 Bug Overview: PixieFail Bug #3 CVE-2023-45231 CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE-125 Out-of-bounds Read Out-of-bounds read when handling a ND Redirect message with truncated options Change Overview: Adds a check to prevent truncated options from being parsed + // + // Cannot process truncated options. + // Cannot process options with a length of 0 as there is no Type field. + // + if (OptionLen < sizeof (IP6_OPTION_HEADER)) { + return FALSE; + } Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Ip6Dxe/Ip6Option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.c +++ b/NetworkPkg/Ip6Dxe/Ip6Option.c @@ -XXX,XX +XXX,XX @@ Ip6IsNDOptionValid ( return FALSE; } + // + // Cannot process truncated options. + // Cannot process options with a length of 0 as there is no Type field. + // + if (OptionLen < sizeof (IP6_OPTION_HEADER)) { + return FALSE; + } + Offset = 0; // -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114468): https://edk2.groups.io/g/devel/message/114468 Mute This Topic: https://groups.io/mt/103964981/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 Validates that the patch for... Out-of-bounds read when handling a ND Redirect message with truncated options .. has been fixed Tests the following function to ensure that an out of bounds read does not occur Ip6OptionValidation Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 42 ++++++ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 20 +++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 129 ++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # Build HOST_APPLICATION that tests NetworkPkg # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf + NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the Ip6Dxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = Ip6DxeUnitTest + FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A + VERSION_STRING = 1.0 + MODULE_TYPE = HOST_APPLICATION +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# +[Sources] + Ip6DxeGoogleTest.cpp + Ip6OptionGoogleTest.cpp + ../Ip6Option.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the Ip6Dxe module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Tests for Ip6Option.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include "../Ip6Impl.h" + #include "../Ip6Option.h" +} + +///////////////////////////////////////////////////////////////////////// +// Defines +/////////////////////////////////////////////////////////////////////// + +#define IP6_PREFIX_INFO_OPTION_DATA_LEN 32 +#define OPTION_HEADER_IP6_PREFIX_DATA_LEN (sizeof (IP6_OPTION_HEADER) + IP6_PREFIX_INFO_OPTION_DATA_LEN) + +//////////////////////////////////////////////////////////////////////// +// Symbol Definitions +// These functions are not directly under test - but required to compile +//////////////////////////////////////////////////////////////////////// +UINT32 mIp6Id; + +EFI_STATUS +Ip6SendIcmpError ( + IN IP6_SERVICE *IpSb, + IN NET_BUF *Packet, + IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL, + IN EFI_IPv6_ADDRESS *DestinationAddress, + IN UINT8 Type, + IN UINT8 Code, + IN UINT32 *Pointer OPTIONAL + ) +{ + // .. + return EFI_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////// +// Ip6OptionValidation Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Ip6OptionValidationTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +// Test Description: +// Null option should return false +TEST_F (Ip6OptionValidationTest, NullOptionShouldReturnFalse) { + UINT8 *option = nullptr; + UINT16 optionLen = 10; // Provide a suitable length + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Truncated option should return false +TEST_F (Ip6OptionValidationTest, TruncatedOptionShouldReturnFalse) { + UINT8 option[] = { 0x01 }; // Provide a truncated option + UINT16 optionLen = 1; + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with zero length should return false +TEST_F (Ip6OptionValidationTest, OptionWithZeroLengthShouldReturnFalse) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 0; + UINT8 option[sizeof (IP6_OPTION_HEADER)]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + UINT16 optionLen = sizeof (IP6_OPTION_HEADER); + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with valid length should return true +TEST_F (Ip6OptionValidationTest, ValidPrefixInfoOptionShouldReturnTrue) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 4; // Length 4 * 8 = 32 + UINT8 option[OPTION_HEADER_IP6_PREFIX_DATA_LEN]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + + EXPECT_TRUE (Ip6IsNDOptionValid (option, IP6_PREFIX_INFO_OPTION_DATA_LEN)); +} + +// Test Description: +// Ip6OptionPrefixInfo Option with invalid length should return false +TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse) { + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPrefixInfo; + optionHeader.Length = 3; // Length 3 * 8 = 24 (Invalid) + UINT8 option[sizeof (IP6_OPTION_HEADER)]; + + CopyMem (option, &optionHeader, sizeof (IP6_OPTION_HEADER)); + UINT16 optionLen = sizeof (IP6_OPTION_HEADER); + + EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114469): https://edk2.groups.io/g/devel/message/114469 Mute This Topic: https://groups.io/mt/103964982/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 Bug Details: PixieFail Bug #4 CVE-2023-45232 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') Infinite loop when parsing unknown options in the Destination Options header PixieFail Bug #5 CVE-2023-45233 CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') Infinite loop when parsing a PadN option in the Destination Options header Change Overview: Most importantly this change corrects the following incorrect math and cleans up the code. > // It is a PadN option > // > - Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2); > + OptDataLen = ((EFI_IP6_OPTION *)(Option + Offset))->Length; > + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); > case Ip6OptionSkip: > - Offset = (UINT8)(Offset + *(Option + Offset + 1)); > OptDataLen = ((EFI_IP6_OPTION *)(Option + Offset))->Length; > Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); Additionally, this change also corrects incorrect math where the calling function was calculating the HDR EXT optionLen as a uint8 instead of a uint16 > - OptionLen = (UINT8)((*Option + 1) * 8 - 2); > + OptionLen = IP6_HDR_EXT_LEN (*Option) - IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN; Additionally this check adds additional logic to santize the incoming data Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Ip6Dxe/Ip6Nd.h | 35 ++++++++++++++++ NetworkPkg/Ip6Dxe/Ip6Option.h | 71 ++++++++++++++++++++++++++++++++ NetworkPkg/Ip6Dxe/Ip6Option.c | 76 ++++++++++++++++++++++++++++++----- 3 files changed, 171 insertions(+), 11 deletions(-) diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.h b/NetworkPkg/Ip6Dxe/Ip6Nd.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Nd.h +++ b/NetworkPkg/Ip6Dxe/Ip6Nd.h @@ -XXX,XX +XXX,XX @@ VOID VOID *Context ); +// +// Per RFC8200 Section 4.2 +// +// Two of the currently-defined extension headers -- the Hop-by-Hop +// Options header and the Destination Options header -- carry a variable +// number of type-length-value (TLV) encoded "options", of the following +// format: +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - +// | Option Type | Opt Data Len | Option Data +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - +// +// Option Type 8-bit identifier of the type of option. +// +// Opt Data Len 8-bit unsigned integer. Length of the Option +// Data field of this option, in octets. +// +// Option Data Variable-length field. Option-Type-specific +// data. +// typedef struct _IP6_OPTION_HEADER { + /// + /// identifier of the type of option. + /// UINT8 Type; + /// + /// Length of the Option Data field of this option, in octets. + /// UINT8 Length; + /// + /// Option-Type-specific data. + /// } IP6_OPTION_HEADER; STATIC_ASSERT (sizeof (IP6_OPTION_HEADER) == 2, "IP6_OPTION_HEADER is expected to be exactly 2 bytes long."); +#define IP6_NEXT_OPTION_OFFSET(offset, length) (offset + sizeof(IP6_OPTION_HEADER) + length) +STATIC_ASSERT ( + IP6_NEXT_OPTION_OFFSET (0, 0) == 2, + "The next option is minimally the combined size of the option tag and length" + ); + typedef struct _IP6_ETHE_ADDR_OPTION { UINT8 Type; UINT8 Length; diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.h b/NetworkPkg/Ip6Dxe/Ip6Option.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.h +++ b/NetworkPkg/Ip6Dxe/Ip6Option.h @@ -XXX,XX +XXX,XX @@ #define IP6_FRAGMENT_OFFSET_MASK (~0x3) +// +// For more information see RFC 8200, Section 4.3, 4.4, and 4.6 +// +// This example format is from section 4.6 +// This does not apply to fragment headers +// +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Next Header | Hdr Ext Len | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// | | +// . . +// . Header-Specific Data . +// . . +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Next Header 8-bit selector. Identifies the type of +// header immediately following the extension +// header. Uses the same values as the IPv4 +// Protocol field [IANA-PN]. +// +// Hdr Ext Len 8-bit unsigned integer. Length of the +// Destination Options header in 8-octet units, +// not including the first 8 octets. + +// +// These defines apply to the following: +// 1. Hop by Hop +// 2. Routing +// 3. Destination +// +typedef struct _IP6_EXT_HDR { + /// + /// The Next Header field identifies the type of header immediately + /// + UINT8 NextHeader; + /// + /// The Hdr Ext Len field specifies the length of the Hop-by-Hop Options + /// + UINT8 HdrExtLen; + /// + /// Header-Specific Data + /// +} IP6_EXT_HDR; + +STATIC_ASSERT ( + sizeof (IP6_EXT_HDR) == 2, + "The combined size of Next Header and Len is two 8 bit fields" + ); + +// +// IPv6 extension headers contain an 8-bit length field which describes the size of +// the header. However, the length field only includes the size of the extension +// header options, not the size of the first 8 bytes of the header. Therefore, in +// order to calculate the full size of the extension header, we add 1 (to account +// for the first 8 bytes omitted by the length field reporting) and then multiply +// by 8 (since the size is represented in 8-byte units). +// +// a is the length field of the extension header (UINT8) +// The result may be up to 2046 octets (UINT16) +// +#define IP6_HDR_EXT_LEN(a) (((UINT16)((UINT8)(a)) + 1) * 8) + +// This is the maxmimum length permissible by a extension header +// Length is UINT8 of 8 octets not including the first 8 octets +#define IP6_MAX_EXT_DATA_LENGTH (IP6_HDR_EXT_LEN (MAX_UINT8) - sizeof(IP6_EXT_HDR)) +STATIC_ASSERT ( + IP6_MAX_EXT_DATA_LENGTH == 2046, + "Maximum data length is ((MAX_UINT8 + 1) * 8) - 2" + ); + typedef struct _IP6_FRAGMENT_HEADER { UINT8 NextHeader; UINT8 Reserved; diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Option.c +++ b/NetworkPkg/Ip6Dxe/Ip6Option.c @@ -XXX,XX +XXX,XX @@ @param[in] IpSb The IP6 service data. @param[in] Packet The to be validated packet. @param[in] Option The first byte of the option. - @param[in] OptionLen The length of the whole option. + @param[in] OptionLen The length of all options, expressed in byte length of octets. + Maximum length is 2046 bytes or ((n + 1) * 8) - 2 where n is 255. @param[in] Pointer Identifies the octet offset within the invoking packet where the error was detected. @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( IN IP6_SERVICE *IpSb, IN NET_BUF *Packet, IN UINT8 *Option, - IN UINT8 OptionLen, + IN UINT16 OptionLen, IN UINT32 Pointer ) { - UINT8 Offset; - UINT8 OptionType; + UINT16 Offset; + UINT8 OptionType; + UINT8 OptDataLen; + + if (Option == NULL) { + ASSERT (Option != NULL); + return FALSE; + } + + if ((OptionLen <= 0) || (OptionLen > IP6_MAX_EXT_DATA_LENGTH)) { + ASSERT (OptionLen > 0 && OptionLen <= IP6_MAX_EXT_DATA_LENGTH); + return FALSE; + } + + if (Packet == NULL) { + ASSERT (Packet != NULL); + return FALSE; + } + + if (IpSb == NULL) { + ASSERT (IpSb != NULL); + return FALSE; + } Offset = 0; @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( // // It is a PadN option // - Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2); + OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length; + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); break; case Ip6OptionRouterAlert: // @@ -XXX,XX +XXX,XX @@ Ip6IsOptionValid ( // switch (OptionType & Ip6OptionMask) { case Ip6OptionSkip: - Offset = (UINT8)(Offset + *(Option + Offset + 1)); + OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length; + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); break; case Ip6OptionDiscard: return FALSE; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( UINT32 Pointer; UINT32 Offset; UINT8 *Option; - UINT8 OptionLen; + UINT16 OptionLen; BOOLEAN Flag; UINT8 CountD; UINT8 CountA; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // Fall through // case IP6_DESTINATION: + // + // See https://www.rfc-editor.org/rfc/rfc2460#section-4.2 page 23 + // + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Next Header | Hdr Ext Len | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // | | + // . . + // . Options . + // . . + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + // + // Next Header 8-bit selector. Identifies the type of header + // immediately following the Destination Options + // header. Uses the same values as the IPv4 + // Protocol field [RFC-1700 et seq.]. + // + // Hdr Ext Len 8-bit unsigned integer. Length of the + // Destination Options header in 8-octet units, not + // including the first 8 octets. + // + // Options Variable-length field, of length such that the + // complete Destination Options header is an + // integer multiple of 8 octets long. Contains one + // or more TLV-encoded options, as described in + // section 4.2. + // + if (*NextHeader == IP6_DESTINATION) { CountD++; } @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( Offset++; Option = ExtHdrs + Offset; - OptionLen = (UINT8)((*Option + 1) * 8 - 2); + OptionLen = IP6_HDR_EXT_LEN (*Option) - sizeof (IP6_EXT_HDR); Option++; Offset++; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // // Ignore the routing header and proceed to process the next header. // - Offset = Offset + (RoutingHead->HeaderLen + 1) * 8; + Offset = Offset + IP6_HDR_EXT_LEN (RoutingHead->HeaderLen); if (UnFragmentLen != NULL) { *UnFragmentLen = Offset; @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // to the packet's source address, pointing to the unrecognized routing // type. // - Pointer = Offset + 2 + sizeof (EFI_IP6_HEADER); + Pointer = Offset + sizeof (IP6_EXT_HDR) + sizeof (EFI_IP6_HEADER); if ((IpSb != NULL) && (Packet != NULL) && !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) { @@ -XXX,XX +XXX,XX @@ Ip6IsExtsValid ( // // RFC2402, Payload length is specified in 32-bit words, minus "2". // - OptionLen = (UINT8)((*Option + 2) * 4); + OptionLen = ((UINT16)(*Option + 2) * 4); Offset = Offset + OptionLen; break; -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114470): https://edk2.groups.io/g/devel/message/114470 Mute This Topic: https://groups.io/mt/103964983/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> 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 <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 10 +- .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 +++ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 278 ++++++++++++++++++ 3 files changed, 324 insertions(+), 4 deletions(-) create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ ## @file -# Unit test suite for the Ip6Dxe using Google Test +# Unit test suite for the Ip6DxeGoogleTest using Google Test # # Copyright (c) Microsoft Corporation.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent ## [Defines] INF_VERSION = 0x00010017 - BASE_NAME = Ip6DxeUnitTest - FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A + BASE_NAME = Ip6DxeGoogleTest + FILE_GUID = AE39981C-B7FE-41A8-A9C2-F41910477CA3 VERSION_STRING = 1.0 MODULE_TYPE = HOST_APPLICATION # @@ -XXX,XX +XXX,XX @@ [Defines] # VALID_ARCHITECTURES = IA32 X64 AARCH64 # [Sources] + ../Ip6Option.c + Ip6OptionGoogleTest.h Ip6DxeGoogleTest.cpp Ip6OptionGoogleTest.cpp - ../Ip6Option.c + Ip6OptionGoogleTest.h [Packages] MdePkg/MdePkg.dec diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + Exposes the functions needed to test the Ip6Option module. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef IP6_OPTION_HEADER_GOOGLE_TEST_H_ +#define IP6_OPTION_HEADER_GOOGLE_TEST_H_ + +#include <Uefi.h> +#include "../Ip6Impl.h" + +/** + Validate the IP6 option format for both the packets we received + and that we will transmit. It will compute the ICMPv6 error message fields + if the option is malformatted. + + @param[in] IpSb The IP6 service data. + @param[in] Packet The to be validated packet. + @param[in] Option The first byte of the option. + @param[in] OptionLen The length of the whole option. + @param[in] Pointer Identifies the octet offset within + the invoking packet where the error was detected. + + + @retval TRUE The option is properly formatted. + @retval FALSE The option is malformatted. + +**/ +BOOLEAN +Ip6IsOptionValid ( + IN IP6_SERVICE *IpSb, + IN NET_BUF *Packet, + IN UINT8 *Option, + IN UINT16 OptionLen, + IN UINT32 Pointer + ); + +#endif // __IP6_OPTION_HEADER_GOOGLE_TEST_H__ diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp +++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ extern "C" { #include <Library/DebugLib.h> #include "../Ip6Impl.h" #include "../Ip6Option.h" + #include "Ip6OptionGoogleTest.h" } ///////////////////////////////////////////////////////////////////////// @@ -XXX,XX +XXX,XX @@ TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse) EXPECT_FALSE (Ip6IsNDOptionValid (option, optionLen)); } + +//////////////////////////////////////////////////////////////////////// +// Ip6IsOptionValid Tests +//////////////////////////////////////////////////////////////////////// + +// Define a fixture for your tests if needed +class Ip6IsOptionValidTest : public ::testing::Test { +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + // Initialize any resources or variables + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + // Clean up any resources or variables + } +}; + +// Test Description +// Verify that a NULL option is Invalid +TEST_F (Ip6IsOptionValidTest, NullOptionShouldReturnTrue) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + IP6_SERVICE *IpSb = NULL; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + EXPECT_FALSE (Ip6IsOptionValid (IpSb, &Packet, NULL, 0, 0)); +} + +// Test Description +// Verify that an unknown option with a length of 0 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength0) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 0; // This will cause an infinite loop if the function is not working correctly + + // This should be a valid option even though the length is 0 + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that an unknown option with a length of 1 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLength1) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 1; // This will cause an infinite loop if the function is not working correctly + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that an unknown option with a length of 2 and type of <unknown> does not cause an infinite loop +TEST_F (Ip6IsOptionValidTest, VerifyIpSkipUnknownOption) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 2; // Valid length for an unknown option + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that Ip6OptionPad1 is valid with a length of 0 +TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPad1) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPad1; + optionHeader.Length = 0; + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that Ip6OptionPadN doesn't overflow with various lengths +TEST_F (Ip6IsOptionValidTest, VerifyIp6OptionPadN) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = Ip6OptionPadN; + optionHeader.Length = 0xFF; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFE; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFD; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFC; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify an unknown option doesn't cause an infinite loop with various lengths +TEST_F (Ip6IsOptionValidTest, VerifyNoInfiniteLoopOnUnknownOptionLengthAttemptOverflow) { + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + IP6_OPTION_HEADER optionHeader; + + optionHeader.Type = 23; // Unknown Option + optionHeader.Length = 0xFF; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFE; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFD; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); + + optionHeader.Length = 0xFC; + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, sizeof (optionHeader), 0)); +} + +// Test Description +// Verify that the function supports multiple options +TEST_F (Ip6IsOptionValidTest, MultiOptionSupport) { + UINT16 HdrLen; + NET_BUF Packet = { 0 }; + // we need to define enough of the packet to make the function work + // The function being tested will pass IpSb to Ip6SendIcmpError which is defined above + UINT32 DeadCode = 0xDeadC0de; + // Don't actually use this pointer, just pass it to the function, nothing will be done with it + IP6_SERVICE *IpSb = (IP6_SERVICE *)&DeadCode; + + EFI_IPv6_ADDRESS SourceAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IPv6_ADDRESS DestinationAddress = { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29 }; + EFI_IP6_HEADER Ip6Header = { 0 }; + + Ip6Header.SourceAddress = SourceAddress; + Ip6Header.DestinationAddress = DestinationAddress; + Packet.Ip.Ip6 = &Ip6Header; + + UINT8 ExtHdr[1024] = { 0 }; + UINT8 *Cursor = ExtHdr; + IP6_OPTION_HEADER *Option = (IP6_OPTION_HEADER *)ExtHdr; + + // Let's start chaining options + + Option->Type = 23; // Unknown Option + Option->Length = 0xFC; + + Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionPad1; + + Cursor += sizeof (1); + + // Type and length aren't processed, instead it just moves the pointer forward by 4 bytes + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionRouterAlert; + Option->Length = 4; + + Cursor += sizeof (IP6_OPTION_HEADER) + 4; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionPadN; + Option->Length = 0xFC; + + Cursor += sizeof (IP6_OPTION_HEADER) + 0xFC; + + Option = (IP6_OPTION_HEADER *)Cursor; + Option->Type = Ip6OptionRouterAlert; + Option->Length = 4; + + Cursor += sizeof (IP6_OPTION_HEADER) + 4; + + // Total 524 + + HdrLen = (UINT16)(Cursor - ExtHdr); + + EXPECT_TRUE (Ip6IsOptionValid (IpSb, &Packet, ExtHdr, HdrLen, 0)); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114471): https://edk2.groups.io/g/devel/message/114471 Mute This Topic: https://groups.io/mt/103964985/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 Bug Details: PixieFail Bug #6 CVE-2023-45234 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise message Change Overview: Introduces a function to cache the Dns Server and perform sanitizing on the incoming DnsServerLen to ensure that the length is valid > + EFI_STATUS > + PxeBcCacheDnsServerAddresses ( > + IN PXEBC_PRIVATE_DATA *Private, > + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 > + ) Additional code cleanup Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 71 +++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -XXX,XX +XXX,XX @@ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent @@ -XXX,XX +XXX,XX @@ PxeBcSelectDhcp6Offer ( } } +/** + Cache the DHCPv6 DNS Server addresses + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. + + @retval EFI_SUCCESS Cache the DHCPv6 DNS Server address successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_DEVICE_ERROR The DNS Server Address Length provided by a untrusted + option is not a multiple of 16 bytes (sizeof (EFI_IPv6_ADDRESS)). +**/ +EFI_STATUS +PxeBcCacheDnsServerAddresses ( + IN PXEBC_PRIVATE_DATA *Private, + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ) +{ + UINT16 DnsServerLen; + + DnsServerLen = NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen); + // + // Make sure that the number is nonzero + // + if (DnsServerLen == 0) { + return EFI_DEVICE_ERROR; + } + + // + // Make sure the DnsServerlen is a multiple of EFI_IPv6_ADDRESS (16) + // + if (DnsServerLen % sizeof (EFI_IPv6_ADDRESS) != 0) { + return EFI_DEVICE_ERROR; + } + + // + // This code is currently written to only support a single DNS Server instead + // of multiple such as is spec defined (RFC3646, Section 3). The proper behavior + // would be to allocate the full space requested, CopyMem all of the data, + // and then add a DnsServerCount field to Private and update additional code + // that depends on this. + // + // To support multiple DNS servers the `AllocationSize` would need to be changed to DnsServerLen + // + // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886 + // + Private->DnsServer = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS)); + if (Private->DnsServer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Intentionally only copy over the first server address. + // To support multiple DNS servers, the `Length` would need to be changed to DnsServerLen + // + CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); + + return EFI_SUCCESS; +} + /** Handle the DHCPv6 offer packet. @@ -XXX,XX +XXX,XX @@ PxeBcHandleDhcp6Offer ( UINT32 SelectIndex; UINT32 Index; + ASSERT (Private != NULL); ASSERT (Private->SelectIndex > 0); SelectIndex = (UINT32)(Private->SelectIndex - 1); ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); @@ -XXX,XX +XXX,XX @@ PxeBcHandleDhcp6Offer ( Status = EFI_SUCCESS; // - // First try to cache DNS server address if DHCP6 offer provides. + // First try to cache DNS server addresses if DHCP6 offer provides. // if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { - Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); - if (Private->DnsServer == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = PxeBcCacheDnsServerAddresses (Private, Cache6); + if (EFI_ERROR (Status)) { + return Status; } - - CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); } if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114472): https://edk2.groups.io/g/devel/message/114472 Mute This Topic: https://groups.io/mt/103964986/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 Unit tests to that the bug.. Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise message ..has been patched This contains tests for the following functions: PxeBcHandleDhcp6Offer PxeBcCacheDnsServerAddresses Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 + .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 48 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 50 +++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 300 ++++++++++++++++++ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 19 ++ 5 files changed, 418 insertions(+) create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf + NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf @@ -XXX,XX +XXX,XX @@ +## @file +# Unit test suite for the UefiPxeBcDxe using Google Test +# +# Copyright (c) Microsoft Corporation.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +[Defines] +INF_VERSION = 0x00010005 +BASE_NAME = UefiPxeBcDxeGoogleTest +FILE_GUID = 77D45C64-EC1E-4174-887B-886E89FD1EDF +MODULE_TYPE = HOST_APPLICATION +VERSION_STRING = 1.0 + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + UefiPxeBcDxeGoogleTest.cpp + PxeBcDhcp6GoogleTest.cpp + PxeBcDhcp6GoogleTest.h + ../PxeBcDhcp6.c + ../PxeBcSupport.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec + NetworkPkg/NetworkPkg.dec + +[LibraryClasses] + GoogleTestLib + DebugLib + NetLib + PcdLib + +[Protocols] + gEfiDhcp6ServiceBindingProtocolGuid + gEfiDns6ServiceBindingProtocolGuid + gEfiDns6ProtocolGuid + +[Pcd] + gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType + +[Guids] + gZeroGuid diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h @@ -XXX,XX +XXX,XX @@ +/** @file + This file exposes the internal interfaces which may be unit tested + for the PxeBcDhcp6Dxe driver. + + Copyright (c) Microsoft Corporation.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef PXE_BC_DHCP6_GOOGLE_TEST_H_ +#define PXE_BC_DHCP6_GOOGLE_TEST_H_ + +// +// Minimal includes needed to compile +// +#include <Uefi.h> +#include "../PxeBcImpl.h" + +/** + Handle the DHCPv6 offer packet. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. + @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet. + +**/ +EFI_STATUS +PxeBcHandleDhcp6Offer ( + IN PXEBC_PRIVATE_DATA *Private + ); + +/** + Cache the DHCPv6 Server address + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. + + @retval EFI_SUCCESS Cache the DHCPv6 Server address successfully. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_DEVICE_ERROR Failed to cache the DHCPv6 Server address. +**/ +EFI_STATUS +PxeBcCacheDnsServerAddresses ( + IN PXEBC_PRIVATE_DATA *Private, + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ); + +#endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Host based unit test for PxeBcDhcp6.c. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +extern "C" { + #include <Uefi.h> + #include <Library/BaseLib.h> + #include <Library/DebugLib.h> + #include "../PxeBcImpl.h" + #include "../PxeBcDhcp6.h" + #include "PxeBcDhcp6GoogleTest.h" +} + +/////////////////////////////////////////////////////////////////////////////// +// Definitions +/////////////////////////////////////////////////////////////////////////////// + +#define PACKET_SIZE (1500) + +typedef struct { + UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03) + UINT16 OptionLen; // The length of the option (e.g., 16 bytes) + UINT8 ServerId[16]; // The 16-byte DHCPv6 Server Identifier +} DHCP6_OPTION_SERVER_ID; + +/////////////////////////////////////////////////////////////////////////////// +/// Symbol Definitions +/////////////////////////////////////////////////////////////////////////////// + +EFI_STATUS +MockUdpWrite ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp OPTIONAL, + IN EFI_IP_ADDRESS *SrcIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +MockUdpRead ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL, + IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL, + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + return EFI_SUCCESS; +} + +EFI_STATUS +MockConfigure ( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +// Needed by PxeBcSupport +EFI_STATUS +EFIAPI +QueueDpc ( + IN EFI_TPL DpcTpl, + IN EFI_DPC_PROCEDURE DpcProcedure, + IN VOID *DpcContext OPTIONAL + ) +{ + return EFI_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcHandleDhcp6OfferTest Tests +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcHandleDhcp6OfferTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + EFI_PXE_BASE_CODE_MODE Mode = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + + // Need to setup the EFI_PXE_BASE_CODE_MODE + Private.PxeBc.Mode = &Mode; + + // for this test it doesn't really matter what the Dhcpv6 ack is set to + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +// Note: +// Testing PxeBcHandleDhcp6Offer() is difficult because it depends on a +// properly setup Private structure. Attempting to properly test this function +// without a signficant refactor is a fools errand. Instead, we will test +// that we can prevent an overflow in the function. +TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) { + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337); + + ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR); +} + +class PxeBcCacheDnsServerAddressesTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + } +}; + +// Test Description +// Test that we cache the DNS server address from the DHCPv6 offer packet +TEST_F (PxeBcCacheDnsServerAddressesTest, BasicUsageTest) { + UINT8 SearchPattern[16] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF }; + EFI_DHCP6_PACKET_OPTION *Option; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Option = (EFI_DHCP6_PACKET_OPTION *)AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + sizeof (SearchPattern)); + ASSERT_NE (Option, nullptr); + + Option->OpCode = DHCP6_OPT_SERVER_ID; + Option->OpLen = NTOHS (sizeof (SearchPattern)); + CopyMem (Option->Data, SearchPattern, sizeof (SearchPattern)); + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; + + Private.DnsServer = nullptr; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS); + ASSERT_NE (Private.DnsServer, nullptr); + ASSERT_EQ (CompareMem (Private.DnsServer, SearchPattern, sizeof (SearchPattern)), 0); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } + + if (Option) { + FreePool (Option); + } +} +// Test Description +// Test that we can prevent an overflow in the function +TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptOverflowTest) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR); + ASSERT_EQ (Private.DnsServer, nullptr); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} + +// Test Description +// Test that we can prevent an underflow in the function +TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptUnderflowTest) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (2); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR); + ASSERT_EQ (Private.DnsServer, nullptr); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} + +// Test Description +// Test that we can handle recursive dns (multiple dns entries) +TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) { + EFI_DHCP6_PACKET_OPTION Option = { 0 }; + PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL; + + Private.SelectIndex = 1; // SelectIndex is 1-based + Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6; + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option; + // Setup the DHCPv6 offer packet + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID; + + EFI_IPv6_ADDRESS addresses[2] = { + // 2001:db8:85a3::8a2e:370:7334 + { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 }, + // fe80::d478:91c3:ecd7:4ff9 + { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x78, 0x91, 0xc3, 0xec, 0xd7, 0x4f, 0xf9 } + }; + + CopyMem (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, &addresses, sizeof (addresses)); + + Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (sizeof (addresses)); + + Private.DnsServer = NULL; + + ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS); + + ASSERT_NE (Private.DnsServer, nullptr); + + // + // This is expected to fail until DnsServer supports multiple DNS servers + // + // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886 + // + // Disabling: + // ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0); + + if (Private.DnsServer) { + FreePool (Private.DnsServer); + } +} diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp @@ -XXX,XX +XXX,XX @@ +/** @file + Acts as the main entry point for the tests for the UefiPxeBcDxe module. + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include <gtest/gtest.h> + +//////////////////////////////////////////////////////////////////////////////// +// Run the tests +//////////////////////////////////////////////////////////////////////////////// +int +main ( + int argc, + char *argv[] + ) +{ + testing::InitGoogleTest (&argc, argv); + return RUN_ALL_TESTS (); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114473): https://edk2.groups.io/g/devel/message/114473 Mute This Topic: https://groups.io/mt/103964987/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
This adds support for GetTime Google Test Mock Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Zhiguang Liu <zhiguang.liu@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- .../GoogleTest/Library/MockUefiRuntimeServicesTableLib.h | 7 +++++++ .../MockUefiRuntimeServicesTableLib.cpp | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h b/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h +++ b/MdePkg/Test/Mock/Include/GoogleTest/Library/MockUefiRuntimeServicesTableLib.h @@ -XXX,XX +XXX,XX @@ struct MockUefiRuntimeServicesTableLib { IN UINTN DataSize, IN VOID *Data) ); + + MOCK_FUNCTION_DECLARATION ( + EFI_STATUS, + gRT_GetTime, + (OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL) + ); }; #endif diff --git a/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp b/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp index XXXXXXX..XXXXXXX 100644 --- a/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp +++ b/MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.cpp @@ -XXX,XX +XXX,XX @@ MOCK_INTERFACE_DEFINITION (MockUefiRuntimeServicesTableLib); MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_GetVariable, 5, EFIAPI); MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_SetVariable, 5, EFIAPI); +MOCK_FUNCTION_DEFINITION (MockUefiRuntimeServicesTableLib, gRT_GetTime, 2, EFIAPI); static EFI_RUNTIME_SERVICES localRt = { - { 0 }, // EFI_TABLE_HEADER + { 0 }, // EFI_TABLE_HEADER - NULL, // EFI_GET_TIME + gRT_GetTime, // EFI_GET_TIME NULL, // EFI_SET_TIME NULL, // EFI_GET_WAKEUP_TIME NULL, // EFI_SET_WAKEUP_TIME -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114474): https://edk2.groups.io/g/devel/message/114474 Mute This Topic: https://groups.io/mt/103964988/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 Bug Details: PixieFail Bug #7 CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message Change Overview: Performs two checks 1. Checks that the length of the duid is accurate > + // > + // Check that the minimum and maximum requirements are met > + // > + if ((OpLen < PXEBC_MIN_SIZE_OF_DUID) || (OpLen > PXEBC_MAX_SIZE_OF_DUID)) { > + Status = EFI_INVALID_PARAMETER; > + goto ON_ERROR; > + } 2. Ensures that the amount of data written to the buffer is tracked and never exceeds that > + // > + // Check that the option length is valid. > + // > + if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) { > + Status = EFI_OUT_OF_RESOURCES; > + goto ON_ERROR; > + } Additional code clean up and fix for memory leak in case Option was NULL Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 ++++++ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 77 ++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h @@ -XXX,XX +XXX,XX @@ #define PXEBC_ADDR_START_DELIMITER '[' #define PXEBC_ADDR_END_DELIMITER ']' +// +// A DUID consists of a 2-octet type code represented in network byte +// order, followed by a variable number of octets that make up the +// actual identifier. The length of the DUID (not including the type +// code) is at least 1 octet and at most 128 octets. +// +#define PXEBC_MIN_SIZE_OF_DUID (sizeof(UINT16) + 1) +#define PXEBC_MAX_SIZE_OF_DUID (sizeof(UINT16) + 128) + +// +// This define represents the combineds code and length field from +// https://datatracker.ietf.org/doc/html/rfc3315#section-22.1 +// +#define PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN \ + (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode) + \ + sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen)) + #define GET_NEXT_DHCP6_OPTION(Opt) \ (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \ sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1) diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( EFI_STATUS Status; EFI_DHCP6_PACKET *IndexOffer; UINT8 *Option; + UINTN DiscoverLenNeeded; PxeBc = &Private->PxeBc; Request = Private->Dhcp6Request; @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( return EFI_DEVICE_ERROR; } - Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); + DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); + Discover = AllocateZeroPool (DiscoverLenNeeded); if (Discover == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( DHCP6_OPT_SERVER_ID ); if (Option == NULL) { - return EFI_NOT_FOUND; + Status = EFI_NOT_FOUND; + goto ON_ERROR; } // // Add Server ID Option. // OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen); - CopyMem (DiscoverOpt, Option, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + + // + // Check that the minimum and maximum requirements are met + // + if ((OpLen < PXEBC_MIN_SIZE_OF_DUID) || (OpLen > PXEBC_MAX_SIZE_OF_DUID)) { + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + + // + // Check that the option length is valid. + // + if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + CopyMem (DiscoverOpt, Option, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } while (RequestLen < Request->Length) { @@ -XXX,XX +XXX,XX @@ PxeBcRequestBootService ( (OpCode != DHCP6_OPT_SERVER_ID) ) { + // + // Check that the option length is valid. + // + if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // // Copy all the options except IA option and Server ID // - CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } - RequestOpt += (OpLen + 4); - RequestLen += (OpLen + 4); + RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } // @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( UINT16 OpLen; UINT32 Xid; EFI_STATUS Status; + UINTN DiscoverLenNeeded; PxeBc = &Private->PxeBc; Mode = PxeBc->Mode; @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( return EFI_DEVICE_ERROR; } - Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); + DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); + Discover = AllocateZeroPool (DiscoverLenNeeded); if (Discover == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -XXX,XX +XXX,XX @@ PxeBcDhcp6Discover ( DiscoverLen = sizeof (EFI_DHCP6_HEADER); RequestLen = DiscoverLen; + // + // The request packet is generated by the UEFI network stack. In the DHCP4 DORA and DHCP6 SARR sequence, + // the first (discover in DHCP4 and solicit in DHCP6) and third (request in both DHCP4 and DHCP6) are + // generated by the DHCP client (the UEFI network stack in this case). By the time this function executes, + // the DHCP sequence already has been executed once (see UEFI Specification Figures 24.2 and 24.3), with + // Private->Dhcp6Request being a cached copy of the DHCP6 request packet that UEFI network stack previously + // generated and sent. + // + // Therefore while this code looks like it could overflow, in practice it's not possible. + // while (RequestLen < Request->Length) { OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode); OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen); if ((OpCode != EFI_DHCP6_IA_TYPE_NA) && (OpCode != EFI_DHCP6_IA_TYPE_TA)) { + if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // // Copy all the options except IA option. // - CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); + CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } - RequestOpt += (OpLen + 4); - RequestLen += (OpLen + 4); + RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); } Status = PxeBc->UdpWrite ( -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114475): https://edk2.groups.io/g/devel/message/114475 Mute This Topic: https://groups.io/mt/103964991/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
From: Doug Flick <dougflick@microsoft.com> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 Unit tests to confirm that the bug.. Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message ..has been patched. This patch contains unit tests for the following functions: PxeBcRequestBootService PxeBcDhcp6Discover Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/Test/NetworkPkgHostTest.dsc | 5 +- .../GoogleTest/PxeBcDhcp6GoogleTest.h | 18 ++ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 278 +++++++++++++++++- 3 files changed, 298 insertions(+), 3 deletions(-) diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/Test/NetworkPkgHostTest.dsc +++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc @@ -XXX,XX +XXX,XX @@ [Components] # NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf - NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf + NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf { + <LibraryClasses> + UefiRuntimeServicesTableLib|MdePkg/Test/Mock/Library/GoogleTest/MockUefiRuntimeServicesTableLib/MockUefiRuntimeServicesTableLib.inf + } # Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests. [LibraryClasses] diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h @@ -XXX,XX +XXX,XX @@ PxeBcCacheDnsServerAddresses ( IN PXEBC_DHCP6_PACKET_CACHE *Cache6 ); +/** + Build and send out the request packet for the bootfile, and parse the reply. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Index PxeBc option boot item type. + + @retval EFI_SUCCESS Successfully discovered the boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover the boot file. + +**/ +EFI_STATUS +PxeBcRequestBootService ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ); + #endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp index XXXXXXX..XXXXXXX 100644 --- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp @@ -XXX,XX +XXX,XX @@ Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ -#include <gtest/gtest.h> +#include <Library/GoogleTestLib.h> +#include <GoogleTest/Library/MockUefiLib.h> +#include <GoogleTest/Library/MockUefiRuntimeServicesTableLib.h> extern "C" { #include <Uefi.h> @@ -XXX,XX +XXX,XX @@ extern "C" { // Definitions /////////////////////////////////////////////////////////////////////////////// -#define PACKET_SIZE (1500) +#define PACKET_SIZE (1500) +#define REQUEST_OPTION_LENGTH (120) typedef struct { UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03) @@ -XXX,XX +XXX,XX @@ MockConfigure ( } // Needed by PxeBcSupport +EFI_STATUS +PxeBcDns6 ( + IN PXEBC_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress + ) +{ + return EFI_SUCCESS; +} + +UINT32 +PxeBcBuildDhcp6Options ( + IN PXEBC_PRIVATE_DATA *Private, + OUT EFI_DHCP6_PACKET_OPTION **OptList, + IN UINT8 *Buffer + ) +{ + return EFI_SUCCESS; +} + EFI_STATUS EFIAPI QueueDpc ( @@ -XXX,XX +XXX,XX @@ TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) { ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR); } +/////////////////////////////////////////////////////////////////////////////// +// PxeBcCacheDnsServerAddresses Tests +/////////////////////////////////////////////////////////////////////////////// + class PxeBcCacheDnsServerAddressesTest : public ::testing::Test { public: PXEBC_PRIVATE_DATA Private = { 0 }; @@ -XXX,XX +XXX,XX @@ TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) { FreePool (Private.DnsServer); } } + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcRequestBootServiceTest Test Cases +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcRequestBootServiceTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + +protected: + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +TEST_F (PxeBcRequestBootServiceTest, ServerDiscoverBasicUsageTest) { + PxeBcRequestBootServiceTest::Private.OfferBuffer[0].Dhcp6.OfferType = PxeOfferTypeProxyBinl; + + DHCP6_OPTION_SERVER_ID Server = { 0 }; + + Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID); + Server.OptionLen = HTONS (16); // valid length + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer[Index].Dhcp6.Packet.Offer; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &Server, sizeof (Server)); + Cursor += sizeof (Server); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS); +} + +TEST_F (PxeBcRequestBootServiceTest, AttemptDiscoverOverFlowExpectFailure) { + PxeBcRequestBootServiceTest::Private.OfferBuffer[0].Dhcp6.OfferType = PxeOfferTypeProxyBinl; + + DHCP6_OPTION_SERVER_ID Server = { 0 }; + + Server.OptionCode = HTONS (DHCP6_OPT_SERVER_ID); + Server.OptionLen = HTONS (1500); // This length would overflow without a check + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.OfferBuffer[Index].Dhcp6.Packet.Offer; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &Server, sizeof (Server)); + Cursor += sizeof (Server); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + // This is going to be stopped by the duid overflow check + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_INVALID_PARAMETER); +} + +TEST_F (PxeBcRequestBootServiceTest, RequestBasicUsageTest) { + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = 0; // valid length + + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request[Index]; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_SUCCESS); +} + +TEST_F (PxeBcRequestBootServiceTest, AttemptRequestOverFlowExpectFailure) { + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = 1500; // this length would overflow without a check + + UINT8 Index = 0; + + EFI_DHCP6_PACKET *Packet = (EFI_DHCP6_PACKET *)&Private.Dhcp6Request[Index]; + + UINT8 *Cursor = (UINT8 *)(Packet->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + // Update the packet length + Packet->Length = (UINT16)(Cursor - (UINT8 *)Packet); + Packet->Size = PACKET_SIZE; + + ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_OUT_OF_RESOURCES); +} + +/////////////////////////////////////////////////////////////////////////////// +// PxeBcDhcp6Discover Test +/////////////////////////////////////////////////////////////////////////////// + +class PxeBcDhcp6DiscoverTest : public ::testing::Test { +public: + PXEBC_PRIVATE_DATA Private = { 0 }; + EFI_UDP6_PROTOCOL Udp6Read; + +protected: + MockUefiRuntimeServicesTableLib RtServicesMock; + + // Add any setup code if needed + virtual void + SetUp ( + ) + { + Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); + + // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL + // The function under test really only needs the following: + // UdpWrite + // UdpRead + + Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite; + Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead; + + // Need to setup EFI_UDP6_PROTOCOL + // The function under test really only needs the following: + // Configure + + Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure; + Private.Udp6Read = &Udp6Read; + } + + // Add any cleanup code if needed + virtual void + TearDown ( + ) + { + if (Private.Dhcp6Request != NULL) { + FreePool (Private.Dhcp6Request); + } + + // Clean up any resources or variables + } +}; + +// Test Description +// This will cause an overflow by an untrusted packet during the option parsing +TEST_F (PxeBcDhcp6DiscoverTest, BasicOverflowTest) { + EFI_IPv6_ADDRESS DestIp = { 0 }; + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = HTONS (0xFFFF); // overflow + + UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + Private.Dhcp6Request->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request); + + EXPECT_CALL (RtServicesMock, gRT_GetTime) + .WillOnce (::testing::Return (0)); + + ASSERT_EQ ( + PxeBcDhcp6Discover ( + &(PxeBcDhcp6DiscoverTest::Private), + 0, + NULL, + FALSE, + (EFI_IP_ADDRESS *)&DestIp + ), + EFI_OUT_OF_RESOURCES + ); +} + +// Test Description +// This will test that we can handle a packet with a valid option length +TEST_F (PxeBcDhcp6DiscoverTest, BasicUsageTest) { + EFI_IPv6_ADDRESS DestIp = { 0 }; + EFI_DHCP6_PACKET_OPTION RequestOpt = { 0 }; // the data section doesn't really matter + + RequestOpt.OpCode = HTONS (0x1337); + RequestOpt.OpLen = HTONS (0x30); + + UINT8 *Cursor = (UINT8 *)(Private.Dhcp6Request->Dhcp6.Option); + + CopyMem (Cursor, &RequestOpt, sizeof (RequestOpt)); + Cursor += sizeof (RequestOpt); + + Private.Dhcp6Request->Length = (UINT16)(Cursor - (UINT8 *)Private.Dhcp6Request); + + EXPECT_CALL (RtServicesMock, gRT_GetTime) + .WillOnce (::testing::Return (0)); + + ASSERT_EQ ( + PxeBcDhcp6Discover ( + &(PxeBcDhcp6DiscoverTest::Private), + 0, + NULL, + FALSE, + (EFI_IP_ADDRESS *)&DestIp + ), + EFI_SUCCESS + ); +} -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114476): https://edk2.groups.io/g/devel/message/114476 Mute This Topic: https://groups.io/mt/103964992/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
This creates / adds a security file that tracks the security fixes found in this package and can be used to find the fixes that were applied. Cc: Saloni Kasbekar <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> --- NetworkPkg/SecurityFixes.yaml | 123 ++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 NetworkPkg/SecurityFixes.yaml diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/NetworkPkg/SecurityFixes.yaml @@ -XXX,XX +XXX,XX @@ +## @file +# Security Fixes for SecurityPkg +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +CVE_2023_45229: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit Tests" + cve: CVE-2023-45229 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 01 - edk2/NetworkPkg: Out-of-bounds read when processing IA_NA/IA_TA options in a DHCPv6 Advertise message" + note: + files_impacted: + - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c + - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4534 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45229 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45230: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit Tests" + cve: CVE-2023-45230 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 02 - edk2/NetworkPkg: Buffer overflow in the DHCPv6 client via a long Server ID option" + note: + files_impacted: + - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c + - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4535 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45230 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45231: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Unit Tests" + cve: CVE-2023-45231 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 03 - edk2/NetworkPkg: Out-of-bounds read when handling a ND Redirect message with truncated options" + note: + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4536 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45231 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45232: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" + cve: CVE-2023-45232 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 04 - edk2/NetworkPkg: Infinite loop when parsing unknown options in the Destination Options header" + note: + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + - NetworkPkg/Ip6Dxe/Ip6Option.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4537 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45232 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45233: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" + cve: CVE-2023-45233 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 05 - edk2/NetworkPkg: Infinite loop when parsing a PadN option in the Destination Options header " + note: This was fixed along with CVE-2023-45233 + files_impacted: + - NetworkPkg/Ip6Dxe/Ip6Option.c + - NetworkPkg/Ip6Dxe/Ip6Option.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4538 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45233 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45234: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Unit Tests" + cve: CVE-2023-45234 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 06 - edk2/NetworkPkg: Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise message" + note: + files_impacted: + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4539 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45234 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45235: + commit_titles: + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Patch" + - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Unit Tests" + cve: CVE-2023-45235 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 07 - edk2/NetworkPkg: Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message" + note: + files_impacted: + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c + - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4540 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45235 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html -- 2.43.0 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114477): https://edk2.groups.io/g/devel/message/114477 Mute This Topic: https://groups.io/mt/103964993/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-