[OE-core][kirkstone 05/38] ovmf: Fix CVE-2023-45232, CVE-2023-45233

Steve Sakoman
2024-12-04T17:54:35Z

From: Soumya Sambu <soumya.sambu@windriver.com>

CVE-2023-45232:
EDK2's Network Package is susceptible to an infinite loop vulnerability
when parsing unknown options in the Destination Options header of IPv6.
This vulnerability can be exploited by an attacker to gain unauthorized
access and potentially lead to a loss of Availability.

CVE-2023-45233:
EDK2's Network Package is susceptible to an infinite lop vulnerability
when parsing a PadN option in the Destination Options header of IPv6.
This vulnerability can be exploited by an attacker to gain unauthorized
access and potentially lead to a loss of Availability.

References:
https://nvd.nist.gov/vuln/detail/CVE-2023-45232
https://nvd.nist.gov/vuln/detail/CVE-2023-45233

Upstream-patches:
https://github.com/tianocore/edk2/commit/4df0229ef992d4f2721a8508787ebf9dc81fbd6e
https://github.com/tianocore/edk2/commit/c9c87f08dd6ace36fa843424522c3558a8374cac

Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
---
.../CVE-2023-45232-CVE-2023-45233-0001.patch | 360 +++++++++++++++
.../CVE-2023-45232-CVE-2023-45233-0002.patch | 417 ++++++++++++++++++
meta/recipes-core/ovmf/ovmf_git.bb | 2 +
3 files changed, 779 insertions(+)
create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch
create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch

diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch
new file mode 100644
index 0000000000..d43e971d9d
--- /dev/null
+++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch
@@ -0,0 +1,360 @@
+From 4df0229ef992d4f2721a8508787ebf9dc81fbd6e Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 26 Jan 2024 05:54:50 +0800
+Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Patch
+
+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>
+Reviewed-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
+
+CVE: CVE-2023-45232, CVE-2023-45233
+
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4df0229ef992d4f2721a8508787ebf9dc81fbd6e]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ NetworkPkg/Ip6Dxe/Ip6Nd.h | 35 ++++++++++++++++
+ NetworkPkg/Ip6Dxe/Ip6Option.c | 76 ++++++++++++++++++++++++++++++-----
+ NetworkPkg/Ip6Dxe/Ip6Option.h | 71 ++++++++++++++++++++++++++++++++
+ 3 files changed, 171 insertions(+), 11 deletions(-)
+
+diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.h b/NetworkPkg/Ip6Dxe/Ip6Nd.h
+index 860934a167..bf64e9114e 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Nd.h
++++ b/NetworkPkg/Ip6Dxe/Ip6Nd.h
+@@ -56,13 +56,48 @@ 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.c b/NetworkPkg/Ip6Dxe/Ip6Option.c
+index 8718d5d875..fd97ce116f 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Option.c
++++ b/NetworkPkg/Ip6Dxe/Ip6Option.c
+@@ -17,7 +17,8 @@
+ @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.
+
+@@ -31,12 +32,33 @@ 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;
+
+@@ -54,7 +76,8 @@ 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:
+ //
+@@ -69,7 +92,8 @@ 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;
+@@ -308,7 +332,7 @@ Ip6IsExtsValid (
+ UINT32 Pointer;
+ UINT32 Offset;
+ UINT8 *Option;
+- UINT8 OptionLen;
++ UINT16 OptionLen;
+ BOOLEAN Flag;
+ UINT8 CountD;
+ UINT8 CountA;
+@@ -385,6 +409,36 @@ 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++;
+ }
+@@ -398,7 +452,7 @@ Ip6IsExtsValid (
+
+ Offset++;
+ Option = ExtHdrs + Offset;
+- OptionLen = (UINT8)((*Option + 1) * 8 - 2);
++ OptionLen = IP6_HDR_EXT_LEN (*Option) - sizeof (IP6_EXT_HDR);
+ Option++;
+ Offset++;
+
+@@ -430,7 +484,7 @@ 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;
+@@ -441,7 +495,7 @@ 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))
+ {
+@@ -527,7 +581,7 @@ 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;
+
+diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.h b/NetworkPkg/Ip6Dxe/Ip6Option.h
+index bd8e223c8a..fb07c28f5a 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Option.h
++++ b/NetworkPkg/Ip6Dxe/Ip6Option.h
+@@ -12,6 +12,77 @@
+
+ #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;
+--
+2.40.0
+
diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch
new file mode 100644
index 0000000000..c6834a852e
--- /dev/null
+++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch
@@ -0,0 +1,417 @@
+From c9c87f08dd6ace36fa843424522c3558a8374cac Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 26 Jan 2024 05:54:51 +0800
+Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests
+
+REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537
+REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538
+
+Unit tests to confirm that..
+
+Infinite loop when parsing unknown options in the Destination Options
+header
+
+and
+
+Infinite loop when parsing a PadN option in the Destination Options
+header
+
+... have been patched
+
+This patch tests the following functions:
+Ip6IsOptionValid
+
+Cc: Saloni Kasbekar <saloni.kasbekar@intel.com>
+Cc: Zachary Clark-williams <zachary.clark-williams@intel.com>
+
+Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
+Reviewed-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
+
+CVE: CVE-2023-45232, CVE-2023-45233
+
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/c9c87f08dd6ace36fa843424522c3558a8374cac]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 10 +-
+ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 278 ++++++++++++++++++
+ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 +++
+ 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 6e4de0745f..ba29dbabad 100644
+--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+@@ -1,13 +1,13 @@
+ ## @file
+-# Unit test suite for the Ip6Dxe using Google Test
++# Unit test suite for the Ip6DxeGoogleTest using Google Test
+ #
+ # Copyright (c) Microsoft Corporation.
+ # 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
+ #
+@@ -16,9 +16,11 @@
+ # 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.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+index f2cd90e1a9..29f8a4a96e 100644
+--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+@@ -12,6 +12,7 @@ extern "C" {
+ #include <Library/DebugLib.h>
+ #include "../Ip6Impl.h"
+ #include "../Ip6Option.h"
++ #include "Ip6OptionGoogleTest.h"
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+@@ -127,3 +128,280 @@ 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));
++}
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h
+new file mode 100644
+index 0000000000..0509b6ae30
+--- /dev/null
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h
+@@ -0,0 +1,40 @@
++/** @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__
+--
+2.40.0
+
diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb
index e46b3ddebe..fc87cdf441 100644
--- a/meta/recipes-core/ovmf/ovmf_git.bb
+++ b/meta/recipes-core/ovmf/ovmf_git.bb
@@ -37,6 +37,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \
file://CVE-2023-45230-0002.patch \
file://CVE-2023-45231-0001.patch \
file://CVE-2023-45231-0002.patch \
+ file://CVE-2023-45232-CVE-2023-45233-0001.patch \
+ file://CVE-2023-45232-CVE-2023-45233-0002.patch \
"

PV = "edk2-stable202202"
--
2.34.1