--- /dev/null
+From 0cf3620092c1f5d2093e5bfa43ff137b888f18b3 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 11:24:43 -0800
+Subject: [PATCH 01/12] SECURITY PATCH TCBZ4535 - CVE-2023-45230 - Patch
+
+---
+ NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 39 +++
+ NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 411 +++++++++++++++++---------
+ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 455 +++++++++++++++++++++--------
+ NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 82 +++---
+ 4 files changed, 707 insertions(+), 280 deletions(-)
+
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
+index 0eb9c669b5..b552331767 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
+@@ -45,6 +45,45 @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE;
+ #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S')\r
+ #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I')\r
+ \r
++//\r
++// For more information on DHCP options see RFC 8415, Section 21.1\r
++// \r
++// The format of DHCP options is:\r
++//\r
++// 0 1 2 3\r
++// 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\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | option-code | option-len |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | option-data |\r
++// | (option-len octets) |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++//\r
++#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16))\r
++#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16))\r
++\r
++// Combined size of Code and Length\r
++#define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \\r
++ DHCP6_SIZE_OF_OPT_LEN)\r
++\r
++STATIC_ASSERT (\r
++ DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN == 4,\r
++ "Combined size of Code and Length must be 4 per RFC 8415"\r
++ );\r
++\r
++// Offset to the length is just past the code\r
++#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE)\r
++STATIC_ASSERT (\r
++ DHCP6_OPT_LEN_OFFSET (0) == 2,\r
++ "Offset of length is + 2 past start of option"\r
++ );\r
++\r
++#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)\r
++STATIC_ASSERT (\r
++ DHCP6_OPT_DATA_OFFSET(0) == 4,\r
++ "Offset to option data should be +4 from start of option"\r
++ );\r
++\r
+ #define DHCP6_PACKET_ALL 0\r
+ #define DHCP6_PACKET_STATEFUL 1\r
+ #define DHCP6_PACKET_STATELESS 2\r
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
+index dcd01e6268..1401910950 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
+@@ -3,9 +3,9 @@
+ \r
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
++ Copyright (c) Microsoft Corporation\r
+ \r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-\r
+ **/\r
+ \r
+ #include "Dhcp6Impl.h"\r
+@@ -930,7 +930,8 @@ Dhcp6SendSolicitMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
+@@ -944,54 +945,64 @@ Dhcp6SendSolicitMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance->IaCb.Ia,\r
+ Instance->IaCb.T1,\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ //\r
+ // Append user-defined when configurate Dhcp6 service.\r
+ //\r
+ for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
+ UserOpt = Instance->Config->OptionList[Index];\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ UserOpt->OpCode,\r
+ UserOpt->OpLen,\r
+ UserOpt->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+ // Callback to user with the packet to be sent and check the user's feedback.\r
+ //\r
+ Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1005,10 +1016,8 @@ Dhcp6SendSolicitMsg (
+ Instance->StartTime = 0;\r
+ \r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1020,6 +1029,14 @@ Dhcp6SendSolicitMsg (
+ Elapsed,\r
+ Instance->Config->SolicitRetransmission\r
+ );\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1110,7 +1127,8 @@ Dhcp6SendRequestMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
+@@ -1124,51 +1142,67 @@ Dhcp6SendRequestMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptServerId),\r
+ ServerId->Length,\r
+ ServerId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance->IaCb.Ia,\r
+ Instance->IaCb.T1,\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ //\r
+ // Append user-defined when configurate Dhcp6 service.\r
+ //\r
+ for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
+ UserOpt = Instance->Config->OptionList[Index];\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ UserOpt->OpCode,\r
+ UserOpt->OpLen,\r
+ UserOpt->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+@@ -1177,8 +1211,7 @@ Dhcp6SendRequestMsg (
+ Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet);\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1194,14 +1227,21 @@ Dhcp6SendRequestMsg (
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1266,7 +1306,8 @@ Dhcp6SendDeclineMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE;\r
+@@ -1280,42 +1321,58 @@ Dhcp6SendDeclineMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptServerId),\r
+ ServerId->Length,\r
+ ServerId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
++ DecIa,\r
++ 0,\r
++ 0,\r
++ Packet->Dhcp6.Header.MessageType\r
++ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+ // Callback to user with the packet to be sent and check the user's feedback.\r
+ //\r
+ Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1329,16 +1386,22 @@ Dhcp6SendDeclineMsg (
+ Instance->StartTime = 0;\r
+ \r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1399,7 +1462,8 @@ Dhcp6SendReleaseMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE;\r
+@@ -1413,45 +1477,61 @@ Dhcp6SendReleaseMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ //\r
+ // ServerId is extracted from packet, it's network order.\r
+ //\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptServerId),\r
+ ServerId->Length,\r
+ ServerId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
++ RelIa,\r
++ 0,\r
++ 0,\r
++ Packet->Dhcp6.Header.MessageType\r
++ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- //\r
+- // Determine the size/length of packet\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+ // Callback to user with the packet to be sent and check the user's feedback.\r
+ //\r
+ Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1461,16 +1541,22 @@ Dhcp6SendReleaseMsg (
+ Instance->IaCb.Ia->State = Dhcp6Releasing;\r
+ \r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1524,12 +1610,14 @@ Dhcp6SendRenewRebindMsg (
+ UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);\r
+ }\r
+ \r
++\r
+ //\r
+ // Create the Dhcp6 packet and initialize common fields.\r
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
+@@ -1543,26 +1631,38 @@ Dhcp6SendRenewRebindMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance->IaCb.Ia,\r
+ Instance->IaCb.T1,\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ if (!RebindRequest) {\r
+ //\r
+@@ -1578,18 +1678,22 @@ Dhcp6SendRenewRebindMsg (
+ Dhcp6OptServerId\r
+ );\r
+ if (Option == NULL) {\r
+- FreePool (Packet);\r
+- return EFI_DEVICE_ERROR;\r
++ Status = EFI_DEVICE_ERROR;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ ServerId = (EFI_DHCP6_DUID *)(Option + 2);\r
+ \r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptServerId),\r
+ ServerId->Length,\r
+ ServerId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+ //\r
+@@ -1597,18 +1701,19 @@ Dhcp6SendRenewRebindMsg (
+ //\r
+ for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
+ UserOpt = Instance->Config->OptionList[Index];\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ UserOpt->OpCode,\r
+ UserOpt->OpLen,\r
+ UserOpt->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
++\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+@@ -1618,10 +1723,8 @@ Dhcp6SendRenewRebindMsg (
+ Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing;\r
+ \r
+ Status = Dhcp6CallbackUser (Instance, Event, &Packet);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -1638,16 +1741,22 @@ Dhcp6SendRenewRebindMsg (
+ Instance->StartTime = 0;\r
+ \r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1811,7 +1920,8 @@ Dhcp6SendInfoRequestMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
+@@ -1828,44 +1938,56 @@ Dhcp6SendInfoRequestMsg (
+ \r
+ if (SendClientId) {\r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ OptionRequest->OpCode,\r
+ OptionRequest->OpLen,\r
+ OptionRequest->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ //\r
+ // Append user-defined when configurate Dhcp6 service.\r
+ //\r
+ for (Index = 0; Index < OptionCount; Index++) {\r
+ UserOpt = OptionList[Index];\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ UserOpt->OpCode,\r
+ UserOpt->OpLen,\r
+ UserOpt->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+@@ -1877,16 +1999,22 @@ Dhcp6SendInfoRequestMsg (
+ // Send info-request packet with no state.\r
+ //\r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool (Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+@@ -1937,7 +2065,8 @@ Dhcp6SendConfirmMsg (
+ //\r
+ Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);\r
+ if (Packet == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;\r
+@@ -1951,54 +2080,64 @@ Dhcp6SendConfirmMsg (
+ Cursor = Packet->Dhcp6.Option;\r
+ \r
+ Length = HTONS (ClientId->Length);\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ HTONS (Dhcp6OptClientId),\r
+ Length,\r
+ ClientId->Duid\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendETOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendETOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance,\r
+ &Elapsed\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+- Cursor = Dhcp6AppendIaOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendIaOption (\r
++ Packet,\r
++ &Cursor,\r
+ Instance->IaCb.Ia,\r
+ Instance->IaCb.T1,\r
+ Instance->IaCb.T2,\r
+ Packet->Dhcp6.Header.MessageType\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ \r
+ //\r
+ // Append user-defined when configurate Dhcp6 service.\r
+ //\r
+ for (Index = 0; Index < Instance->Config->OptionCount; Index++) {\r
+ UserOpt = Instance->Config->OptionList[Index];\r
+- Cursor = Dhcp6AppendOption (\r
+- Cursor,\r
++ Status = Dhcp6AppendOption (\r
++ Packet,\r
++ &Cursor,\r
+ UserOpt->OpCode,\r
+ UserOpt->OpLen,\r
+ UserOpt->Data\r
+ );\r
++ if (EFI_ERROR (Status)) {\r
++ goto ON_ERROR;\r
++ }\r
+ }\r
+ \r
+- //\r
+- // Determine the size/length of packet.\r
+- //\r
+- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);\r
+ ASSERT (Packet->Size > Packet->Length + 8);\r
+ \r
+ //\r
+ // Callback to user with the packet to be sent and check the user's feedback.\r
+ //\r
+ Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -2012,16 +2151,22 @@ Dhcp6SendConfirmMsg (
+ Instance->StartTime = 0;\r
+ \r
+ Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);\r
+-\r
+ if (EFI_ERROR (Status)) {\r
+- FreePool (Packet);\r
+- return Status;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Enqueue the sent packet for the retransmission in case reply timeout.\r
+ //\r
+ return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);\r
++\r
++ON_ERROR:\r
++\r
++ if (Packet) {\r
++ FreePool(Packet);\r
++ }\r
++\r
++ return Status;\r
+ }\r
+ \r
+ /**\r
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
+index e6368b5b1c..8f4bd1eb0f 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c
+@@ -142,12 +142,12 @@ Dhcp6GenerateClientId (
+ }\r
+ \r
+ Status = gRT->SetVariable (\r
+- L"ClientId",\r
+- &gEfiDhcp6ServiceBindingProtocolGuid,\r
+- (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),\r
+- Duid->Length + 2,\r
+- (VOID *)Duid\r
+- );\r
++ L"ClientId",\r
++ &gEfiDhcp6ServiceBindingProtocolGuid,\r
++ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),\r
++ Duid->Length + 2,\r
++ (VOID *)Duid\r
++ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (Duid);\r
+ return NULL;\r
+@@ -192,10 +192,10 @@ Dhcp6CopyConfigData (
+ }\r
+ \r
+ CopyMem (\r
+- DstCfg->SolicitRetransmission,\r
+- SorCfg->SolicitRetransmission,\r
+- sizeof (EFI_DHCP6_RETRANSMISSION)\r
+- );\r
++ DstCfg->SolicitRetransmission,\r
++ SorCfg->SolicitRetransmission,\r
++ sizeof (EFI_DHCP6_RETRANSMISSION)\r
++ );\r
+ }\r
+ \r
+ if ((SorCfg->OptionList != NULL) && (SorCfg->OptionCount != 0)) {\r
+@@ -221,10 +221,10 @@ Dhcp6CopyConfigData (
+ }\r
+ \r
+ CopyMem (\r
+- DstCfg->OptionList[Index],\r
+- SorCfg->OptionList[Index],\r
+- OptionSize\r
+- );\r
++ DstCfg->OptionList[Index],\r
++ SorCfg->OptionList[Index],\r
++ OptionSize\r
++ );\r
+ }\r
+ }\r
+ \r
+@@ -422,10 +422,10 @@ Dhcp6CheckAddress (
+ \r
+ for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r
+ if (CompareMem (\r
+- &Addresses[Index1],\r
+- &Ia->IaAddress[Index2],\r
+- sizeof (EFI_IPv6_ADDRESS)\r
+- ) == 0)\r
++ &Addresses[Index1],\r
++ &Ia->IaAddress[Index2],\r
++ sizeof (EFI_IPv6_ADDRESS)\r
++ ) == 0)\r
+ {\r
+ Found = TRUE;\r
+ break;\r
+@@ -503,28 +503,28 @@ Dhcp6DepriveAddress (
+ \r
+ for (Index2 = 0; Index2 < Ia->IaAddressCount; Index2++) {\r
+ if (CompareMem (\r
+- &Addresses[Index1],\r
+- &Ia->IaAddress[Index2],\r
+- sizeof (EFI_IPv6_ADDRESS)\r
+- ) == 0)\r
++ &Addresses[Index1],\r
++ &Ia->IaAddress[Index2],\r
++ sizeof (EFI_IPv6_ADDRESS)\r
++ ) == 0)\r
+ {\r
+ //\r
+ // Copy the deprived address to the copy of Ia\r
+ //\r
+ CopyMem (\r
+- &IaCopy->IaAddress[Index1],\r
+- &Ia->IaAddress[Index2],\r
+- sizeof (EFI_DHCP6_IA_ADDRESS)\r
+- );\r
++ &IaCopy->IaAddress[Index1],\r
++ &Ia->IaAddress[Index2],\r
++ sizeof (EFI_DHCP6_IA_ADDRESS)\r
++ );\r
+ //\r
+ // Delete the deprived address from the instance Ia\r
+ //\r
+ if (Index2 + 1 < Ia->IaAddressCount) {\r
+ CopyMem (\r
+- &Ia->IaAddress[Index2],\r
+- &Ia->IaAddress[Index2 + 1],\r
+- (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)\r
+- );\r
++ &Ia->IaAddress[Index2],\r
++ &Ia->IaAddress[Index2 + 1],\r
++ (Ia->IaAddressCount - Index2 - 1) * sizeof (EFI_DHCP6_IA_ADDRESS)\r
++ );\r
+ }\r
+ \r
+ Found = TRUE;\r
+@@ -577,24 +577,33 @@ Dhcp6OnTransmitted (
+ }\r
+ \r
+ /**\r
+- Append the option to Buf, and move Buf to the end.\r
++ Append the option to Buf, update the length of packet, and move Buf to the end.\r
+ \r
+- @param[in, out] Buf The pointer to the buffer.\r
+- @param[in] OptType The option type.\r
+- @param[in] OptLen The length of option contents.\r
+- @param[in] Data The pointer to the option content.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ will be updated.\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
++ @param[in] OptType The option type.\r
++ @param[in] OptLen The length of option contents.\r
++ @param[in] Data The pointer to the option content.\r
+ \r
+- @return Buf The position to append the next option.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ \r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN UINT16 OptType,\r
+- IN UINT16 OptLen,\r
+- IN UINT8 *Data\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN UINT16 OptType,\r
++ IN UINT16 OptLen,\r
++ IN UINT8 *Data\r
+ )\r
+ {\r
++ UINT32 Length;\r
++ UINT32 BytesNeeded;\r
++\r
+ //\r
+ // The format of Dhcp6 option:\r
+ //\r
+@@ -607,35 +616,95 @@ Dhcp6AppendOption (
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ //\r
+ \r
+- ASSERT (OptLen != 0);\r
++ //\r
++ // Verify the arguments are valid\r
++ //\r
++ if (Packet == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if (Data == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if (OptLen == 0) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ //\r
++ // Verify the PacketCursor is within the packet\r
++ //\r
++ if ( (*PacketCursor < Packet->Dhcp6.Option)\r
++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER))))\r
++ {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ //\r
++ // Calculate the bytes needed for the option\r
++ //\r
++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + NTOHS(OptLen);\r
+ \r
+- WriteUnaligned16 ((UINT16 *)Buf, OptType);\r
+- Buf += 2;\r
+- WriteUnaligned16 ((UINT16 *)Buf, OptLen);\r
+- Buf += 2;\r
+- CopyMem (Buf, Data, NTOHS (OptLen));\r
+- Buf += NTOHS (OptLen);\r
++ //\r
++ // Space remaining in the packet\r
++ //\r
++ Length = Packet->Size - Packet->Length;\r
++ if (Length < BytesNeeded) {\r
++ return EFI_BUFFER_TOO_SMALL;\r
++ }\r
++\r
++ //\r
++ // Verify the PacketCursor is within the packet\r
++ //\r
++ if ( (*PacketCursor < Packet->Dhcp6.Option)\r
++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER))))\r
++ {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
+ \r
+- return Buf;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, OptType);\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, OptLen);\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN;\r
++ CopyMem (*PacketCursor, Data, NTOHS (OptLen));\r
++ *PacketCursor += NTOHS (OptLen);\r
++\r
++ // Update the packet length by the length of the option + 4 bytes\r
++ Packet->Length += BytesNeeded;\r
++\r
++ return EFI_SUCCESS;\r
+ }\r
+ \r
+ /**\r
+ Append the appointed IA Address option to Buf, and move Buf to the end.\r
+ \r
+- @param[in, out] Buf The pointer to the position to append.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ will be updated.\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
+ @param[in] IaAddr The pointer to the IA Address.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
+ \r
+- @return Buf The position to append the next option.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ \r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendIaAddrOption (\r
+- IN OUT UINT8 *Buf,\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
+ IN EFI_DHCP6_IA_ADDRESS *IaAddr,\r
+ IN UINT32 MessageType\r
+ )\r
+ {\r
++ UINT32 BytesNeeded;\r
++ UINT32 Length;\r
++\r
+ // The format of the IA Address option is:\r
+ //\r
+ // 0 1 2 3\r
+@@ -657,17 +726,60 @@ Dhcp6AppendIaAddrOption (
+ // . .\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ \r
++ //\r
++ // Verify the arguments are valid\r
++ //\r
++ if (Packet == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if (IaAddr == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ //\r
++ // Verify the PacketCursor is within the packet\r
++ //\r
++ if ( (*PacketCursor < Packet->Dhcp6.Option)\r
++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER))))\r
++ {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN;\r
++ BytesNeeded += sizeof (EFI_IPv6_ADDRESS);\r
++ //\r
++ // Even if the preferred-lifetime is 0, it still needs to store it.\r
++ //\r
++ BytesNeeded += sizeof (IaAddr->PreferredLifetime);\r
++ //\r
++ // Even if the valid-lifetime is 0, it still needs to store it.\r
++ //\r
++ BytesNeeded += sizeof (IaAddr->ValidLifetime);\r
++\r
++ //\r
++ // Space remaining in the packet\r
++ //\r
++ Length = Packet->Size - Packet->Length;\r
++ if (Length < BytesNeeded) {\r
++ return EFI_BUFFER_TOO_SMALL;\r
++ }\r
++\r
+ //\r
+ // Fill the value of Ia Address option type\r
+ //\r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptIaAddr));\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptIaAddr));\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE;\r
+ \r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS)));\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN;\r
+ \r
+- CopyMem (Buf, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
+- Buf += sizeof (EFI_IPv6_ADDRESS);\r
++ CopyMem (*PacketCursor, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS));\r
++ *PacketCursor += sizeof (EFI_IPv6_ADDRESS);\r
+ \r
+ //\r
+ // Fill the value of preferred-lifetime and valid-lifetime.\r
+@@ -675,44 +787,58 @@ Dhcp6AppendIaAddrOption (
+ // should set to 0 when initiate a Confirm message.\r
+ //\r
+ if (MessageType != Dhcp6MsgConfirm) {\r
+- WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->PreferredLifetime));\r
++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->PreferredLifetime));\r
+ }\r
+ \r
+- Buf += 4;\r
++ *PacketCursor += sizeof (IaAddr->PreferredLifetime);\r
+ \r
+ if (MessageType != Dhcp6MsgConfirm) {\r
+- WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->ValidLifetime));\r
++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->ValidLifetime));\r
+ }\r
+ \r
+- Buf += 4;\r
++ *PacketCursor += sizeof (IaAddr->ValidLifetime);\r
++\r
++ //\r
++ // Update the packet length\r
++ //\r
++ Packet->Length += BytesNeeded;\r
+ \r
+- return Buf;\r
++ return EFI_SUCCESS;\r
+ }\r
+ \r
+ /**\r
+ Append the appointed Ia option to Buf, and move Buf to the end.\r
+ \r
+- @param[in, out] Buf The pointer to the position to append.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ will be updated.\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
+ @param[in] Ia The pointer to the Ia.\r
+ @param[in] T1 The time of T1.\r
+ @param[in] T2 The time of T2.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
+ \r
+- @return Buf The position to append the next Ia option.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ \r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendIaOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN EFI_DHCP6_IA *Ia,\r
+- IN UINT32 T1,\r
+- IN UINT32 T2,\r
+- IN UINT32 MessageType\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN EFI_DHCP6_IA *Ia,\r
++ IN UINT32 T1,\r
++ IN UINT32 T2,\r
++ IN UINT32 MessageType\r
+ )\r
+ {\r
+- UINT8 *AddrOpt;\r
+- UINT16 *Len;\r
+- UINTN Index;\r
++ UINT8 *AddrOpt;\r
++ UINT16 *Len;\r
++ UINTN Index;\r
++ UINT32 BytesNeeded;\r
++ UINT32 Length;\r
++ EFI_STATUS Status;\r
+ \r
+ //\r
+ // The format of IA_NA and IA_TA option:\r
+@@ -733,32 +859,74 @@ Dhcp6AppendIaOption (
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ //\r
+ \r
++ //\r
++ // Verify the arguments are valid\r
++ //\r
++ if (Packet == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if (Ia == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ //\r
++ // Verify the PacketCursor is within the packet\r
++ //\r
++ if ( (*PacketCursor < Packet->Dhcp6.Option)\r
++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER))))\r
++ {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN;\r
++ BytesNeeded += sizeof (Ia->Descriptor.IaId);\r
++ //\r
++ // + N for the IA_NA-options/IA_TA-options\r
++ // Dhcp6AppendIaAddrOption will need to check the length for each address\r
++ //\r
++ if (Ia->Descriptor.Type == Dhcp6OptIana) {\r
++ BytesNeeded += sizeof (T1) + sizeof (T2);\r
++ }\r
++\r
++ //\r
++ // Space remaining in the packet\r
++ //\r
++ Length = (UINT16)(Packet->Size - Packet->Length);\r
++ if (Length < BytesNeeded) {\r
++ return EFI_BUFFER_TOO_SMALL;\r
++ }\r
++\r
+ //\r
+ // Fill the value of Ia option type\r
+ //\r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Ia->Descriptor.Type));\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Ia->Descriptor.Type));\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE;\r
+ \r
+ //\r
+ // Fill the len of Ia option later, keep the pointer first\r
+ //\r
+- Len = (UINT16 *)Buf;\r
+- Buf += 2;\r
++ Len = (UINT16 *)*PacketCursor;\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN;\r
+ \r
+ //\r
+ // Fill the value of iaid\r
+ //\r
+- WriteUnaligned32 ((UINT32 *)Buf, HTONL (Ia->Descriptor.IaId));\r
+- Buf += 4;\r
++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (Ia->Descriptor.IaId));\r
++ *PacketCursor += sizeof (Ia->Descriptor.IaId);\r
+ \r
+ //\r
+ // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified.\r
+ //\r
+ if (Ia->Descriptor.Type == Dhcp6OptIana) {\r
+- WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r
+- Buf += 4;\r
+- WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r
+- Buf += 4;\r
++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T1 != 0) ? T1 : 0xffffffff));\r
++ *PacketCursor += sizeof (T1);\r
++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T2 != 0) ? T2 : 0xffffffff));\r
++ *PacketCursor += sizeof (T2);\r
+ }\r
+ \r
+ //\r
+@@ -766,35 +934,51 @@ Dhcp6AppendIaOption (
+ //\r
+ for (Index = 0; Index < Ia->IaAddressCount; Index++) {\r
+ AddrOpt = (UINT8 *)Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS);\r
+- Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType);\r
++ Status = Dhcp6AppendIaAddrOption (Packet, PacketCursor, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType);\r
++ if (EFI_ERROR (Status)) {\r
++ return Status;\r
++ }\r
+ }\r
+ \r
+ //\r
+ // Fill the value of Ia option length\r
+ //\r
+- *Len = HTONS ((UINT16)(Buf - (UINT8 *)Len - 2));\r
++ *Len = HTONS ((UINT16)(*PacketCursor - (UINT8 *)Len - 2));\r
+ \r
+- return Buf;\r
++ //\r
++ // Update the packet length\r
++ //\r
++ Packet->Length += BytesNeeded;\r
++\r
++ return EFI_SUCCESS;\r
+ }\r
+ \r
+ /**\r
+ Append the appointed Elapsed time option to Buf, and move Buf to the end.\r
+ \r
+- @param[in, out] Buf The pointer to the position to append.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
+ @param[in] Instance The pointer to the Dhcp6 instance.\r
+ @param[out] Elapsed The pointer to the elapsed time value in\r
+- the generated packet.\r
++ the generated packet.\r
+ \r
+- @return Buf The position to append the next Ia option.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ \r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendETOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN DHCP6_INSTANCE *Instance,\r
+- OUT UINT16 **Elapsed\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN DHCP6_INSTANCE *Instance,\r
++ OUT UINT16 **Elapsed\r
+ )\r
+ {\r
++ UINT32 BytesNeeded;\r
++ UINT32 Length;\r
++\r
+ //\r
+ // The format of elapsed time option:\r
+ //\r
+@@ -806,27 +990,70 @@ Dhcp6AppendETOption (
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ //\r
+ \r
++ //\r
++ // Verify the arguments are valid\r
++ //\r
++ if (Packet == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if (Instance == NULL) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ if ((Elapsed == NULL)) {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ //\r
++ // Verify the PacketCursor is within the packet\r
++ //\r
++ if ( (*PacketCursor < Packet->Dhcp6.Option)\r
++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER))))\r
++ {\r
++ return EFI_INVALID_PARAMETER;\r
++ }\r
++\r
++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN;\r
++ //\r
++ // + 2 for elapsed-time\r
++ //\r
++ BytesNeeded += sizeof (UINT16);\r
++ //\r
++ // Space remaining in the packet\r
++ //\r
++ Length = Packet->Size - Packet->Length;\r
++ if (Length < BytesNeeded) {\r
++ return EFI_BUFFER_TOO_SMALL;\r
++ }\r
++\r
+ //\r
+ // Fill the value of elapsed-time option type.\r
+ //\r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptElapsedTime));\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptElapsedTime));\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE;\r
+ \r
+ //\r
+ // Fill the len of elapsed-time option, which is fixed.\r
+ //\r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (2));\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (2));\r
++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN;\r
+ \r
+ //\r
+ // Fill in elapsed time value with 0 value for now. The actual value is\r
+ // filled in later just before the packet is transmitted.\r
+ //\r
+- WriteUnaligned16 ((UINT16 *)Buf, HTONS (0));\r
+- *Elapsed = (UINT16 *)Buf;\r
+- Buf += 2;\r
++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (0));\r
++ *Elapsed = (UINT16 *)*PacketCursor;\r
++ *PacketCursor += sizeof (UINT16);\r
++\r
++ Packet->Length += BytesNeeded;\r
+ \r
+- return Buf;\r
++ return EFI_SUCCESS;\r
+ }\r
+ \r
+ /**\r
+@@ -852,13 +1079,13 @@ SetElapsedTime (
+ //\r
+ gRT->GetTime (&Time, NULL);\r
+ CurrentStamp = MultU64x32 (\r
+- ((((UINT32)(Time.Year - 2000) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second,\r
+- 100\r
+- ) +\r
++ ((((UINT32)(Time.Year - 2000) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second,\r
++ 100\r
++ ) +\r
+ DivU64x32 (\r
+- Time.Nanosecond,\r
+- 10000000\r
+- );\r
++ Time.Nanosecond,\r
++ 10000000\r
++ );\r
+ \r
+ //\r
+ // Sentinel value of 0 means that this is the first DHCP packet that we are\r
+@@ -1290,11 +1517,11 @@ Dhcp6GetMappingTimeOut (
+ \r
+ DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);\r
+ Status = Ip6Cfg->GetData (\r
+- Ip6Cfg,\r
+- Ip6ConfigDataTypeDupAddrDetectTransmits,\r
+- &DataSize,\r
+- &DadXmits\r
+- );\r
++ Ip6Cfg,\r
++ Ip6ConfigDataTypeDupAddrDetectTransmits,\r
++ &DataSize,\r
++ &DadXmits\r
++ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h
+index 046454ff4a..06947f6c1f 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h
+@@ -160,69 +160,85 @@ Dhcp6OnTransmitted (
+ );\r
+ \r
+ /**\r
+- Append the appointed option to the buf, and move the buf to the end.\r
+-\r
+- @param[in, out] Buf The pointer to buffer.\r
+- @param[in] OptType The option type.\r
+- @param[in] OptLen The length of option content.s\r
+- @param[in] Data The pointer to the option content.\r
+-\r
+- @return Buf The position to append the next option.\r
+-\r
++ Append the option to Buf, update the length of packet, and move Buf to the end.\r
++\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ will be updated.\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
++ @param[in] OptType The option type.\r
++ @param[in] OptLen The length of option contents.\r
++ @param[in] Data The pointer to the option content.\r
++\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN UINT16 OptType,\r
+- IN UINT16 OptLen,\r
+- IN UINT8 *Data\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN UINT16 OptType,\r
++ IN UINT16 OptLen,\r
++ IN UINT8 *Data\r
+ );\r
+ \r
+ /**\r
+- Append the Ia option to Buf, and move Buf to the end.\r
+-\r
+- @param[in, out] Buf The pointer to the position to append.\r
++ Append the appointed Ia option to Buf, update the Ia option length, and move Buf\r
++ to the end of the option.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ will be updated.\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
+ @param[in] Ia The pointer to the Ia.\r
+ @param[in] T1 The time of T1.\r
+ @param[in] T2 The time of T2.\r
+ @param[in] MessageType Message type of DHCP6 package.\r
+ \r
+- @return Buf The position to append the next Ia option.\r
+-\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendIaOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN EFI_DHCP6_IA *Ia,\r
+- IN UINT32 T1,\r
+- IN UINT32 T2,\r
+- IN UINT32 MessageType\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN EFI_DHCP6_IA *Ia,\r
++ IN UINT32 T1,\r
++ IN UINT32 T2,\r
++ IN UINT32 MessageType\r
+ );\r
+ \r
+ /**\r
+ Append the appointed Elapsed time option to Buf, and move Buf to the end.\r
+ \r
+- @param[in, out] Buf The pointer to the position to append.\r
++ @param[in, out] Packet A pointer to the packet, on success Packet->Length\r
++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor\r
++ will be moved to the end of the option.\r
+ @param[in] Instance The pointer to the Dhcp6 instance.\r
+ @param[out] Elapsed The pointer to the elapsed time value in\r
+ the generated packet.\r
+ \r
+- @return Buf The position to append the next Ia option.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ \r
+ **/\r
+-UINT8 *\r
++EFI_STATUS\r
+ Dhcp6AppendETOption (\r
+- IN OUT UINT8 *Buf,\r
+- IN DHCP6_INSTANCE *Instance,\r
+- OUT UINT16 **Elapsed\r
++ IN OUT EFI_DHCP6_PACKET *Packet,\r
++ IN OUT UINT8 **PacketCursor,\r
++ IN DHCP6_INSTANCE *Instance,\r
++ OUT UINT16 **Elapsed\r
+ );\r
+ \r
+ /**\r
+ Set the elapsed time based on the given instance and the pointer to the\r
+ elapsed time option.\r
+ \r
+- @param[in] Elapsed The pointer to the position to append.\r
+- @param[in] Instance The pointer to the Dhcp6 instance.\r
++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid\r
++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option.\r
++ @retval EFI_SUCCESS The option is appended successfully.\r
+ **/\r
+ VOID\r
+ SetElapsedTime (\r
+--
+2.41.0
+
+
+From 1bd40aba86eecc8acc07547e6d14e563590b1074 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 11:26:04 -0800
+Subject: [PATCH 02/12] SECURITY PATCH TCBZ4535 - CVE-2023-45230 - Host Based
+ Unit Test
+
+---
+ .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 27 +
+ .../GoogleTest/Dhcp6DxeGoogleTest.inf | 44 ++
+ .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 478 ++++++++++++++++++
+ NetworkPkg/NetworkPkg.ci.yaml | 3 +
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 102 ++++
+ 5 files changed, 654 insertions(+)
+ create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
+ create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
+ create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
+ create mode 100644 NetworkPkg/Test/NetworkPkgHostTest.dsc
+
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
+new file mode 100644
+index 0000000000..b1fe72e195
+--- /dev/null
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
+@@ -0,0 +1,27 @@
++/** @file\r
++ Acts as the main entry point for the tests for the Dhcp6Dxe module.\r
++\r
++ Copyright (c) Microsoft Corporation\r
++ SPDX-License-Identifier: BSD-2-Clause-Patent\r
++**/\r
++#include <gtest/gtest.h>\r
++\r
++////////////////////////////////////////////////////////////////////////////////\r
++// Add test files here\r
++// Google Test will only pick up the tests from the files that are included\r
++// here.\r
++////////////////////////////////////////////////////////////////////////////////\r
++#include "Dhcp6IoGoogleTest.cpp"\r
++\r
++////////////////////////////////////////////////////////////////////////////////\r
++// Run the tests\r
++////////////////////////////////////////////////////////////////////////////////\r
++int\r
++main (\r
++ int argc,\r
++ char *argv[]\r
++ )\r
++{\r
++ testing::InitGoogleTest (&argc, argv);\r
++ return RUN_ALL_TESTS ();\r
++}\r
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
+new file mode 100644
+index 0000000000..c7ec42b322
+--- /dev/null
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
+@@ -0,0 +1,44 @@
++## @file\r
++# Unit test suite for the Dhcp6Dxe using Google Test\r
++#\r
++# Copyright (c) Microsoft Corporation.<BR>\r
++# SPDX-License-Identifier: BSD-2-Clause-Patent\r
++##\r
++[Defines]\r
++ INF_VERSION = 0x00010017\r
++ BASE_NAME = Dhcp6DxeGoogleTest\r
++ FILE_GUID = 1D2A4C65-38C8-4C2F-BB60-B5FA49625AA9\r
++ VERSION_STRING = 1.0\r
++ MODULE_TYPE = HOST_APPLICATION\r
++#\r
++# The following information is for reference only and not required by the build tools.\r
++#\r
++# VALID_ARCHITECTURES = IA32 X64 AARCH64\r
++#\r
++[Sources]\r
++ Dhcp6DxeGoogleTest.cpp\r
++ Dhcp6IoGoogleTest.cpp\r
++ ../Dhcp6Io.c\r
++ ../Dhcp6Utility.c\r
++\r
++\r
++[Packages]\r
++ MdePkg/MdePkg.dec\r
++ MdeModulePkg/MdeModulePkg.dec\r
++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
++ NetworkPkg/NetworkPkg.dec\r
++\r
++[LibraryClasses]\r
++ GoogleTestLib\r
++ DebugLib\r
++ NetLib\r
++ PcdLib\r
++\r
++[Protocols]\r
++ gEfiDhcp6ServiceBindingProtocolGuid\r
++\r
++[Pcd]\r
++ gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType\r
++\r
++[Guids]\r
++ gZeroGuid
+\ No newline at end of file
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
+new file mode 100644
+index 0000000000..dad6a42b12
+--- /dev/null
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
+@@ -0,0 +1,478 @@
++/** @file\r
++ Tests for Dhcp6Io.c.\r
++\r
++ Copyright (c) Microsoft Corporation\r
++ SPDX-License-Identifier: BSD-2-Clause-Patent\r
++**/\r
++#include <gtest/gtest.h>\r
++\r
++extern "C" {\r
++ #include <Uefi.h>\r
++ #include <Library/BaseLib.h>\r
++ #include <Library/DebugLib.h>\r
++ #include <Library/BaseMemoryLib.h>\r
++ #include "../Dhcp6Impl.h"\r
++ #include "../Dhcp6Utility.h"\r
++}\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Defines\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++#define DHCP6_PACKET_MAX_LEN 1500\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++////////////////////////////////////////////////////////////////////////\r
++// Symbol Definitions\r
++// These functions are not directly under test - but required to compile\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++// This definition is used by this test but is also required to compile\r
++// by Dhcp6Io.c\r
++EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {\r
++ { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 }\r
++};\r
++\r
++EFI_STATUS\r
++EFIAPI\r
++UdpIoSendDatagram (\r
++ IN UDP_IO *UdpIo,\r
++ IN NET_BUF *Packet,\r
++ IN UDP_END_POINT *EndPoint OPTIONAL,\r
++ IN EFI_IP_ADDRESS *Gateway OPTIONAL,\r
++ IN UDP_IO_CALLBACK CallBack,\r
++ IN VOID *Context\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++EFI_STATUS\r
++EFIAPI\r
++UdpIoRecvDatagram (\r
++ IN UDP_IO *UdpIo,\r
++ IN UDP_IO_CALLBACK CallBack,\r
++ IN VOID *Context,\r
++ IN UINT32 HeadLen\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Dhcp6AppendOptionTest Tests\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++class Dhcp6AppendOptionTest : public ::testing::Test {\r
++public:\r
++ UINT8 *Buffer = NULL;\r
++ EFI_DHCP6_PACKET *Packet;\r
++\r
++protected:\r
++ // Add any setup code if needed\r
++ virtual void\r
++ SetUp (\r
++ )\r
++ {\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++ }\r
++\r
++ // Add any cleanup code if needed\r
++ virtual void\r
++ TearDown (\r
++ )\r
++ {\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
++ }\r
++ }\r
++};\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that is too small by a duid that is too large\r
++TEST_F (Dhcp6AppendOptionTest, InvalidDataExpectBufferTooSmall) {\r
++ UINT8 *Cursor;\r
++ EFI_DHCP6_DUID *UntrustedDuid;\r
++ EFI_STATUS Status;\r
++\r
++ UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID));\r
++ ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL);\r
++\r
++ UntrustedDuid->Length = NTOHS (0xFFFF);\r
++\r
++ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Status = Dhcp6AppendOption (\r
++ Dhcp6AppendOptionTest::Packet,\r
++ &Cursor,\r
++ HTONS (Dhcp6OptServerId),\r
++ UntrustedDuid->Length,\r
++ UntrustedDuid->Duid\r
++ );\r
++\r
++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
++}\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that is large enough\r
++TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) {\r
++ UINT8 *Cursor;\r
++ EFI_DHCP6_DUID *UntrustedDuid;\r
++ EFI_STATUS Status;\r
++ UINTN OriginalLength;\r
++\r
++ UINT8 Duid[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };\r
++\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++ OriginalLength = Packet->Length;\r
++\r
++ UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID));\r
++ ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL);\r
++\r
++ UntrustedDuid->Length = NTOHS (sizeof (Duid));\r
++ CopyMem (UntrustedDuid->Duid, Duid, sizeof (Duid));\r
++\r
++ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Status = Dhcp6AppendOption (\r
++ Dhcp6AppendOptionTest::Packet,\r
++ &Cursor,\r
++ HTONS (Dhcp6OptServerId),\r
++ UntrustedDuid->Length,\r
++ UntrustedDuid->Duid\r
++ );\r
++\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ // verify that the pointer to cursor moved by the expected amount\r
++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendOptionTest::Packet->Dhcp6.Option + sizeof (Duid) + 4);\r
++\r
++ // verify that the length of the packet is now the expected amount\r
++ ASSERT_EQ (Dhcp6AppendOptionTest::Packet->Length, OriginalLength + sizeof (Duid) + 4);\r
++}\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Dhcp6AppendETOption Tests\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++class Dhcp6AppendETOptionTest : public ::testing::Test {\r
++public:\r
++ UINT8 *Buffer = NULL;\r
++ EFI_DHCP6_PACKET *Packet;\r
++\r
++protected:\r
++ // Add any setup code if needed\r
++ virtual void\r
++ SetUp (\r
++ )\r
++ {\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++ }\r
++\r
++ // Add any cleanup code if needed\r
++ virtual void\r
++ TearDown (\r
++ )\r
++ {\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
++ }\r
++ }\r
++};\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that is too small by a duid that is too large\r
++TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++ DHCP6_INSTANCE Instance;\r
++ UINT16 ElapsedTimeVal;\r
++ UINT16 *ElapsedTime;\r
++\r
++ Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option;\r
++ ElapsedTime = &ElapsedTimeVal;\r
++\r
++ Packet->Length = Packet->Size - 2;\r
++\r
++ Status = Dhcp6AppendETOption (\r
++ Dhcp6AppendETOptionTest::Packet,\r
++ &Cursor,\r
++ &Instance, // Instance is not used in this function\r
++ &ElapsedTime\r
++ );\r
++\r
++ // verify that we error out because the packet is too small for the option header\r
++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
++\r
++ // reset the length\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++}\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that is large enough\r
++TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++ DHCP6_INSTANCE Instance;\r
++ UINT16 ElapsedTimeVal;\r
++ UINT16 *ElapsedTime;\r
++ UINTN ExpectedSize;\r
++ UINTN OriginalLength;\r
++\r
++ Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option;\r
++ ElapsedTime = &ElapsedTimeVal;\r
++ ExpectedSize = 6;\r
++ OriginalLength = Packet->Length;\r
++\r
++ Status = Dhcp6AppendETOption (\r
++ Dhcp6AppendETOptionTest::Packet,\r
++ &Cursor,\r
++ &Instance, // Instance is not used in this function\r
++ &ElapsedTime\r
++ );\r
++\r
++ // verify that the status is EFI_SUCCESS\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ // verify that the pointer to cursor moved by the expected amount\r
++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendETOptionTest::Packet->Dhcp6.Option + ExpectedSize);\r
++\r
++ // verify that the length of the packet is now the expected amount\r
++ ASSERT_EQ (Dhcp6AppendETOptionTest::Packet->Length, OriginalLength + ExpectedSize);\r
++}\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Dhcp6AppendIaOption Tests\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++class Dhcp6AppendIaOptionTest : public ::testing::Test {\r
++public:\r
++ UINT8 *Buffer = NULL;\r
++ EFI_DHCP6_PACKET *Packet;\r
++ EFI_DHCP6_IA *Ia;\r
++\r
++protected:\r
++ // Add any setup code if needed\r
++ virtual void\r
++ SetUp (\r
++ )\r
++ {\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++\r
++ Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2);\r
++ ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL);\r
++\r
++ CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
++ CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
++\r
++ Ia->IaAddressCount = 2;\r
++ }\r
++\r
++ // Add any cleanup code if needed\r
++ virtual void\r
++ TearDown (\r
++ )\r
++ {\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
++ }\r
++\r
++ if (Ia != NULL) {\r
++ FreePool (Ia);\r
++ }\r
++ }\r
++};\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that doesn't have enough space\r
++// for the option header\r
++TEST_F (Dhcp6AppendIaOptionTest, IaNaInvalidDataExpectBufferTooSmall) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++\r
++ Packet->Length = Packet->Size - 2;\r
++\r
++ Ia->Descriptor.Type = Dhcp6OptIana;\r
++ Ia->Descriptor.IaId = 0x12345678;\r
++\r
++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0x12345678,\r
++ 0x11111111,\r
++ Dhcp6OptIana\r
++ );\r
++\r
++ // verify that we error out because the packet is too small for the option header\r
++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
++\r
++ // reset the length\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++}\r
++\r
++// Test Description:\r
++// Attempt to append an option to a packet that doesn't have enough space\r
++// for the option header\r
++TEST_F (Dhcp6AppendIaOptionTest, IaTaInvalidDataExpectBufferTooSmall) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++\r
++ // Use up nearly all the space in the packet\r
++ Packet->Length = Packet->Size - 2;\r
++\r
++ Ia->Descriptor.Type = Dhcp6OptIata;\r
++ Ia->Descriptor.IaId = 0x12345678;\r
++\r
++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0,\r
++ 0,\r
++ Dhcp6OptIata\r
++ );\r
++\r
++ // verify that we error out because the packet is too small for the option header\r
++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
++\r
++ // reset the length\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++}\r
++\r
++TEST_F (Dhcp6AppendIaOptionTest, IaNaValidDataExpectSuccess) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++ UINTN ExpectedSize;\r
++ UINTN OriginalLength;\r
++\r
++ //\r
++ // 2 bytes for the option header type\r
++ //\r
++ ExpectedSize = 2;\r
++ //\r
++ // 2 bytes for the option header length\r
++ //\r
++ ExpectedSize += 2;\r
++ //\r
++ // 4 bytes for the IAID\r
++ //\r
++ ExpectedSize += 4;\r
++ //\r
++ // + 4 bytes for the T1\r
++ //\r
++ ExpectedSize += 4;\r
++ //\r
++ // + 4 bytes for the T2\r
++ //\r
++ ExpectedSize += 4;\r
++ //\r
++ // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2;\r
++ // + 2 bytes for the option header type\r
++ // + 2 bytes for the option header length\r
++ // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address\r
++ //\r
++ ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2;\r
++\r
++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++ OriginalLength = Packet->Length;\r
++\r
++ Ia->Descriptor.Type = Dhcp6OptIana;\r
++ Ia->Descriptor.IaId = 0x12345678;\r
++\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0x12345678,\r
++ 0x12345678,\r
++ Dhcp6OptIana\r
++ );\r
++\r
++ // verify that the pointer to cursor moved by the expected amount\r
++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize);\r
++\r
++ // verify that the length of the packet is now the expected amount\r
++ ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize);\r
++\r
++ // verify that the status is EFI_SUCCESS\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++}\r
++\r
++TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) {\r
++ UINT8 *Cursor;\r
++ EFI_STATUS Status;\r
++ UINTN ExpectedSize;\r
++ UINTN OriginalLength;\r
++\r
++ //\r
++ // 2 bytes for the option header type\r
++ //\r
++ ExpectedSize = 2;\r
++ //\r
++ // 2 bytes for the option header length\r
++ //\r
++ ExpectedSize += 2;\r
++ //\r
++ // 4 bytes for the IAID\r
++ //\r
++ ExpectedSize += 4;\r
++ //\r
++ // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2;\r
++ // + 2 bytes for the option header type\r
++ // + 2 bytes for the option header length\r
++ // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address\r
++ //\r
++ ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2;\r
++\r
++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++ OriginalLength = Packet->Length;\r
++\r
++ Ia->Descriptor.Type = Dhcp6OptIata;\r
++ Ia->Descriptor.IaId = 0x12345678;\r
++\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0,\r
++ 0,\r
++ Dhcp6OptIata\r
++ );\r
++\r
++ // verify that the pointer to cursor moved by the expected amount\r
++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize);\r
++\r
++ // verify that the length of the packet is now the expected amount\r
++ ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize);\r
++\r
++ // verify that the status is EFI_SUCCESS\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++}\r
+diff --git a/NetworkPkg/NetworkPkg.ci.yaml b/NetworkPkg/NetworkPkg.ci.yaml
+index 07dc7abd69..e82e0c6256 100644
+--- a/NetworkPkg/NetworkPkg.ci.yaml
++++ b/NetworkPkg/NetworkPkg.ci.yaml
+@@ -24,6 +24,9 @@
+ "CompilerPlugin": {\r
+ "DscPath": "NetworkPkg.dsc"\r
+ },\r
++ "HostUnitTestCompilerPlugin": {\r
++ "DscPath": "Test/NetworkPkgHostTest.dsc"\r
++ },\r
+ "CharEncodingCheck": {\r
+ "IgnoreFiles": []\r
+ },\r
+diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+new file mode 100644
+index 0000000000..5befdf7688
+--- /dev/null
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -0,0 +1,102 @@
++## @file\r
++# NetworkPkgHostTest DSC file used to build host-based unit tests.\r
++#\r
++# Copyright (c) Microsoft Corporation.<BR>\r
++# SPDX-License-Identifier: BSD-2-Clause-Patent\r
++#\r
++##\r
++[Defines]\r
++ PLATFORM_NAME = NetworkPkgHostTest\r
++ PLATFORM_GUID = 3b68324e-fc07-4d49-9520-9347ede65879\r
++ PLATFORM_VERSION = 0.1\r
++ DSC_SPECIFICATION = 0x00010005\r
++ OUTPUT_DIRECTORY = Build/NetworkPkg/HostTest\r
++ SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64\r
++ BUILD_TARGETS = NOOPT\r
++ SKUID_IDENTIFIER = DEFAULT\r
++ \r
++!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc\r
++[Packages]\r
++ MdePkg/MdePkg.dec\r
++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
++\r
++[Components]\r
++ #\r
++ # Build HOST_APPLICATION that tests NetworkPkg\r
++ #\r
++ NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf\r
++\r
++# Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests.\r
++[LibraryClasses]\r
++ NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf\r
++ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
++ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
++ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
++ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
++ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf\r
++ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
++ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
++ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
++ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
++ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf\r
++ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
++ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
++ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
++ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf\r
++ UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf\r
++ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
++ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
++ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf\r
++ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
++ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
++ SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf\r
++ RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf\r
++ VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf\r
++!ifdef CONTINUOUS_INTEGRATION\r
++ BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf\r
++ TlsLib|CryptoPkg/Library/TlsLibNull/TlsLibNull.inf\r
++!else\r
++ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
++ OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf\r
++ TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf\r
++!endif\r
++ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf\r
++ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf\r
++ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
++ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf\r
++ IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\r
++\r
++!if $(TOOL_CHAIN_TAG) == VS2019 or $(TOOL_CHAIN_TAG) == VS2022\r
++[LibraryClasses.X64]\r
++ # Provide StackCookie support lib so that we can link to /GS exports for VS builds\r
++ RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf\r
++ NULL|MdePkg/Library/BaseBinSecurityLibRng/BaseBinSecurityLibRng.inf\r
++!endif\r
++\r
++[LibraryClasses.common.UEFI_DRIVER]\r
++ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
++ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf\r
++ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf\r
++[LibraryClasses.common.UEFI_APPLICATION]\r
++ DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf\r
++ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf\r
++[LibraryClasses.ARM, LibraryClasses.AARCH64]\r
++ #\r
++ # It is not possible to prevent ARM compiler calls to generic intrinsic functions.\r
++ # This library provides the instrinsic functions generated by a given compiler.\r
++ # [LibraryClasses.ARM] and NULL mean link this library into all ARM images.\r
++ #\r
++ # MU_CHANGE Start\r
++!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019\r
++ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf\r
++!endif\r
++ # MU_CHANGE End\r
++ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf\r
++[LibraryClasses.ARM]\r
++ RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf\r
++[LibraryClasses.RISCV64]\r
++ RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf\r
++ \r
++[PcdsFixedAtBuild]\r
++ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2\r
++ gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType|0x4
+\ No newline at end of file
+--
+2.41.0
+
+
+From 9613e15be77676e119291f28ae46cb13bf37f235 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 11:26:47 -0800
+Subject: [PATCH 03/12] SECURITY PATCH TCBZ4534 - CVE-2023-45229 - Patch
+
+---
+ NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 134 ++++++++++++++++++---
+ NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 202 ++++++++++++++++++++++----------
+ 2 files changed, 257 insertions(+), 79 deletions(-)
+
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
+index b552331767..5247b324ac 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
+@@ -45,6 +45,20 @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE;
+ #define DHCP6_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'S')\r
+ #define DHCP6_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', '6', 'I')\r
+ \r
++#define DHCP6_PACKET_ALL 0\r
++#define DHCP6_PACKET_STATEFUL 1\r
++#define DHCP6_PACKET_STATELESS 2\r
++\r
++#define DHCP6_BASE_PACKET_SIZE 1024\r
++\r
++#define DHCP6_PORT_CLIENT 546\r
++#define DHCP6_PORT_SERVER 547\r
++\r
++#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20)\r
++\r
++#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE)\r
++#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE)\r
++\r
+ //\r
+ // For more information on DHCP options see RFC 8415, Section 21.1\r
+ // \r
+@@ -59,8 +73,8 @@ typedef struct _DHCP6_INSTANCE DHCP6_INSTANCE;
+ // | (option-len octets) |\r
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+ //\r
+-#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16))\r
+-#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16))\r
++#define DHCP6_SIZE_OF_OPT_CODE (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode))\r
++#define DHCP6_SIZE_OF_OPT_LEN (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen))\r
+ \r
+ // Combined size of Code and Length\r
+ #define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \\r
+@@ -72,31 +86,121 @@ STATIC_ASSERT (
+ );\r
+ \r
+ // Offset to the length is just past the code\r
+-#define DHCP6_OPT_LEN_OFFSET(a) (a + DHCP6_SIZE_OF_OPT_CODE)\r
++#define DHCP6_OFFSET_OF_OPT_LEN(a) (a + DHCP6_SIZE_OF_OPT_CODE)\r
+ STATIC_ASSERT (\r
+- DHCP6_OPT_LEN_OFFSET (0) == 2,\r
++ DHCP6_OFFSET_OF_OPT_LEN (0) == 2,\r
+ "Offset of length is + 2 past start of option"\r
+ );\r
+ \r
+-#define DHCP6_OPT_DATA_OFFSET(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)\r
++#define DHCP6_OFFSET_OF_OPT_DATA(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)\r
+ STATIC_ASSERT (\r
+- DHCP6_OPT_DATA_OFFSET(0) == 4,\r
++ DHCP6_OFFSET_OF_OPT_DATA(0) == 4,\r
+ "Offset to option data should be +4 from start of option"\r
+ );\r
++//\r
++// Identity Association options (both NA (Non-Temporary) and TA (Temporary Association))\r
++// are defined in RFC 8415 and are a deriviation of a TLV stucture\r
++// For more information on IA_NA see Section 21.4\r
++// For more information on IA_TA see Section 21.5\r
++//\r
++//\r
++// The format of IA_NA and IA_TA option:\r
++//\r
++// 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\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | OPTION_IA_NA | option-len |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | IAID (4 octets) |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | T1 (only for IA_NA) |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | T2 (only for IA_NA) |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | |\r
++// . IA_NA-options/IA_TA-options .\r
++// . .\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++//\r
++#define DHCP6_SIZE_OF_IAID (sizeof(UINT32))\r
++#define DHCP6_SIZE_OF_TIME_INTERVAL (sizeof(UINT32))\r
+ \r
+-#define DHCP6_PACKET_ALL 0\r
+-#define DHCP6_PACKET_STATEFUL 1\r
+-#define DHCP6_PACKET_STATELESS 2\r
++// Combined size of IAID, T1, and T2\r
++#define DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 (DHCP6_SIZE_OF_IAID + \\r
++ DHCP6_SIZE_OF_TIME_INTERVAL + \\r
++ DHCP6_SIZE_OF_TIME_INTERVAL)\r
++STATIC_ASSERT (\r
++ DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 == 12,\r
++ "Combined size of IAID, T1, T2 must be 12 per RFC 8415"\r
++ );\r
+ \r
+-#define DHCP6_BASE_PACKET_SIZE 1024\r
++// This is the size of IA_TA without options\r
++#define DHCP6_MIN_SIZE_OF_IA_TA (DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \\r
++ DHCP6_SIZE_OF_IAID)\r
++STATIC_ASSERT (\r
++ DHCP6_MIN_SIZE_OF_IA_TA == 8,\r
++ "Minimum combined size of IA_TA per RFC 8415"\r
++ );\r
+ \r
+-#define DHCP6_PORT_CLIENT 546\r
+-#define DHCP6_PORT_SERVER 547\r
++// Offset to a IA_TA inner option\r
++#define DHCP6_OFFSET_OF_IA_TA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_TA)\r
++STATIC_ASSERT (\r
++ DHCP6_OFFSET_OF_IA_TA_INNER_OPT (0) == 8,\r
++ "Offset of IA_TA Inner option is + 8 past start of option"\r
++ );\r
+ \r
+-#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20)\r
++// This is the size of IA_NA without options (16)\r
++#define DHCP6_MIN_SIZE_OF_IA_NA DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \\r
++ DHCP6_SIZE_OF_COMBINED_IAID_T1_T2\r
++STATIC_ASSERT (\r
++ DHCP6_MIN_SIZE_OF_IA_NA == 16,\r
++ "Minimum combined size of IA_TA per RFC 8415"\r
++ );\r
+ \r
+-#define DHCP6_INSTANCE_FROM_THIS(Instance) CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE)\r
+-#define DHCP6_SERVICE_FROM_THIS(Service) CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE)\r
++#define DHCP6_OFFSET_OF_IA_NA_INNER_OPT(a) (a + DHCP6_MIN_SIZE_OF_IA_NA)\r
++STATIC_ASSERT (\r
++ DHCP6_OFFSET_OF_IA_NA_INNER_OPT (0) == 16,\r
++ "Offset of IA_NA Inner option is + 16 past start of option"\r
++ );\r
++\r
++#define DHCP6_OFFSET_OF_IA_NA_T1(a) (a + \\r
++ DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \\r
++ DHCP6_SIZE_OF_IAID)\r
++STATIC_ASSERT (\r
++ DHCP6_OFFSET_OF_IA_NA_T1 (0) == 8,\r
++ "Offset of IA_NA Inner option is + 8 past start of option"\r
++ );\r
++\r
++#define DHCP6_OFFSET_OF_IA_NA_T2(a) (a + \\r
++ DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN +\\r
++ DHCP6_SIZE_OF_IAID + \\r
++ DHCP6_SIZE_OF_TIME_INTERVAL)\r
++STATIC_ASSERT (\r
++ DHCP6_OFFSET_OF_IA_NA_T2 (0) == 12,\r
++ "Offset of IA_NA Inner option is + 12 past start of option"\r
++ );\r
++\r
++//\r
++// For more information see RFC 8415 Section 21.13\r
++//\r
++// The format of the Status Code Option:\r
++//\r
++// 0 1 2 3\r
++// 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\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | OPTION_STATUS_CODE | option-len |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | status-code | |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |\r
++// . .\r
++// . status-message .\r
++// . .\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++//\r
++#define DHCP6_OFFSET_OF_STATUS_CODE(a) (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)\r
++STATIC_ASSERT (\r
++ DHCP6_OFFSET_OF_STATUS_CODE (0) == 4,\r
++ "Offset of status is + 4 past start of option"\r
++ );\r
+ \r
+ extern EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress;\r
+ extern EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate;\r
+diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
+index 1401910950..f96b4c7962 100644
+--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
+@@ -598,8 +598,9 @@ Dhcp6UpdateIaInfo (
+ // The inner options still start with 2 bytes option-code and 2 bytes option-len.\r
+ //\r
+ if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
+- T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 8)));\r
+- T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 12)));\r
++\r
++ T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T1(Option))));\r
++ T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T2(Option))));\r
+ //\r
+ // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,\r
+ // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes\r
+@@ -609,13 +610,14 @@ Dhcp6UpdateIaInfo (
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ \r
+- IaInnerOpt = Option + 16;\r
+- IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 12);\r
++ IaInnerOpt = DHCP6_OFFSET_OF_IA_NA_INNER_OPT(Option);\r
++ IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN(Option)))) - DHCP6_SIZE_OF_COMBINED_IAID_T1_T2);\r
+ } else {\r
+ T1 = 0;\r
+ T2 = 0;\r
+- IaInnerOpt = Option + 8;\r
+- IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 4);\r
++\r
++ IaInnerOpt = DHCP6_OFFSET_OF_IA_TA_INNER_OPT(Option);\r
++ IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN(Option)))) - DHCP6_SIZE_OF_IAID);\r
+ }\r
+ \r
+ //\r
+@@ -641,7 +643,7 @@ Dhcp6UpdateIaInfo (
+ Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);\r
+ \r
+ if (Option != NULL) {\r
+- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));\r
++ StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN(Option))));\r
+ if (StsCode != Dhcp6StsSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+@@ -661,6 +663,88 @@ Dhcp6UpdateIaInfo (
+ return Status;\r
+ }\r
+ \r
++/*\r
++ Seeks the Inner Options from a DHCP6 Option\r
++\r
++ @param[in] IaType The type of the IA option.\r
++ @param[in] Option The pointer to the DHCP6 Option.\r
++ @param[in] OptionLen The length of the DHCP6 Option.\r
++ @param[out] IaInnerOpt The pointer to the IA inner option.\r
++ @param[out] IaInnerLen The length of the IA inner option.\r
++\r
++ @retval EFI_SUCCESS Seek the inner option successfully.\r
++ @retval EFI_DEVICE_ERROR The OptionLen is invalid. On Error,\r
++ the pointers are not modified\r
++*/\r
++EFI_STATUS\r
++Dhcp6SeekInnerOptionSafe (\r
++ IN UINT16 IaType,\r
++ IN UINT8 *Option,\r
++ IN UINT32 OptionLen,\r
++ OUT UINT8 **IaInnerOpt,\r
++ OUT UINT16 *IaInnerLen\r
++ )\r
++{\r
++ \r
++ UINT16 IaInnerLenTmp;\r
++ UINT8 *IaInnerOptTmp;\r
++\r
++ if (Option == NULL) {\r
++ ASSERT (Option != NULL);\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ if (IaInnerOpt == NULL) {\r
++ ASSERT (IaInnerOpt != NULL);\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ if (IaInnerLen == NULL) {\r
++ ASSERT (IaInnerLen != NULL);\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ if (IaType == Dhcp6OptIana) {\r
++ // Verify we have a fully formed IA_NA\r
++ if (OptionLen < DHCP6_MIN_SIZE_OF_IA_NA) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++ \r
++ //\r
++ IaInnerOptTmp = DHCP6_OFFSET_OF_IA_NA_INNER_OPT(Option);\r
++\r
++ // Verify the IaInnerLen is valid.\r
++ IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)DHCP6_OFFSET_OF_OPT_LEN(Option)));\r
++ if (IaInnerLenTmp < DHCP6_SIZE_OF_COMBINED_IAID_T1_T2) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ IaInnerLenTmp -= DHCP6_SIZE_OF_COMBINED_IAID_T1_T2;\r
++ } else if (IaType == Dhcp6OptIata) {\r
++ // Verify the OptionLen is valid.\r
++ if (OptionLen < DHCP6_MIN_SIZE_OF_IA_TA) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ IaInnerOptTmp = DHCP6_OFFSET_OF_IA_TA_INNER_OPT(Option);\r
++\r
++ // Verify the IaInnerLen is valid.\r
++ IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN(Option))));\r
++ if (IaInnerLenTmp < DHCP6_SIZE_OF_IAID) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ IaInnerLenTmp -= DHCP6_SIZE_OF_IAID;\r
++ } else {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ *IaInnerOpt = IaInnerOptTmp;\r
++ *IaInnerLen = IaInnerLenTmp;\r
++\r
++ return EFI_SUCCESS;\r
++}\r
++\r
+ /**\r
+ Seek StatusCode Option in package. A Status Code option may appear in the\r
+ options field of a DHCP message and/or in the options field of another option.\r
+@@ -684,6 +768,12 @@ Dhcp6SeekStsOption (
+ UINT8 *IaInnerOpt;\r
+ UINT16 IaInnerLen;\r
+ UINT16 StsCode;\r
++ UINT32 OptionLen;\r
++\r
++ // OptionLen is the length of the Options excluding the DHCP header.\r
++ // Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last\r
++ // byte of the Option[] field.\r
++ OptionLen = Packet->Length - sizeof (Packet->Dhcp6.Header);\r
+ \r
+ //\r
+ // Seek StatusCode option directly in DHCP message body. That is, search in\r
+@@ -691,12 +781,12 @@ Dhcp6SeekStsOption (
+ //\r
+ *Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ OptionLen,\r
+ Dhcp6OptStatusCode\r
+ );\r
+ \r
+ if (*Option != NULL) {\r
+- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));\r
++ StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_STATUS_CODE(*Option))));\r
+ if (StsCode != Dhcp6StsSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+@@ -707,7 +797,7 @@ Dhcp6SeekStsOption (
+ //\r
+ *Option = Dhcp6SeekIaOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - sizeof (EFI_DHCP6_HEADER),\r
++ OptionLen,\r
+ &Instance->Config->IaDescriptor\r
+ );\r
+ if (*Option == NULL) {\r
+@@ -715,52 +805,35 @@ Dhcp6SeekStsOption (
+ }\r
+ \r
+ //\r
+- // The format of the IA_NA option is:\r
++ // Calculate the distance from Packet->Dhcp6.Option to the IA option.\r
+ //\r
+- // 0 1 2 3\r
+- // 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\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | OPTION_IA_NA | option-len |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | IAID (4 octets) |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | T1 |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | T2 |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | |\r
+- // . IA_NA-options .\r
+- // . .\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++ // Packet->Size and Packet->Length are both UINT32 type, and Packet->Size is\r
++ // the size of the whole packet, including the DHCP header, and Packet->Length\r
++ // is the length of the DHCP message body, excluding the DHCP header.\r
+ //\r
+- // The format of the IA_TA option is:\r
++ // (*Option - Packet->Dhcp6.Option) is the number of bytes from the start of\r
++ // DHCP6 option area to the start of the IA option.\r
+ //\r
+- // 0 1 2 3\r
+- // 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\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | OPTION_IA_TA | option-len |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | IAID (4 octets) |\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+- // | |\r
+- // . IA_TA-options .\r
+- // . .\r
+- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++ // Dhcp6SeekInnerOptionSafe() is searching starting from the start of the\r
++ // IA option to the end of the DHCP6 option area, thus subtract the space\r
++ // up until this option\r
+ //\r
++ OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option);\r
+ \r
+ //\r
+- // sizeof (option-code + option-len + IaId) = 8\r
+- // sizeof (option-code + option-len + IaId + T1) = 12\r
+- // sizeof (option-code + option-len + IaId + T1 + T2) = 16\r
++ // Seek the inner option\r
+ //\r
+- // The inner options still start with 2 bytes option-code and 2 bytes option-len.\r
+- //\r
+- if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {\r
+- IaInnerOpt = *Option + 16;\r
+- IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 12);\r
+- } else {\r
+- IaInnerOpt = *Option + 8;\r
+- IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 4);\r
++ if (EFI_ERROR (\r
++ Dhcp6SeekInnerOptionSafe (\r
++ Instance->Config->IaDescriptor.Type,\r
++ *Option,\r
++ OptionLen,\r
++ &IaInnerOpt,\r
++ &IaInnerLen\r
++ )\r
++ ))\r
++ {\r
++ return EFI_DEVICE_ERROR;\r
+ }\r
+ \r
+ //\r
+@@ -784,7 +857,7 @@ Dhcp6SeekStsOption (
+ //\r
+ *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);\r
+ if (*Option != NULL) {\r
+- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));\r
++ StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE(*Option)))));\r
+ if (StsCode != Dhcp6StsSuccess) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+@@ -1105,7 +1178,7 @@ Dhcp6SendRequestMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Instance->AdSelect->Dhcp6.Option,\r
+- Instance->AdSelect->Length - 4,\r
++ Instance->AdSelect->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerId\r
+ );\r
+ if (Option == NULL) {\r
+@@ -1289,7 +1362,7 @@ Dhcp6SendDeclineMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ LastReply->Dhcp6.Option,\r
+- LastReply->Length - 4,\r
++ LastReply->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerId\r
+ );\r
+ if (Option == NULL) {\r
+@@ -1448,7 +1521,7 @@ Dhcp6SendReleaseMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ LastReply->Dhcp6.Option,\r
+- LastReply->Length - 4,\r
++ LastReply->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerId\r
+ );\r
+ if (Option == NULL) {\r
+@@ -1674,7 +1747,7 @@ Dhcp6SendRenewRebindMsg (
+ \r
+ Option = Dhcp6SeekOption (\r
+ LastReply->Dhcp6.Option,\r
+- LastReply->Length - 4,\r
++ LastReply->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerId\r
+ );\r
+ if (Option == NULL) {\r
+@@ -2210,7 +2283,7 @@ Dhcp6HandleReplyMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ Packet->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptRapidCommit\r
+ );\r
+ \r
+@@ -2356,7 +2429,7 @@ Dhcp6HandleReplyMsg (
+ //\r
+ // Any error status code option is found.\r
+ //\r
+- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));\r
++ StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE(Option)))));\r
+ switch (StsCode) {\r
+ case Dhcp6StsUnspecFail:\r
+ //\r
+@@ -2489,7 +2562,7 @@ Dhcp6SelectAdvertiseMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ AdSelect->Dhcp6.Option,\r
+- AdSelect->Length - 4,\r
++ AdSelect->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerUnicast\r
+ );\r
+ \r
+@@ -2500,7 +2573,7 @@ Dhcp6SelectAdvertiseMsg (
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+- CopyMem (Instance->Unicast, Option + 4, sizeof (EFI_IPv6_ADDRESS));\r
++ CopyMem (Instance->Unicast, DHCP6_OFFSET_OF_OPT_DATA(Option), sizeof (EFI_IPv6_ADDRESS));\r
+ }\r
+ \r
+ //\r
+@@ -2553,7 +2626,7 @@ Dhcp6HandleAdvertiseMsg (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ Packet->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptRapidCommit\r
+ );\r
+ \r
+@@ -2647,7 +2720,8 @@ Dhcp6HandleAdvertiseMsg (
+ CopyMem (Instance->AdSelect, Packet, Packet->Size);\r
+ \r
+ if (Option != NULL) {\r
+- Instance->AdPref = *(Option + 4);\r
++ Instance->AdPref = *(DHCP6_OFFSET_OF_OPT_DATA(Option));\r
++\r
+ }\r
+ } else {\r
+ //\r
+@@ -2716,11 +2790,11 @@ Dhcp6HandleStateful (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN,\r
+ Dhcp6OptClientId\r
+ );\r
+ \r
+- if ((Option == NULL) || (CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0)) {\r
++ if ((Option == NULL) || (CompareMem (DHCP6_OFFSET_OF_OPT_DATA(Option), ClientId->Duid, ClientId->Length) != 0)) {\r
+ goto ON_CONTINUE;\r
+ }\r
+ \r
+@@ -2729,7 +2803,7 @@ Dhcp6HandleStateful (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN,\r
+ Dhcp6OptServerId\r
+ );\r
+ \r
+@@ -2834,7 +2908,7 @@ Dhcp6HandleStateless (
+ //\r
+ Option = Dhcp6SeekOption (\r
+ Packet->Dhcp6.Option,\r
+- Packet->Length - 4,\r
++ Packet->Length - sizeof(EFI_DHCP6_HEADER),\r
+ Dhcp6OptServerId\r
+ );\r
+ \r
+--
+2.41.0
+
+
+From ac0130907b8a88cca3c4d8eb590f3b4aa33133d8 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 13:31:38 -0800
+Subject: [PATCH 04/12] SECURITY PATCH TCBZ4534 - CVE-2023-45229 - Host Based
+ Unit Test
+
+---
+ .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 54 +-
+ .../GoogleTest/Dhcp6DxeGoogleTest.inf | 86 +--
+ .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 631 ++++++++++++++----
+ .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 ++
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 204 +++---
+ 5 files changed, 726 insertions(+), 307 deletions(-)
+ create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h
+
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
+index b1fe72e195..36fd708cfc 100644
+--- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp
+@@ -1,27 +1,27 @@
+-/** @file\r
+- Acts as the main entry point for the tests for the Dhcp6Dxe module.\r
+-\r
+- Copyright (c) Microsoft Corporation\r
+- SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-**/\r
+-#include <gtest/gtest.h>\r
+-\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-// Add test files here\r
+-// Google Test will only pick up the tests from the files that are included\r
+-// here.\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-#include "Dhcp6IoGoogleTest.cpp"\r
+-\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-// Run the tests\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-int\r
+-main (\r
+- int argc,\r
+- char *argv[]\r
+- )\r
+-{\r
+- testing::InitGoogleTest (&argc, argv);\r
+- return RUN_ALL_TESTS ();\r
+-}\r
++/** @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>
++
++////////////////////////////////////////////////////////////////////////////////
++// Add test files here
++// Google Test will only pick up the tests from the files that are included
++// here.
++////////////////////////////////////////////////////////////////////////////////
++#include "Dhcp6IoGoogleTest.cpp"
++
++////////////////////////////////////////////////////////////////////////////////
++// Run the tests
++////////////////////////////////////////////////////////////////////////////////
++int
++main (
++ int argc,
++ char *argv[]
++ )
++{
++ testing::InitGoogleTest (&argc, argv);
++ return RUN_ALL_TESTS ();
++}
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
+index c7ec42b322..b74497b6b3 100644
+--- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf
+@@ -1,44 +1,44 @@
+-## @file\r
+-# Unit test suite for the Dhcp6Dxe using Google Test\r
+-#\r
+-# Copyright (c) Microsoft Corporation.<BR>\r
+-# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-##\r
+-[Defines]\r
+- INF_VERSION = 0x00010017\r
+- BASE_NAME = Dhcp6DxeGoogleTest\r
+- FILE_GUID = 1D2A4C65-38C8-4C2F-BB60-B5FA49625AA9\r
+- VERSION_STRING = 1.0\r
+- MODULE_TYPE = HOST_APPLICATION\r
+-#\r
+-# The following information is for reference only and not required by the build tools.\r
+-#\r
+-# VALID_ARCHITECTURES = IA32 X64 AARCH64\r
+-#\r
+-[Sources]\r
+- Dhcp6DxeGoogleTest.cpp\r
+- Dhcp6IoGoogleTest.cpp\r
+- ../Dhcp6Io.c\r
+- ../Dhcp6Utility.c\r
+-\r
+-\r
+-[Packages]\r
+- MdePkg/MdePkg.dec\r
+- MdeModulePkg/MdeModulePkg.dec\r
+- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+- NetworkPkg/NetworkPkg.dec\r
+-\r
+-[LibraryClasses]\r
+- GoogleTestLib\r
+- DebugLib\r
+- NetLib\r
+- PcdLib\r
+-\r
+-[Protocols]\r
+- gEfiDhcp6ServiceBindingProtocolGuid\r
+-\r
+-[Pcd]\r
+- gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType\r
+-\r
+-[Guids]\r
++## @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
+\ No newline at end of file
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
+index dad6a42b12..31e848543d 100644
+--- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp
+@@ -7,12 +7,13 @@
+ #include <gtest/gtest.h>\r
+ \r
+ extern "C" {\r
+- #include <Uefi.h>\r
+- #include <Library/BaseLib.h>\r
+- #include <Library/DebugLib.h>\r
+- #include <Library/BaseMemoryLib.h>\r
+- #include "../Dhcp6Impl.h"\r
+- #include "../Dhcp6Utility.h"\r
++#include <Uefi.h>\r
++#include <Library/BaseLib.h>\r
++#include <Library/DebugLib.h>\r
++#include <Library/BaseMemoryLib.h>\r
++#include "../Dhcp6Impl.h"\r
++#include "../Dhcp6Utility.h"\r
++#include "Dhcp6IoGoogleTest.h"\r
+ }\r
+ \r
+ ////////////////////////////////////////////////////////////////////////\r
+@@ -21,7 +22,35 @@ extern "C" {
+ \r
+ #define DHCP6_PACKET_MAX_LEN 1500\r
+ \r
++// This definition is used by this test but is also required to compile\r
++// by Dhcp6Io.c\r
++#define DHCPV6_OPTION_IA_NA 3\r
++#define DHCPV6_OPTION_IA_TA 4\r
++\r
++#define SEARCH_PATTERN 0xDEADC0DE\r
++#define SEARCH_PATTERN_LEN sizeof(SEARCH_PATTERN)\r
++\r
+ ////////////////////////////////////////////////////////////////////////\r
++// Test structures for IA_NA and IA_TA options\r
++////////////////////////////////////////////////////////////////////////\r
++typedef struct {\r
++ UINT16 Code;\r
++ UINT16 Len;\r
++ UINT32 IAID;\r
++} DHCPv6_OPTION;\r
++\r
++typedef struct {\r
++ DHCPv6_OPTION Header;\r
++ UINT32 T1;\r
++ UINT32 T2;\r
++ UINT8 InnerOptions[0];\r
++} DHCPv6_OPTION_IA_NA;\r
++\r
++typedef struct {\r
++ DHCPv6_OPTION Header;\r
++ UINT8 InnerOptions[0];\r
++} DHCPv6_OPTION_IA_TA;\r
++\r
+ ////////////////////////////////////////////////////////////////////////\r
+ // Symbol Definitions\r
+ // These functions are not directly under test - but required to compile\r
+@@ -65,33 +94,33 @@ UdpIoRecvDatagram (
+ \r
+ class Dhcp6AppendOptionTest : public ::testing::Test {\r
+ public:\r
+- UINT8 *Buffer = NULL;\r
+- EFI_DHCP6_PACKET *Packet;\r
++UINT8 *Buffer = NULL;\r
++EFI_DHCP6_PACKET *Packet;\r
+ \r
+ protected:\r
+- // Add any setup code if needed\r
+- virtual void\r
+- SetUp (\r
+- )\r
+- {\r
+- // Initialize any resources or variables\r
+- Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
+- ASSERT_NE (Buffer, (UINT8 *)NULL);\r
+-\r
+- Packet = (EFI_DHCP6_PACKET *)Buffer;\r
+- Packet->Size = DHCP6_PACKET_MAX_LEN;\r
+- }\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++}\r
+ \r
+- // Add any cleanup code if needed\r
+- virtual void\r
+- TearDown (\r
+- )\r
+- {\r
+- // Clean up any resources or variables\r
+- if (Buffer != NULL) {\r
+- FreePool (Buffer);\r
+- }\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
+ }\r
++}\r
+ };\r
+ \r
+ // Test Description:\r
+@@ -109,12 +138,12 @@ TEST_F (Dhcp6AppendOptionTest, InvalidDataExpectBufferTooSmall) {
+ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option;\r
+ \r
+ Status = Dhcp6AppendOption (\r
+- Dhcp6AppendOptionTest::Packet,\r
+- &Cursor,\r
+- HTONS (Dhcp6OptServerId),\r
+- UntrustedDuid->Length,\r
+- UntrustedDuid->Duid\r
+- );\r
++ Dhcp6AppendOptionTest::Packet,\r
++ &Cursor,\r
++ HTONS (Dhcp6OptServerId),\r
++ UntrustedDuid->Length,\r
++ UntrustedDuid->Duid\r
++ );\r
+ \r
+ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
+ }\r
+@@ -141,12 +170,12 @@ TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) {
+ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option;\r
+ \r
+ Status = Dhcp6AppendOption (\r
+- Dhcp6AppendOptionTest::Packet,\r
+- &Cursor,\r
+- HTONS (Dhcp6OptServerId),\r
+- UntrustedDuid->Length,\r
+- UntrustedDuid->Duid\r
+- );\r
++ Dhcp6AppendOptionTest::Packet,\r
++ &Cursor,\r
++ HTONS (Dhcp6OptServerId),\r
++ UntrustedDuid->Length,\r
++ UntrustedDuid->Duid\r
++ );\r
+ \r
+ ASSERT_EQ (Status, EFI_SUCCESS);\r
+ \r
+@@ -163,34 +192,34 @@ TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) {
+ \r
+ class Dhcp6AppendETOptionTest : public ::testing::Test {\r
+ public:\r
+- UINT8 *Buffer = NULL;\r
+- EFI_DHCP6_PACKET *Packet;\r
++UINT8 *Buffer = NULL;\r
++EFI_DHCP6_PACKET *Packet;\r
+ \r
+ protected:\r
+- // Add any setup code if needed\r
+- virtual void\r
+- SetUp (\r
+- )\r
+- {\r
+- // Initialize any resources or variables\r
+- Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
+- ASSERT_NE (Buffer, (UINT8 *)NULL);\r
+-\r
+- Packet = (EFI_DHCP6_PACKET *)Buffer;\r
+- Packet->Size = DHCP6_PACKET_MAX_LEN;\r
+- Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
+- }\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++}\r
+ \r
+- // Add any cleanup code if needed\r
+- virtual void\r
+- TearDown (\r
+- )\r
+- {\r
+- // Clean up any resources or variables\r
+- if (Buffer != NULL) {\r
+- FreePool (Buffer);\r
+- }\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
+ }\r
++}\r
+ };\r
+ \r
+ // Test Description:\r
+@@ -208,11 +237,11 @@ TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) {
+ Packet->Length = Packet->Size - 2;\r
+ \r
+ Status = Dhcp6AppendETOption (\r
+- Dhcp6AppendETOptionTest::Packet,\r
+- &Cursor,\r
+- &Instance, // Instance is not used in this function\r
+- &ElapsedTime\r
+- );\r
++ Dhcp6AppendETOptionTest::Packet,\r
++ &Cursor,\r
++ &Instance, // Instance is not used in this function\r
++ &ElapsedTime\r
++ );\r
+ \r
+ // verify that we error out because the packet is too small for the option header\r
+ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
+@@ -238,11 +267,11 @@ TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) {
+ OriginalLength = Packet->Length;\r
+ \r
+ Status = Dhcp6AppendETOption (\r
+- Dhcp6AppendETOptionTest::Packet,\r
+- &Cursor,\r
+- &Instance, // Instance is not used in this function\r
+- &ElapsedTime\r
+- );\r
++ Dhcp6AppendETOptionTest::Packet,\r
++ &Cursor,\r
++ &Instance, // Instance is not used in this function\r
++ &ElapsedTime\r
++ );\r
+ \r
+ // verify that the status is EFI_SUCCESS\r
+ ASSERT_EQ (Status, EFI_SUCCESS);\r
+@@ -260,46 +289,46 @@ TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) {
+ \r
+ class Dhcp6AppendIaOptionTest : public ::testing::Test {\r
+ public:\r
+- UINT8 *Buffer = NULL;\r
+- EFI_DHCP6_PACKET *Packet;\r
+- EFI_DHCP6_IA *Ia;\r
++UINT8 *Buffer = NULL;\r
++EFI_DHCP6_PACKET *Packet;\r
++EFI_DHCP6_IA *Ia;\r
+ \r
+ protected:\r
+- // Add any setup code if needed\r
+- virtual void\r
+- SetUp (\r
+- )\r
+- {\r
+- // Initialize any resources or variables\r
+- Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
+- ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ // Initialize any resources or variables\r
++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN);\r
++ ASSERT_NE (Buffer, (UINT8 *)NULL);\r
++\r
++ Packet = (EFI_DHCP6_PACKET *)Buffer;\r
++ Packet->Size = DHCP6_PACKET_MAX_LEN;\r
+ \r
+- Packet = (EFI_DHCP6_PACKET *)Buffer;\r
+- Packet->Size = DHCP6_PACKET_MAX_LEN;\r
++ Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2);\r
++ ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL);\r
+ \r
+- Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2);\r
+- ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL);\r
++ CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
++ CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
+ \r
+- CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
+- CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS));\r
++ Ia->IaAddressCount = 2;\r
++}\r
+ \r
+- Ia->IaAddressCount = 2;\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ // Clean up any resources or variables\r
++ if (Buffer != NULL) {\r
++ FreePool (Buffer);\r
+ }\r
+ \r
+- // Add any cleanup code if needed\r
+- virtual void\r
+- TearDown (\r
+- )\r
+- {\r
+- // Clean up any resources or variables\r
+- if (Buffer != NULL) {\r
+- FreePool (Buffer);\r
+- }\r
+-\r
+- if (Ia != NULL) {\r
+- FreePool (Ia);\r
+- }\r
++ if (Ia != NULL) {\r
++ FreePool (Ia);\r
+ }\r
++}\r
+ };\r
+ \r
+ // Test Description:\r
+@@ -317,13 +346,13 @@ TEST_F (Dhcp6AppendIaOptionTest, IaNaInvalidDataExpectBufferTooSmall) {
+ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
+ \r
+ Status = Dhcp6AppendIaOption (\r
+- Dhcp6AppendIaOptionTest::Packet,\r
+- &Cursor,\r
+- Ia,\r
+- 0x12345678,\r
+- 0x11111111,\r
+- Dhcp6OptIana\r
+- );\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0x12345678,\r
++ 0x11111111,\r
++ Dhcp6OptIana\r
++ );\r
+ \r
+ // verify that we error out because the packet is too small for the option header\r
+ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
+@@ -348,13 +377,13 @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaInvalidDataExpectBufferTooSmall) {
+ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
+ \r
+ Status = Dhcp6AppendIaOption (\r
+- Dhcp6AppendIaOptionTest::Packet,\r
+- &Cursor,\r
+- Ia,\r
+- 0,\r
+- 0,\r
+- Dhcp6OptIata\r
+- );\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0,\r
++ 0,\r
++ Dhcp6OptIata\r
++ );\r
+ \r
+ // verify that we error out because the packet is too small for the option header\r
+ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL);\r
+@@ -406,13 +435,13 @@ TEST_F (Dhcp6AppendIaOptionTest, IaNaValidDataExpectSuccess) {
+ Ia->Descriptor.IaId = 0x12345678;\r
+ \r
+ Status = Dhcp6AppendIaOption (\r
+- Dhcp6AppendIaOptionTest::Packet,\r
+- &Cursor,\r
+- Ia,\r
+- 0x12345678,\r
+- 0x12345678,\r
+- Dhcp6OptIana\r
+- );\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0x12345678,\r
++ 0x12345678,\r
++ Dhcp6OptIana\r
++ );\r
+ \r
+ // verify that the pointer to cursor moved by the expected amount\r
+ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize);\r
+@@ -450,7 +479,7 @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) {
+ //\r
+ ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2;\r
+ \r
+- Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option;\r
+ \r
+ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
+ OriginalLength = Packet->Length;\r
+@@ -459,13 +488,13 @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) {
+ Ia->Descriptor.IaId = 0x12345678;\r
+ \r
+ Status = Dhcp6AppendIaOption (\r
+- Dhcp6AppendIaOptionTest::Packet,\r
+- &Cursor,\r
+- Ia,\r
+- 0,\r
+- 0,\r
+- Dhcp6OptIata\r
+- );\r
++ Dhcp6AppendIaOptionTest::Packet,\r
++ &Cursor,\r
++ Ia,\r
++ 0,\r
++ 0,\r
++ Dhcp6OptIata\r
++ );\r
+ \r
+ // verify that the pointer to cursor moved by the expected amount\r
+ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize);\r
+@@ -476,3 +505,335 @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) {
+ // verify that the status is EFI_SUCCESS\r
+ ASSERT_EQ (Status, EFI_SUCCESS);\r
+ }\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Dhcp6SeekInnerOptionSafe Tests\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++// Define a fixture for your tests if needed\r
++class Dhcp6SeekInnerOptionSafeTest : public ::testing::Test {\r
++protected:\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ // Initialize any resources or variables\r
++}\r
++\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ // Clean up any resources or variables\r
++}\r
++};\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IANA option is found.\r
++TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAValidOptionExpectSuccess) {\r
++ EFI_STATUS Result;\r
++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 };\r
++ UINT32 OptionLength = sizeof (Option);\r
++ DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++\r
++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT8 *InnerOptionPtr = NULL;\r
++ UINT16 InnerOptionLength = 0;\r
++\r
++ OptionPtr->Header.Code = Dhcp6OptIana;\r
++ OptionPtr->Header.Len = HTONS (4 + 12); // Valid length has to be more than 12\r
++ OptionPtr->Header.IAID = 0x12345678;\r
++ OptionPtr->T1 = 0x11111111;\r
++ OptionPtr->T2 = 0x22222222;\r
++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength);\r
++\r
++ Result = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIana,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Result, EFI_SUCCESS);\r
++ ASSERT_EQ (InnerOptionLength, 4);\r
++ ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0);\r
++}\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_DEIVCE_ERROR when the IANA option size is invalid.\r
++TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAInvalidSizeExpectFail) {\r
++ // Lets add an inner option of bytes we expect to find\r
++ EFI_STATUS Status;\r
++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 };\r
++ UINT32 OptionLength = sizeof (Option);\r
++ DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++\r
++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT8 *InnerOptionPtr = NULL;\r
++ UINT16 InnerOptionLength = 0;\r
++\r
++ OptionPtr->Header.Code = Dhcp6OptIana;\r
++ OptionPtr->Header.Len = HTONS (4); // Set the length to lower than expected (12)\r
++ OptionPtr->Header.IAID = 0x12345678;\r
++ OptionPtr->T1 = 0x11111111;\r
++ OptionPtr->T2 = 0x22222222;\r
++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength);\r
++\r
++ // Set the InnerOptionLength to be less than the size of the option\r
++ Status = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIana,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Status, EFI_DEVICE_ERROR);\r
++\r
++ // Now set the OptionLength to be less than the size of the option\r
++ OptionLength = sizeof (DHCPv6_OPTION_IA_NA) - 1;\r
++ Status = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIana,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Status, EFI_DEVICE_ERROR);\r
++}\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option is found\r
++TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAValidOptionExpectSuccess) {\r
++ // Lets add an inner option of bytes we expect to find\r
++ EFI_STATUS Status;\r
++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 };\r
++ UINT32 OptionLength = sizeof (Option);\r
++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++\r
++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT8 *InnerOptionPtr = NULL;\r
++ UINT16 InnerOptionLength = 0;\r
++\r
++ OptionPtr->Header.Code = Dhcp6OptIata;\r
++ OptionPtr->Header.Len = HTONS (4 + 4); // Valid length has to be more than 4\r
++ OptionPtr->Header.IAID = 0x12345678;\r
++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength);\r
++\r
++ Status = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIata,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++ ASSERT_EQ (InnerOptionLength, 4);\r
++ ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0);\r
++}\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid.\r
++TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAInvalidSizeExpectFail) {\r
++ // Lets add an inner option of bytes we expect to find\r
++ EFI_STATUS Status;\r
++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 };\r
++ UINT32 OptionLength = sizeof (Option);\r
++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++\r
++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT8 *InnerOptionPtr = NULL;\r
++ UINT16 InnerOptionLength = 0;\r
++\r
++ OptionPtr->Header.Code = Dhcp6OptIata;\r
++ OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4)\r
++ OptionPtr->Header.IAID = 0x12345678;\r
++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength);\r
++\r
++ Status = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIata,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Status, EFI_DEVICE_ERROR);\r
++\r
++ // Now lets try modifying the OptionLength to be less than the size of the option\r
++ OptionLength = sizeof (DHCPv6_OPTION_IA_TA) - 1;\r
++ Status = Dhcp6SeekInnerOptionSafe (\r
++ Dhcp6OptIata,\r
++ Option,\r
++ OptionLength,\r
++ &InnerOptionPtr,\r
++ &InnerOptionLength\r
++ );\r
++ ASSERT_EQ (Status, EFI_DEVICE_ERROR);\r
++}\r
++\r
++// Test Description:\r
++// This test verifies that any other Option Type fails\r
++TEST_F (Dhcp6SeekInnerOptionSafeTest, InvalidOption) {\r
++ // Lets add an inner option of bytes we expect to find\r
++ EFI_STATUS Result;\r
++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 };\r
++ UINT32 OptionLength = sizeof (Option);\r
++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++\r
++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT8 *InnerOptionPtr = NULL;\r
++ UINT16 InnerOptionLength = 0;\r
++\r
++ OptionPtr->Header.Code = 0xC0DE;\r
++ OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4)\r
++ OptionPtr->Header.IAID = 0x12345678;\r
++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength);\r
++\r
++ Result = Dhcp6SeekInnerOptionSafe (0xC0DE, Option, OptionLength, &InnerOptionPtr, &InnerOptionLength);\r
++ ASSERT_EQ (Result, EFI_DEVICE_ERROR);\r
++}\r
++\r
++////////////////////////////////////////////////////////////////////////\r
++// Dhcp6SeekStsOption Tests\r
++////////////////////////////////////////////////////////////////////////\r
++\r
++#define PACKET_SIZE (1500)\r
++\r
++class Dhcp6SeekStsOptionTest : public ::testing::Test {\r
++public:\r
++DHCP6_INSTANCE Instance = { 0 };\r
++EFI_DHCP6_PACKET *Packet = NULL;\r
++EFI_DHCP6_CONFIG_DATA Config = { 0 };\r
++\r
++protected:\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ // Allocate a packet\r
++ Packet = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE);\r
++ ASSERT_NE (Packet, nullptr);\r
++\r
++ // Initialize the packet\r
++ Packet->Size = PACKET_SIZE;\r
++\r
++ Instance.Config = &Config;\r
++}\r
++\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ // Clean up any resources or variables\r
++ FreePool (Packet);\r
++}\r
++};\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekStsOption returns EFI_DEVICE_ERROR when the option is invalid\r
++// This verifies that the calling function is working as expected\r
++TEST_F (Dhcp6SeekStsOptionTest, SeekIATAOptionExpectFail) {\r
++ EFI_STATUS Status;\r
++ UINT8 *Option = NULL;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++ UINT16 SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ UINT16 *Len = NULL;\r
++ EFI_DHCP6_IA Ia = { 0 };\r
++\r
++ Ia.Descriptor.Type = DHCPV6_OPTION_IA_TA;\r
++ Ia.IaAddressCount = 1;\r
++ Ia.IaAddress[0].PreferredLifetime = 0xDEADBEEF;\r
++ Ia.IaAddress[0].ValidLifetime = 0xDEADAAAA;\r
++ Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress;\r
++\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++\r
++ Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option;\r
++\r
++ // Let's append the option to the packet\r
++ Status = Dhcp6AppendOption (\r
++ Dhcp6SeekStsOptionTest::Packet,\r
++ &Option,\r
++ Dhcp6OptStatusCode,\r
++ SearchPatternLength,\r
++ (UINT8 *)&SearchPattern\r
++ );\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ // Inner option length - this will be overwritten later\r
++ Len = (UINT16 *)(Option + 2);\r
++\r
++ // Fill in the inner IA option\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6SeekStsOptionTest::Packet,\r
++ &Option,\r
++ &Ia,\r
++ 0x12345678,\r
++ 0x11111111,\r
++ 0x22222222\r
++ );\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ // overwrite the len of inner Ia option\r
++ *Len = HTONS (3);\r
++\r
++ Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_TA;\r
++\r
++ Option = NULL;\r
++ Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option);\r
++\r
++ ASSERT_EQ (Status, EFI_DEVICE_ERROR);\r
++}\r
++\r
++// Test Description:\r
++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid.\r
++TEST_F (Dhcp6SeekStsOptionTest, SeekIANAOptionExpectSuccess) {\r
++ EFI_STATUS Status = EFI_NOT_FOUND;\r
++ UINT8 *Option = NULL;\r
++ UINT32 SearchPattern = SEARCH_PATTERN;\r
++ UINT16 SearchPatternLength = SEARCH_PATTERN_LEN;\r
++ EFI_DHCP6_IA Ia = { 0 };\r
++\r
++ Ia.Descriptor.Type = DHCPV6_OPTION_IA_NA;\r
++ Ia.IaAddressCount = 1;\r
++ Ia.IaAddress[0].PreferredLifetime = 0x11111111;\r
++ Ia.IaAddress[0].ValidLifetime = 0x22222222;\r
++ Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress;\r
++ Packet->Length = sizeof (EFI_DHCP6_HEADER);\r
++\r
++ Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option;\r
++\r
++ Status = Dhcp6AppendOption (\r
++ Dhcp6SeekStsOptionTest::Packet,\r
++ &Option,\r
++ Dhcp6OptStatusCode,\r
++ SearchPatternLength,\r
++ (UINT8 *)&SearchPattern\r
++ );\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ Status = Dhcp6AppendIaOption (\r
++ Dhcp6SeekStsOptionTest::Packet,\r
++ &Option,\r
++ &Ia,\r
++ 0x12345678,\r
++ 0x11111111,\r
++ 0x22222222\r
++ );\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++\r
++ Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_NA;\r
++\r
++ Option = NULL;\r
++ Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option);\r
++\r
++ ASSERT_EQ (Status, EFI_SUCCESS);\r
++}\r
+diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h
+new file mode 100644
+index 0000000000..c5e38daf9c
+--- /dev/null
++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h
+@@ -0,0 +1,58 @@
++/** @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/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+index 5befdf7688..f6459b124f 100644
+--- a/NetworkPkg/Test/NetworkPkgHostTest.dsc
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -1,102 +1,102 @@
+-## @file\r
+-# NetworkPkgHostTest DSC file used to build host-based unit tests.\r
+-#\r
+-# Copyright (c) Microsoft Corporation.<BR>\r
+-# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-#\r
+-##\r
+-[Defines]\r
+- PLATFORM_NAME = NetworkPkgHostTest\r
+- PLATFORM_GUID = 3b68324e-fc07-4d49-9520-9347ede65879\r
+- PLATFORM_VERSION = 0.1\r
+- DSC_SPECIFICATION = 0x00010005\r
+- OUTPUT_DIRECTORY = Build/NetworkPkg/HostTest\r
+- SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64\r
+- BUILD_TARGETS = NOOPT\r
+- SKUID_IDENTIFIER = DEFAULT\r
+- \r
+-!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc\r
+-[Packages]\r
+- MdePkg/MdePkg.dec\r
+- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+-\r
+-[Components]\r
+- #\r
+- # Build HOST_APPLICATION that tests NetworkPkg\r
+- #\r
+- NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf\r
+-\r
+-# Despite these library classes being listed in [LibraryClasses] below, they are not needed for the host-based unit tests.\r
+-[LibraryClasses]\r
+- NetLib|NetworkPkg/Library/DxeNetLib/DxeNetLib.inf\r
+- DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
+- BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
+- BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
+- DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
+- HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf\r
+- MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
+- PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+- PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
+- UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
+- UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf\r
+- UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
+- UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
+- UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
+- UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf\r
+- UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf\r
+- TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
+- PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
+- PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf\r
+- DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
+- DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
+- SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf\r
+- RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf\r
+- VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf\r
+-!ifdef CONTINUOUS_INTEGRATION\r
+- BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf\r
+- TlsLib|CryptoPkg/Library/TlsLibNull/TlsLibNull.inf\r
+-!else\r
+- BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
+- OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf\r
+- TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf\r
+-!endif\r
+- DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf\r
+- FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf\r
+- FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
+- SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf\r
+- IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\r
+-\r
+-!if $(TOOL_CHAIN_TAG) == VS2019 or $(TOOL_CHAIN_TAG) == VS2022\r
+-[LibraryClasses.X64]\r
+- # Provide StackCookie support lib so that we can link to /GS exports for VS builds\r
+- RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf\r
+- NULL|MdePkg/Library/BaseBinSecurityLibRng/BaseBinSecurityLibRng.inf\r
+-!endif\r
+-\r
+-[LibraryClasses.common.UEFI_DRIVER]\r
+- HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
+- ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf\r
+- DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf\r
+-[LibraryClasses.common.UEFI_APPLICATION]\r
+- DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf\r
+- ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf\r
+-[LibraryClasses.ARM, LibraryClasses.AARCH64]\r
+- #\r
+- # It is not possible to prevent ARM compiler calls to generic intrinsic functions.\r
+- # This library provides the instrinsic functions generated by a given compiler.\r
+- # [LibraryClasses.ARM] and NULL mean link this library into all ARM images.\r
+- #\r
+- # MU_CHANGE Start\r
+-!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019\r
+- NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf\r
+-!endif\r
+- # MU_CHANGE End\r
+- NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf\r
+-[LibraryClasses.ARM]\r
+- RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf\r
+-[LibraryClasses.RISCV64]\r
+- RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf\r
+- \r
+-[PcdsFixedAtBuild]\r
+- gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2\r
+- gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType|0x4
+\ No newline at end of file
++## @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
++ NULL|MdePkg/Library/BaseBinSecurityLibRng/BaseBinSecurityLibRng.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.
++ #
++ # MU_CHANGE Start
++!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019
++ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
++!endif
++ # MU_CHANGE End
++ 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
+--
+2.41.0
+
+
+From d74c1be05f439ab3b94ac50f8b46cece775c8ee7 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 13:32:28 -0800
+Subject: [PATCH 05/12] SECURITY PATCH TCBZ4536 - CVE-2023-45231 - Patch
+
+---
+ NetworkPkg/Ip6Dxe/Ip6Option.c | 112 ++++++++++++++++++----------------
+ 1 file changed, 60 insertions(+), 52 deletions(-)
+
+diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c
+index 199eea124d..bc74d52a6c 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Option.c
++++ b/NetworkPkg/Ip6Dxe/Ip6Option.c
+@@ -76,27 +76,27 @@ Ip6IsOptionValid (
+ case Ip6OptionParameterProblem:\r
+ Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 2,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 2,\r
++ &Pointer\r
++ );\r
+ return FALSE;\r
+ case Ip6OptionMask:\r
+ if (!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {\r
+ Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 2,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 2,\r
++ &Pointer\r
++ );\r
+ }\r
+ \r
+ return FALSE;\r
+@@ -137,6 +137,14 @@ Ip6IsNDOptionValid (
+ return FALSE;\r
+ }\r
+ \r
++ //\r
++ // Cannot process truncated options.\r
++ // Cannot process options with a length of 0 as there is no Type field.\r
++ //\r
++ if (OptionLen < sizeof (IP6_OPTION_HEADER)) {\r
++ return FALSE;\r
++ }\r
++\r
+ Offset = 0;\r
+ \r
+ //\r
+@@ -358,14 +366,14 @@ Ip6IsExtsValid (
+ !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))\r
+ {\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 1,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 1,\r
++ &Pointer\r
++ );\r
+ }\r
+ \r
+ return FALSE;\r
+@@ -438,14 +446,14 @@ Ip6IsExtsValid (
+ !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))\r
+ {\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 0,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 0,\r
++ &Pointer\r
++ );\r
+ }\r
+ \r
+ return FALSE;\r
+@@ -484,14 +492,14 @@ Ip6IsExtsValid (
+ {\r
+ Pointer = sizeof (UINT32);\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 0,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 0,\r
++ &Pointer\r
++ );\r
+ return FALSE;\r
+ }\r
+ }\r
+@@ -560,14 +568,14 @@ Ip6IsExtsValid (
+ !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))\r
+ {\r
+ Ip6SendIcmpError (\r
+- IpSb,\r
+- Packet,\r
+- NULL,\r
+- &Packet->Ip.Ip6->SourceAddress,\r
+- ICMP_V6_PARAMETER_PROBLEM,\r
+- 1,\r
+- &Pointer\r
+- );\r
++ IpSb,\r
++ Packet,\r
++ NULL,\r
++ &Packet->Ip.Ip6->SourceAddress,\r
++ ICMP_V6_PARAMETER_PROBLEM,\r
++ 1,\r
++ &Pointer\r
++ );\r
+ }\r
+ \r
+ return FALSE;\r
+@@ -774,10 +782,10 @@ Ip6FillFragmentHeader (
+ // Append the part2 (fragmentable part) of Extension headers\r
+ //\r
+ CopyMem (\r
+- Buffer + Part1Len + sizeof (IP6_FRAGMENT_HEADER),\r
+- ExtHdrs + Part1Len,\r
+- ExtHdrsLen - Part1Len\r
+- );\r
++ Buffer + Part1Len + sizeof (IP6_FRAGMENT_HEADER),\r
++ ExtHdrs + Part1Len,\r
++ ExtHdrsLen - Part1Len\r
++ );\r
+ }\r
+ \r
+ *UpdatedExtHdrs = Buffer;\r
+--
+2.41.0
+
+
+From 2f237a59ec4ea3df4b1614566ac29c90fb106669 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Fri, 15 Dec 2023 13:55:30 -0800
+Subject: [PATCH 06/12] SECURITY PATCH TCBZ4536 - CVE-2023-45231 - Host Based
+ Unit Test
+
+---
+ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 27 ++++
+ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 42 ++++++
+ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 129 ++++++++++++++++++
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 +
+ 4 files changed, 199 insertions(+)
+ create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
+ create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+ create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
+new file mode 100644
+index 0000000000..9dd5577249
+--- /dev/null
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
+@@ -0,0 +1,27 @@
++/** @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>
++
++////////////////////////////////////////////////////////////////////////////////
++// Add test files here
++// Google Test will only pick up the tests from the files that are included
++// here.
++////////////////////////////////////////////////////////////////////////////////
++#include "Ip6OptionGoogleTest.cpp"
++
++////////////////////////////////////////////////////////////////////////////////
++// Run the tests
++////////////////////////////////////////////////////////////////////////////////
++int
++main (
++ int argc,
++ char *argv[]
++ )
++{
++ testing::InitGoogleTest (&argc, argv);
++ return RUN_ALL_TESTS ();
++}
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+new file mode 100644
+index 0000000000..b85584b796
+--- /dev/null
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+@@ -0,0 +1,42 @@
++## @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
+\ No newline at end of file
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+new file mode 100644
+index 0000000000..c4bcfacb92
+--- /dev/null
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+@@ -0,0 +1,129 @@
++/** @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, OPTION_HEADER_IP6_PREFIX_DATA_LEN);
++
++ EXPECT_FALSE (Ip6IsNDOptionValid (option, OPTION_HEADER_IP6_PREFIX_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));
++}
+\ No newline at end of file
+diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+index f6459b124f..8ed3585c06 100644
+--- a/NetworkPkg/Test/NetworkPkgHostTest.dsc
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -25,6 +25,7 @@
+ # 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]
+--
+2.41.0
+
+
+From 7ec488242f6c634a6e08fda25e4196ab24bf2d42 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 10:37:40 -0800
+Subject: [PATCH 07/12] SECURITY PATCH TCBZ4537 / TCBZ4538 - CVE-2023-45232 /
+ CVE-2023-45233 - Patch
+
+---
+ NetworkPkg/Ip6Dxe/Ip6Option.c | 81 ++++++++++++++++++++++++++-----
+ NetworkPkg/Ip6Dxe/Ip6Option.h | 89 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 157 insertions(+), 13 deletions(-)
+
+diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c
+index bc74d52a6c..9ca4d6ae5d 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Option.c
++++ b/NetworkPkg/Ip6Dxe/Ip6Option.c
+@@ -9,6 +9,7 @@
+ \r
+ #include "Ip6Impl.h"\r
+ \r
++\r
+ /**\r
+ Validate the IP6 option format for both the packets we received\r
+ and that we will transmit. It will compute the ICMPv6 error message fields\r
+@@ -17,7 +18,8 @@
+ @param[in] IpSb The IP6 service data.\r
+ @param[in] Packet The to be validated packet.\r
+ @param[in] Option The first byte of the option.\r
+- @param[in] OptionLen The length of the whole option.\r
++ @param[in] OptionLen The length of all options, expressed in byte length of octets.\r
++ Maximum length is 2046 bytes or ((n + 1) * 8) - 2 where n is 255.\r
+ @param[in] Pointer Identifies the octet offset within\r
+ the invoking packet where the error was detected.\r
+ \r
+@@ -31,12 +33,33 @@ Ip6IsOptionValid (
+ IN IP6_SERVICE *IpSb,\r
+ IN NET_BUF *Packet,\r
+ IN UINT8 *Option,\r
+- IN UINT8 OptionLen,\r
++ IN UINT16 OptionLen,\r
+ IN UINT32 Pointer\r
+ )\r
+ {\r
+- UINT8 Offset;\r
+- UINT8 OptionType;\r
++ UINT16 Offset;\r
++ UINT8 OptionType;\r
++ UINT8 OptDataLen;\r
++\r
++ if (Option == NULL) {\r
++ ASSERT (Option != NULL);\r
++ return FALSE;\r
++ }\r
++\r
++ if (OptionLen <= 0 || OptionLen > IP6_MAX_EXT_DATA_LENGTH) {\r
++ ASSERT (OptionLen > 0 && OptionLen <= IP6_MAX_EXT_DATA_LENGTH);\r
++ return FALSE;\r
++ }\r
++\r
++ if (Packet == NULL) {\r
++ ASSERT (Packet != NULL);\r
++ return FALSE;\r
++ }\r
++\r
++ if (IpSb == NULL) {\r
++ ASSERT (IpSb != NULL);\r
++ return FALSE;\r
++ }\r
+ \r
+ Offset = 0;\r
+ \r
+@@ -54,7 +77,8 @@ Ip6IsOptionValid (
+ //\r
+ // It is a PadN option\r
+ //\r
+- Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2);\r
++ OptDataLen = *(IP6_OFFSET_OF_OPT_LEN(Option + Offset));\r
++ Offset = IP6_NEXT_OPTION_OFFSET(Offset, OptDataLen);\r
+ break;\r
+ case Ip6OptionRouterAlert:\r
+ //\r
+@@ -69,7 +93,8 @@ Ip6IsOptionValid (
+ //\r
+ switch (OptionType & Ip6OptionMask) {\r
+ case Ip6OptionSkip:\r
+- Offset = (UINT8)(Offset + *(Option + Offset + 1));\r
++ OptDataLen = *(IP6_OFFSET_OF_OPT_LEN(Option + Offset));\r
++ Offset = IP6_NEXT_OPTION_OFFSET(Offset, OptDataLen);\r
+ break;\r
+ case Ip6OptionDiscard:\r
+ return FALSE;\r
+@@ -308,7 +333,7 @@ Ip6IsExtsValid (
+ UINT32 Pointer;\r
+ UINT32 Offset;\r
+ UINT8 *Option;\r
+- UINT8 OptionLen;\r
++ UINT16 OptionLen;\r
+ BOOLEAN Flag;\r
+ UINT8 CountD;\r
+ UINT8 CountA;\r
+@@ -385,6 +410,36 @@ Ip6IsExtsValid (
+ // Fall through\r
+ //\r
+ case IP6_DESTINATION:\r
++ //\r
++ // See https://www.rfc-editor.org/rfc/rfc2460#section-4.2 page 23\r
++ //\r
++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++ // | Next Header | Hdr Ext Len | |\r
++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +\r
++ // | |\r
++ // . .\r
++ // . Options .\r
++ // . .\r
++ // | |\r
++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++ //\r
++ //\r
++ // Next Header 8-bit selector. Identifies the type of header\r
++ // immediately following the Destination Options\r
++ // header. Uses the same values as the IPv4\r
++ // Protocol field [RFC-1700 et seq.].\r
++ //\r
++ // Hdr Ext Len 8-bit unsigned integer. Length of the\r
++ // Destination Options header in 8-octet units, not\r
++ // including the first 8 octets.\r
++ //\r
++ // Options Variable-length field, of length such that the\r
++ // complete Destination Options header is an\r
++ // integer multiple of 8 octets long. Contains one\r
++ // or more TLV-encoded options, as described in\r
++ // section 4.2.\r
++ //\r
++\r
+ if (*NextHeader == IP6_DESTINATION) {\r
+ CountD++;\r
+ }\r
+@@ -397,8 +452,8 @@ Ip6IsExtsValid (
+ Pointer = Offset;\r
+ \r
+ Offset++;\r
+- Option = ExtHdrs + Offset;\r
+- OptionLen = (UINT8)((*Option + 1) * 8 - 2);\r
++ Option = ExtHdrs + Offset;\r
++ OptionLen = IP6_HDR_EXT_LEN(*Option) - IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN;\r
+ Option++;\r
+ Offset++;\r
+ \r
+@@ -430,7 +485,7 @@ Ip6IsExtsValid (
+ //\r
+ // Ignore the routing header and proceed to process the next header.\r
+ //\r
+- Offset = Offset + (RoutingHead->HeaderLen + 1) * 8;\r
++ Offset = Offset + IP6_HDR_EXT_LEN(RoutingHead->HeaderLen);\r
+ \r
+ if (UnFragmentLen != NULL) {\r
+ *UnFragmentLen = Offset;\r
+@@ -441,7 +496,7 @@ Ip6IsExtsValid (
+ // to the packet's source address, pointing to the unrecognized routing\r
+ // type.\r
+ //\r
+- Pointer = Offset + 2 + sizeof (EFI_IP6_HEADER);\r
++ Pointer = Offset + IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN + sizeof (EFI_IP6_HEADER);\r
+ if ((IpSb != NULL) && (Packet != NULL) &&\r
+ !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))\r
+ {\r
+@@ -527,8 +582,8 @@ Ip6IsExtsValid (
+ //\r
+ // RFC2402, Payload length is specified in 32-bit words, minus "2".\r
+ //\r
+- OptionLen = (UINT8)((*Option + 2) * 4);\r
+- Offset = Offset + OptionLen;\r
++ OptionLen = ((UINT16)(*Option + 2) * 4);\r
++ Offset = Offset + OptionLen;\r
+ break;\r
+ \r
+ case IP6_NO_NEXT_HEADER:\r
+diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.h b/NetworkPkg/Ip6Dxe/Ip6Option.h
+index bd8e223c8a..1f9237b4e9 100644
+--- a/NetworkPkg/Ip6Dxe/Ip6Option.h
++++ b/NetworkPkg/Ip6Dxe/Ip6Option.h
+@@ -12,6 +12,95 @@
+ \r
+ #define IP6_FRAGMENT_OFFSET_MASK (~0x3)\r
+ \r
++//\r
++// Per RFC8200 Section 4.2\r
++//\r
++// Two of the currently-defined extension headers -- the Hop-by-Hop\r
++// Options header and the Destination Options header -- carry a variable\r
++// number of type-length-value (TLV) encoded "options", of the following\r
++// format:\r
++//\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -\r
++// | Option Type | Opt Data Len | Option Data\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -\r
++//\r
++// Option Type 8-bit identifier of the type of option.\r
++//\r
++// Opt Data Len 8-bit unsigned integer. Length of the Option\r
++// Data field of this option, in octets.\r
++//\r
++// Option Data Variable-length field. Option-Type-specific\r
++// data.\r
++//\r
++#define IP6_SIZE_OF_OPT_TYPE (sizeof(UINT8))\r
++#define IP6_SIZE_OF_OPT_LEN (sizeof(UINT8))\r
++#define IP6_COMBINED_SIZE_OF_OPT_TAG_AND_LEN (IP6_SIZE_OF_OPT_TYPE + IP6_SIZE_OF_OPT_LEN)\r
++#define IP6_OFFSET_OF_OPT_LEN(a) (a + IP6_SIZE_OF_OPT_TYPE)\r
++STATIC_ASSERT (\r
++ IP6_OFFSET_OF_OPT_LEN (0) == 1,\r
++ "The Length field should be 1 octet (8 bits) past the start of the option"\r
++ );\r
++\r
++#define IP6_NEXT_OPTION_OFFSET(offset, length) (offset + IP6_COMBINED_SIZE_OF_OPT_TAG_AND_LEN + length)\r
++STATIC_ASSERT (\r
++ IP6_NEXT_OPTION_OFFSET (0, 0) == 2,\r
++ "The next option is minimally the combined size of the option tag and length"\r
++ );\r
++\r
++//\r
++// For more information see RFC 8200, Section 4.3, 4.4, and 4.6\r
++//\r
++// This example format is from section 4.6\r
++// This does not apply to fragment headers\r
++//\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++// | Next Header | Hdr Ext Len | |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +\r
++// | |\r
++// . .\r
++// . Header-Specific Data .\r
++// . .\r
++// | |\r
++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
++//\r
++// Next Header 8-bit selector. Identifies the type of\r
++// header immediately following the extension\r
++// header. Uses the same values as the IPv4\r
++// Protocol field [IANA-PN].\r
++//\r
++// Hdr Ext Len 8-bit unsigned integer. Length of the\r
++// Destination Options header in 8-octet units,\r
++// not including the first 8 octets.\r
++\r
++//\r
++// These defines apply to the following:\r
++// 1. Hop by Hop\r
++// 2. Routing\r
++// 3. Destination\r
++//\r
++#define IP6_SIZE_OF_EXT_NEXT_HDR (sizeof(UINT8))\r
++#define IP6_SIZE_OF_HDR_EXT_LEN (sizeof(UINT8))\r
++\r
++#define IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN (IP6_SIZE_OF_EXT_NEXT_HDR + IP6_SIZE_OF_HDR_EXT_LEN)\r
++STATIC_ASSERT (\r
++ IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN == 2,\r
++ "The combined size of Next Header and Len is two 8 bit fields"\r
++ );\r
++\r
++//\r
++// The "+ 1" in this calculation is because of the "not including the first 8 octets"\r
++// part of the definition (meaning the value of 0 represents 64 bits)\r
++//\r
++#define IP6_HDR_EXT_LEN(a) (((UINT16)(UINT8)(a) + 1) * 8)\r
++\r
++// This is the maxmimum length permissible by a extension header\r
++// Length is UINT8 of 8 octets not including the first 8 octets\r
++#define IP6_MAX_EXT_DATA_LENGTH (IP6_HDR_EXT_LEN (MAX_UINT8) - IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN)\r
++STATIC_ASSERT (\r
++ IP6_MAX_EXT_DATA_LENGTH == 2046,\r
++ "Maximum data length is ((MAX_UINT8 + 1) * 8) - 2"\r
++ );\r
++\r
+ typedef struct _IP6_FRAGMENT_HEADER {\r
+ UINT8 NextHeader;\r
+ UINT8 Reserved;\r
+--
+2.41.0
+
+
+From d925ff1f00e769bcdbd04c1cb81560a8dec4e235 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 10:49:41 -0800
+Subject: [PATCH 08/12] SECURITY PATCH TCBZ4537 / TCBZ4538 - CVE-2023-45232 /
+ CVE-2023-45233 - Host Based Unit Test
+
+---
+ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 3 +-
+ .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 5 +-
+ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 344 +++++++++++++++++-
+ .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 33 ++
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 2 +-
+ 5 files changed, 376 insertions(+), 11 deletions(-)
+ create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h
+
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
+index 9dd5577249..5525da4231 100644
+--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp
+@@ -1,6 +1,5 @@
+ /** @file
+- Acts as the main entry point for the tests for the Ip6Dxe module.
+-
++ Acts as the main entry point for the tests for the Ip6Dxe driver.
+ Copyright (c) Microsoft Corporation
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+ **/
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+index b85584b796..9f4ce85157 100644
+--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf
+@@ -1,5 +1,5 @@
+ ## @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
+@@ -31,7 +31,6 @@
+ DebugLib
+ NetLib
+ PcdLib
+-
+ [Protocols]
+ gEfiDhcp6ServiceBindingProtocolGuid
+
+@@ -39,4 +38,4 @@
+ gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType
+
+ [Guids]
+- gZeroGuid
+\ No newline at end of file
++ gZeroGuid
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+index c4bcfacb92..640e96a17c 100644
+--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp
+@@ -1,5 +1,5 @@
+ /** @file
+- Tests for Ip6Option.c.
++ Host based unit test for Ip6Option.c.
+
+ Copyright (c) Microsoft Corporation
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+@@ -12,18 +12,23 @@ extern "C" {
+ #include <Library/DebugLib.h>
+ #include "../Ip6Impl.h"
+ #include "../Ip6Option.h"
++ #include "Ip6OptionGoogleTest.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
++///////////////////////////////////////////////////////////////////////
++// Symbol definitions
++//
++// These symbols / stub functions are required to be defined in order
++// to compile but are not under test. These can be converted to
++// Mock functions if required in the future.
++//
+ ////////////////////////////////////////////////////////////////////////
+ UINT32 mIp6Id;
+
+@@ -126,4 +131,333 @@ TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse)
+ UINT16 optionLen = sizeof (IP6_OPTION_HEADER);
+
+ 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));
++}
++
++// Test Description
++// Verify that a OptionLength that is too small fails
++TEST_F (Ip6IsOptionValidTest, VerifyOptionLengthTooSmall) {
++ 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_FALSE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, 0, 0));
++}
++
++// Test Description
++// Verify that a OptionLength that is too large fails
++TEST_F (Ip6IsOptionValidTest, VerifyOptionLengthTooLarge) {
++ 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_FALSE (Ip6IsOptionValid (IpSb, &Packet, (UINT8 *)&optionHeader, MAX_UINT8, 0));
+ }
+\ No newline at end of file
+diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h
+new file mode 100644
+index 0000000000..43ad56b4ab
+--- /dev/null
++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h
+@@ -0,0 +1,33 @@
++#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__
+\ No newline at end of file
+diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+index 8ed3585c06..a95a617d98 100644
+--- a/NetworkPkg/Test/NetworkPkgHostTest.dsc
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -14,7 +14,7 @@
+ SUPPORTED_ARCHITECTURES = IA32|X64|AARCH64
+ BUILD_TARGETS = NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+-
++
+ !include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
+ [Packages]
+ MdePkg/MdePkg.dec
+--
+2.41.0
+
+
+From 813bfde4aa9b099c1eb6d9b38d3dbf3b9e3fa50d Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 11:16:54 -0800
+Subject: [PATCH 09/12] SECURITY PATCH TCBZ4539 - CVE-2023-45234 - Patch
+
+---
+ 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 425e0cf806..4059fae5fc 100644
+--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
+@@ -3,6 +3,7 @@
+ \r
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
++ Copyright (c) Microsoft Corporation\r
+ \r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+ \r
+@@ -1312,6 +1313,65 @@ PxeBcSelectDhcp6Offer (
+ }\r
+ }\r
+ \r
++/**\r
++ Cache the DHCPv6 DNS Server addresses\r
++\r
++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
++ @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE.\r
++\r
++ @retval EFI_SUCCESS Cache the DHCPv6 DNS Server address successfully.\r
++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
++ @retval EFI_DEVICE_ERROR The DNS Server Address Length provided by a untrusted\r
++ option is not a multiple of 16 bytes (sizeof (EFI_IPv6_ADDRESS)).\r
++*/\r
++EFI_STATUS\r
++PxeBcCacheDnsServerAddresses (\r
++ IN PXEBC_PRIVATE_DATA *Private,\r
++ IN PXEBC_DHCP6_PACKET_CACHE *Cache6\r
++ )\r
++{\r
++ UINT16 DnsServerLen;\r
++\r
++ DnsServerLen = NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen);\r
++ //\r
++ // Make sure that the number is nonzero\r
++ //\r
++ if (DnsServerLen == 0) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ //\r
++ // Make sure the DnsServerlen is a multiple of EFI_IPv6_ADDRESS (16)\r
++ //\r
++ if (DnsServerLen % sizeof (EFI_IPv6_ADDRESS) != 0) {\r
++ return EFI_DEVICE_ERROR;\r
++ }\r
++\r
++ //\r
++ // This code is currently written to only support a single DNS Server instead\r
++ // of multiple such as is spec defined (RFC3646, Section 3). The proper behavior\r
++ // would be to allocate the full space requested, CopyMem all of the data,\r
++ // and then add a DnsServerCount field to Private and update additional code\r
++ // that depends on this.\r
++ //\r
++ // To support multiple DNS servers the `AllocationSize` would need to be changed to DnsServerLen\r
++ //\r
++ // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886\r
++ //\r
++ Private->DnsServer = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));\r
++ if (Private->DnsServer == NULL) {\r
++ return EFI_OUT_OF_RESOURCES;\r
++ }\r
++\r
++ //\r
++ // Intentionally only copy over the first server address.\r
++ // To support multiple DNS servers, the `Length` would need to be changed to DnsServerLen\r
++ //\r
++ CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS));\r
++\r
++ return EFI_SUCCESS;\r
++}\r
++\r
+ /**\r
+ Handle the DHCPv6 offer packet.\r
+ \r
+@@ -1335,6 +1395,7 @@ PxeBcHandleDhcp6Offer (
+ UINT32 SelectIndex;\r
+ UINT32 Index;\r
+ \r
++ ASSERT (Private != NULL);\r
+ ASSERT (Private->SelectIndex > 0);\r
+ SelectIndex = (UINT32)(Private->SelectIndex - 1);\r
+ ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);\r
+@@ -1342,15 +1403,13 @@ PxeBcHandleDhcp6Offer (
+ Status = EFI_SUCCESS;\r
+ \r
+ //\r
+- // First try to cache DNS server address if DHCP6 offer provides.\r
++ // First try to cache DNS server addresses if DHCP6 offer provides.\r
+ //\r
+ if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) {\r
+- Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen));\r
+- if (Private->DnsServer == NULL) {\r
+- return EFI_OUT_OF_RESOURCES;\r
++ Status = PxeBcCacheDnsServerAddresses (Private, Cache6);\r
++ if (EFI_ERROR (Status)) {\r
++ return Status;\r
+ }\r
+-\r
+- CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS));\r
+ }\r
+ \r
+ if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {\r
+--
+2.41.0
+
+
+From 688eb3679f795d8699d09acc7a8c2322b389c440 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 11:17:25 -0800
+Subject: [PATCH 10/12] SECURITY PATCH TCBZ4539 - CVE-2023-45234 - Host Based
+ Unit Test
+
+---
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 1 +
+ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 301 ++++++++++++++++++
+ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 48 +++
+ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 21 ++
+ .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 47 +++
+ 5 files changed, 418 insertions(+)
+ create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
+ create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
+ create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
+ create mode 100644 NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
+
+diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+index a95a617d98..b9d031a611 100644
+--- a/NetworkPkg/Test/NetworkPkgHostTest.dsc
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -26,6 +26,7 @@
+ #
+ 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/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
+new file mode 100644
+index 0000000000..9ee805a284
+--- /dev/null
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
+@@ -0,0 +1,301 @@
++/** @file\r
++ Host based unit test for PxeBcDhcp6.c.\r
++\r
++ Copyright (c) Microsoft Corporation\r
++ SPDX-License-Identifier: BSD-2-Clause-Patent\r
++**/\r
++#include <gtest/gtest.h>\r
++\r
++extern "C" {\r
++#include <Uefi.h>\r
++#include <Library/BaseLib.h>\r
++#include <Library/DebugLib.h>\r
++#include "../PxeBcImpl.h"\r
++#include "../PxeBcDhcp6.h"\r
++#include "PxeBcDhcp6GoogleTest.h"\r
++}\r
++\r
++///////////////////////////////////////////////////////////////////////////////\r
++// Definitions\r
++///////////////////////////////////////////////////////////////////////////////\r
++\r
++#define PACKET_SIZE (1500)\r
++\r
++typedef struct {\r
++ UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03)\r
++ UINT16 OptionLen; // The length of the option (e.g., 16 bytes)\r
++ UINT8 ServerId[16]; // The 16-byte DHCPv6 Server Identifier\r
++} DHCP6_OPTION_SERVER_ID;\r
++\r
++///////////////////////////////////////////////////////////////////////////////\r
++/// Symbol Definitions\r
++///////////////////////////////////////////////////////////////////////////////\r
++\r
++EFI_STATUS\r
++MockUdpWrite (\r
++ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
++ IN UINT16 OpFlags,\r
++ IN EFI_IP_ADDRESS *DestIp,\r
++ IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort,\r
++ IN EFI_IP_ADDRESS *GatewayIp OPTIONAL,\r
++ IN EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
++ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL,\r
++ IN UINTN *HeaderSize OPTIONAL,\r
++ IN VOID *HeaderPtr OPTIONAL,\r
++ IN UINTN *BufferSize,\r
++ IN VOID *BufferPtr\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++EFI_STATUS\r
++MockUdpRead (\r
++ IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
++ IN UINT16 OpFlags,\r
++ IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,\r
++ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,\r
++ IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
++ IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL,\r
++ IN UINTN *HeaderSize OPTIONAL,\r
++ IN VOID *HeaderPtr OPTIONAL,\r
++ IN OUT UINTN *BufferSize,\r
++ IN VOID *BufferPtr\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++EFI_STATUS\r
++MockConfigure (\r
++ IN EFI_UDP6_PROTOCOL *This,\r
++ IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++// Needed by PxeBcSupport\r
++EFI_STATUS\r
++EFIAPI\r
++QueueDpc (\r
++ IN EFI_TPL DpcTpl,\r
++ IN EFI_DPC_PROCEDURE DpcProcedure,\r
++ IN VOID *DpcContext OPTIONAL\r
++ )\r
++{\r
++ return EFI_SUCCESS;\r
++}\r
++\r
++///////////////////////////////////////////////////////////////////////////////\r
++// PxeBcHandleDhcp6OfferTest Tests\r
++///////////////////////////////////////////////////////////////////////////////\r
++\r
++class PxeBcHandleDhcp6OfferTest : public ::testing::Test {\r
++public:\r
++PXEBC_PRIVATE_DATA Private = { 0 };\r
++EFI_UDP6_PROTOCOL Udp6Read;\r
++EFI_PXE_BASE_CODE_MODE Mode = { 0 };\r
++\r
++protected:\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++ Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE);\r
++\r
++ // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL\r
++ // The function under test really only needs the following:\r
++ // UdpWrite\r
++ // UdpRead\r
++\r
++ Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite;\r
++ Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead;\r
++\r
++ // Need to setup EFI_UDP6_PROTOCOL\r
++ // The function under test really only needs the following:\r
++ // Configure\r
++\r
++ Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure;\r
++ Private.Udp6Read = &Udp6Read;\r
++\r
++ // Need to setup the EFI_PXE_BASE_CODE_MODE\r
++ Private.PxeBc.Mode = &Mode;\r
++\r
++ // for this test it doesn't really matter what the Dhcpv6 ack is set to\r
++}\r
++\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++ if (Private.Dhcp6Request != NULL) {\r
++ FreePool (Private.Dhcp6Request);\r
++ }\r
++\r
++ // Clean up any resources or variables\r
++}\r
++};\r
++\r
++// Note:\r
++// Testing PxeBcHandleDhcp6Offer() is difficult because it depends on a\r
++// properly setup Private structure. Attempting to properly test this function\r
++// without a signficant refactor is a fools errand. Instead, we will test\r
++// that we can prevent an overflow in the function.\r
++TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) {\r
++ PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
++ EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
++\r
++ Private.SelectIndex = 1; // SelectIndex is 1-based\r
++ Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
++\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
++ // Setup the DHCPv6 offer packet\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337);\r
++\r
++ ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR);\r
++}\r
++\r
++class PxeBcCacheDnsServerAddressesTest : public ::testing::Test {\r
++public:\r
++PXEBC_PRIVATE_DATA Private = { 0 };\r
++\r
++protected:\r
++// Add any setup code if needed\r
++virtual void\r
++SetUp (\r
++ )\r
++{\r
++}\r
++\r
++// Add any cleanup code if needed\r
++virtual void\r
++TearDown (\r
++ )\r
++{\r
++}\r
++};\r
++\r
++// Test Description\r
++// Test that we cache the DNS server address from the DHCPv6 offer packet\r
++TEST_F (PxeBcCacheDnsServerAddressesTest, BasicUsageTest) {\r
++ UINT8 SearchPattern[16] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF };\r
++ EFI_DHCP6_PACKET_OPTION *Option;\r
++ PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
++\r
++ Option = (EFI_DHCP6_PACKET_OPTION *)AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + sizeof (SearchPattern));\r
++ ASSERT_NE (Option, nullptr);\r
++\r
++ Option->OpCode = DHCP6_OPT_SERVER_ID;\r
++ Option->OpLen = NTOHS (sizeof (SearchPattern));\r
++ CopyMem (Option->Data, SearchPattern, sizeof (SearchPattern));\r
++\r
++ Private.SelectIndex = 1; // SelectIndex is 1-based\r
++ Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = Option;\r
++\r
++ Private.DnsServer = nullptr;\r
++\r
++ ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS);\r
++ ASSERT_NE (Private.DnsServer, nullptr);\r
++ ASSERT_EQ (CompareMem (Private.DnsServer, SearchPattern, sizeof (SearchPattern)), 0);\r
++\r
++ if (Private.DnsServer) {\r
++ FreePool (Private.DnsServer);\r
++ }\r
++\r
++ if (Option) {\r
++ FreePool (Option);\r
++ }\r
++}\r
++// Test Description\r
++// Test that we can prevent an overflow in the function\r
++TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptOverflowTest) {\r
++ EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
++ PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
++\r
++ Private.SelectIndex = 1; // SelectIndex is 1-based\r
++ Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
++ // Setup the DHCPv6 offer packet\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337);\r
++\r
++ Private.DnsServer = NULL;\r
++\r
++ ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR);\r
++ ASSERT_EQ (Private.DnsServer, nullptr);\r
++\r
++ if (Private.DnsServer) {\r
++ FreePool (Private.DnsServer);\r
++ }\r
++}\r
++\r
++// Test Description\r
++// Test that we can prevent an underflow in the function\r
++TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptUnderflowTest) {\r
++ EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
++ PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
++\r
++ Private.SelectIndex = 1; // SelectIndex is 1-based\r
++ Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
++ // Setup the DHCPv6 offer packet\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (2);\r
++\r
++ Private.DnsServer = NULL;\r
++\r
++ ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR);\r
++ ASSERT_EQ (Private.DnsServer, nullptr);\r
++\r
++ if (Private.DnsServer) {\r
++ FreePool (Private.DnsServer);\r
++ }\r
++}\r
++\r
++\r
++// Test Description\r
++// Test that we can handle recursive dns (multiple dns entries)\r
++TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) {\r
++ EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
++ PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
++\r
++ Private.SelectIndex = 1; // SelectIndex is 1-based\r
++ Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
++ // Setup the DHCPv6 offer packet\r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
++\r
++ EFI_IPv6_ADDRESS addresses[2] = {\r
++ // 2001:db8:85a3::8a2e:370:7334\r
++ {0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},\r
++ // fe80::d478:91c3:ecd7:4ff9\r
++ {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x78, 0x91, 0xc3, 0xec, 0xd7, 0x4f, 0xf9}\r
++ };\r
++\r
++\r
++ CopyMem(Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, &addresses, sizeof(addresses));\r
++ \r
++ Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (sizeof(addresses));\r
++\r
++ Private.DnsServer = NULL;\r
++\r
++ ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS);\r
++\r
++ ASSERT_NE (Private.DnsServer, nullptr);\r
++ \r
++ //\r
++ // This is expected to fail until DnsServer supports multiple DNS servers \r
++ //\r
++ // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886\r
++ //\r
++ ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0);\r
++\r
++ if (Private.DnsServer) {\r
++ FreePool (Private.DnsServer);\r
++ }\r
++}\r
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
+new file mode 100644
+index 0000000000..724ee468cb
+--- /dev/null
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
+@@ -0,0 +1,48 @@
++/** @file\r
++ \r
++ This file exposes the internal interfaces which may be unit tested\r
++ for the PxeBcDhcp6Dxe driver.\r
++\r
++ Copyright (c) Microsoft Corporation.<BR>\r
++ SPDX-License-Identifier: BSD-2-Clause-Patent\r
++**/\r
++#ifndef __PXE_BC_DHCP6_GOOGLE_TEST_H__\r
++#define __PXE_BC_DHCP6_GOOGLE_TEST_H__\r
++\r
++// Minimal includes needed to compile\r
++#include <Uefi.h>\r
++#include "../PxeBcImpl.h"\r
++\r
++/**\r
++ Handle the DHCPv6 offer packet.\r
++\r
++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
++\r
++ @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.\r
++ @retval EFI_NO_RESPONSE No response to the following request packet.\r
++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
++ @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet.\r
++\r
++**/\r
++EFI_STATUS\r
++PxeBcHandleDhcp6Offer (\r
++ IN PXEBC_PRIVATE_DATA *Private\r
++ );\r
++\r
++ /**\r
++ Cache the DHCPv6 Server address\r
++\r
++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.\r
++ @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE.\r
++\r
++ @retval EFI_SUCCESS Cache the DHCPv6 Server address successfully.\r
++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
++ @retval EFI_DEVICE_ERROR Failed to cache the DHCPv6 Server address.\r
++*/\r
++EFI_STATUS\r
++PxeBcCacheDnsServerAddresses (\r
++ IN PXEBC_PRIVATE_DATA *Private,\r
++ IN PXEBC_DHCP6_PACKET_CACHE *Cache6\r
++ );\r
++\r
++#endif // __PXE_BC_DHCP6_GOOGLE_TEST_H__
+\ No newline at end of file
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
+new file mode 100644
+index 0000000000..cc295f5c88
+--- /dev/null
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
+@@ -0,0 +1,21 @@
++/** @file\r
++ Acts as the main entry point for the tests for the UefiPxeBcDxe module.\r
++ Copyright (c) Microsoft Corporation\r
++ SPDX-License-Identifier: BSD-2-Clause-Patent\r
++**/\r
++#include <gtest/gtest.h>\r
++\r
++////////////////////////////////////////////////////////////////////////////////\r
++// Add test files here\r
++// Google Test will only pick up the tests from the files that are included\r
++// here.\r
++////////////////////////////////////////////////////////////////////////////////\r
++#include "PxeBcDhcp6GoogleTest.cpp"\r
++\r
++////////////////////////////////////////////////////////////////////////////////\r
++// Run the tests\r
++////////////////////////////////////////////////////////////////////////////////\r
++int main(int argc, char* argv[]) {\r
++ testing::InitGoogleTest (&argc, argv);\r
++ return RUN_ALL_TESTS ();\r
++}
+\ No newline at end of file
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
+new file mode 100644
+index 0000000000..c2fd7ae7a9
+--- /dev/null
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
+@@ -0,0 +1,47 @@
++## @file\r
++# Unit test suite for the UefiPxeBcDxe using Google Test\r
++#\r
++# Copyright (c) Microsoft Corporation.<BR>\r
++# SPDX-License-Identifier: BSD-2-Clause-Patent\r
++##\r
++[Defines]\r
++INF_VERSION = 0x00010005\r
++BASE_NAME = UefiPxeBcDxeGoogleTest\r
++FILE_GUID = 77D45C64-EC1E-4174-887B-886E89FD1EDF\r
++MODULE_TYPE = HOST_APPLICATION\r
++VERSION_STRING = 1.0\r
++\r
++#\r
++# The following information is for reference only and not required by the build tools.\r
++#\r
++# VALID_ARCHITECTURES = IA32 X64\r
++#\r
++ \r
++[Sources]\r
++ UefiPxeBcDxeGoogleTest.cpp\r
++ PxeBcDhcp6GoogleTest.cpp\r
++ ../PxeBcDhcp6.c\r
++ ../PxeBcSupport.c\r
++\r
++[Packages]\r
++ MdePkg/MdePkg.dec\r
++ MdeModulePkg/MdeModulePkg.dec\r
++ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
++ NetworkPkg/NetworkPkg.dec\r
++\r
++[LibraryClasses]\r
++ GoogleTestLib\r
++ DebugLib\r
++ NetLib\r
++ PcdLib\r
++\r
++[Protocols]\r
++ gEfiDhcp6ServiceBindingProtocolGuid\r
++ gEfiDns6ServiceBindingProtocolGuid\r
++ gEfiDns6ProtocolGuid\r
++\r
++[Pcd]\r
++ gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType\r
++\r
++[Guids]\r
++ gZeroGuid
+\ No newline at end of file
+--
+2.41.0
+
+
+From 4412e98d2835b0a8a0c80763bb1ef4d62015aa12 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 12:45:31 -0800
+Subject: [PATCH 11/12] SECURITY PATCH TCBZ4540 - CVE-2023-45235 - Patch
+
+---
+ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 85 +++++++++++++++++++++-------
+ NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 ++++++
+ 2 files changed, 83 insertions(+), 19 deletions(-)
+
+diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
+index 4059fae5fc..a3b977fe2a 100644
+--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
+@@ -887,6 +887,7 @@ PxeBcRequestBootService (
+ EFI_STATUS Status;\r
+ EFI_DHCP6_PACKET *IndexOffer;\r
+ UINT8 *Option;\r
++ UINTN DiscoverLenNeeded;\r
+ \r
+ PxeBc = &Private->PxeBc;\r
+ Request = Private->Dhcp6Request;\r
+@@ -898,8 +899,9 @@ PxeBcRequestBootService (
+ if (Request == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+-\r
+- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
++ \r
++ DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET);\r
++ Discover = AllocateZeroPool (DiscoverLenNeeded);\r
+ if (Discover == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+@@ -924,16 +926,34 @@ PxeBcRequestBootService (
+ DHCP6_OPT_SERVER_ID\r
+ );\r
+ if (Option == NULL) {\r
+- return EFI_NOT_FOUND;\r
++ Status = EFI_NOT_FOUND;\r
++ goto ON_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Add Server ID Option.\r
+ //\r
+ OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen);\r
+- CopyMem (DiscoverOpt, Option, OpLen + 4);\r
+- DiscoverOpt += (OpLen + 4);\r
+- DiscoverLen += (OpLen + 4);\r
++\r
++ //\r
++ // Check that the minimum and maximum requirements are met\r
++ //\r
++ if (OpLen < PXEBC_MIN_SIZE_OF_DUID || OpLen > PXEBC_MAX_SIZE_OF_DUID) {\r
++ Status = EFI_INVALID_PARAMETER;\r
++ goto ON_ERROR;\r
++ }\r
++\r
++ //\r
++ // Check that the option length is valid.\r
++ //\r
++ if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) {\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
++ }\r
++\r
++ CopyMem (DiscoverOpt, Option, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
+ }\r
+ \r
+ while (RequestLen < Request->Length) {\r
+@@ -944,16 +964,25 @@ PxeBcRequestBootService (
+ (OpCode != DHCP6_OPT_SERVER_ID)\r
+ )\r
+ {\r
++\r
++ //\r
++ // Check that the option length is valid.\r
++ //\r
++ if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) {\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
++ }\r
++\r
+ //\r
+ // Copy all the options except IA option and Server ID\r
+ //\r
+- CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
+- DiscoverOpt += (OpLen + 4);\r
+- DiscoverLen += (OpLen + 4);\r
++ CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
+ }\r
+ \r
+- RequestOpt += (OpLen + 4);\r
+- RequestLen += (OpLen + 4);\r
++ RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
+ }\r
+ \r
+ //\r
+@@ -2154,7 +2183,8 @@ PxeBcDhcp6Discover (
+ UINT16 OpLen;\r
+ UINT32 Xid;\r
+ EFI_STATUS Status;\r
+-\r
++ UINTN DiscoverLenNeeded;\r
++ \r
+ PxeBc = &Private->PxeBc;\r
+ Mode = PxeBc->Mode;\r
+ Request = Private->Dhcp6Request;\r
+@@ -2168,8 +2198,9 @@ PxeBcDhcp6Discover (
+ if (Request == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+-\r
+- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\r
++ \r
++ DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET);\r
++ Discover = AllocateZeroPool (DiscoverLenNeeded);\r
+ if (Discover == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+@@ -2185,22 +2216,38 @@ PxeBcDhcp6Discover (
+ DiscoverLen = sizeof (EFI_DHCP6_HEADER);\r
+ RequestLen = DiscoverLen;\r
+ \r
++ //\r
++ // The request packet is generated by the UEFI network stack. In the DHCP4 DORA and DHCP6 SARR sequence, \r
++ // the first (discover in DHCP4 and solicit in DHCP6) and third (request in both DHCP4 and DHCP6) are \r
++ // generated by the DHCP client (the UEFI network stack in this case). By the time this function executes,\r
++ // the DHCP sequence already has been executed once (see UEFI Specification Figures 24.2 and 24.3), with\r
++ // Private->Dhcp6Request being a cached copy of the DHCP6 request packet that UEFI network stack previously\r
++ // generated and sent. \r
++ //\r
++ // Therefore while this code looks like it could overflow, in practice it's not possible.\r
++ //\r
+ while (RequestLen < Request->Length) {\r
+ OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode);\r
+ OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen);\r
+ if ((OpCode != EFI_DHCP6_IA_TYPE_NA) &&\r
+ (OpCode != EFI_DHCP6_IA_TYPE_TA))\r
+ {\r
++\r
++ if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) {\r
++ Status = EFI_OUT_OF_RESOURCES;\r
++ goto ON_ERROR;\r
++ }\r
++\r
+ //\r
+ // Copy all the options except IA option.\r
+ //\r
+- CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);\r
+- DiscoverOpt += (OpLen + 4);\r
+- DiscoverLen += (OpLen + 4);\r
++ CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
+ }\r
+ \r
+- RequestOpt += (OpLen + 4);\r
+- RequestLen += (OpLen + 4);\r
++ RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
++ RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);\r
+ }\r
+ \r
+ Status = PxeBc->UdpWrite (\r
+diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h
+index c86f6d391b..2f11f0e1d9 100644
+--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h
++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h
+@@ -34,6 +34,23 @@
+ #define PXEBC_ADDR_START_DELIMITER '['\r
+ #define PXEBC_ADDR_END_DELIMITER ']'\r
+ \r
++//\r
++// A DUID consists of a 2-octet type code represented in network byte\r
++// order, followed by a variable number of octets that make up the\r
++// actual identifier. The length of the DUID (not including the type\r
++// code) is at least 1 octet and at most 128 octets.\r
++//\r
++#define PXEBC_MIN_SIZE_OF_DUID (sizeof(UINT16) + 1)\r
++#define PXEBC_MAX_SIZE_OF_DUID (sizeof(UINT16) + 128)\r
++\r
++//\r
++// This define represents the combineds code and length field from\r
++// https://datatracker.ietf.org/doc/html/rfc3315#section-22.1\r
++//\r
++#define PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN \\r
++ (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode) + \\r
++ sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen))\r
++\r
+ #define GET_NEXT_DHCP6_OPTION(Opt) \\r
+ (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \\r
+ sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1)\r
+--
+2.41.0
+
+
+From bef5afa1c2c6868323332dbad0478b85830cd134 Mon Sep 17 00:00:00 2001
+From: Doug Flick <dougflick@microsoft.com>
+Date: Mon, 18 Dec 2023 12:49:26 -0800
+Subject: [PATCH 12/12] SECURITY PATCH TCBZ4540 - CVE-2023-45235 - Host Based
+ Unit Test
+
+---
+ NetworkPkg/Test/NetworkPkgHostTest.dsc | 11 +-
+ .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 871 ++++++++++++------
+ .../GoogleTest/PxeBcDhcp6GoogleTest.h | 18 +
+ .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 42 +-
+ .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 92 +-
+ 5 files changed, 661 insertions(+), 373 deletions(-)
+
+diff --git a/NetworkPkg/Test/NetworkPkgHostTest.dsc b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+index b9d031a611..e6c55692a1 100644
+--- a/NetworkPkg/Test/NetworkPkgHostTest.dsc
++++ b/NetworkPkg/Test/NetworkPkgHostTest.dsc
+@@ -26,7 +26,10 @@
+ #
+ 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]
+@@ -88,11 +91,9 @@
+ # This library provides the instrinsic functions generated by a given compiler.
+ # [LibraryClasses.ARM] and NULL mean link this library into all ARM images.
+ #
+- # MU_CHANGE Start
+-!if $(TOOL_CHAIN_TAG) != VS2017 and $(TOOL_CHAIN_TAG) != VS2015 and $(TOOL_CHAIN_TAG) != VS2019
+- NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
++!if $(TOOL_CHAIN_TAG) == VS2019 or $(TOOL_CHAIN_TAG) == VS2022
++ NULL|MdePkg/Library/CompilerIntrinsicsLib/ArmCompilerIntrinsicsLib.inf
+ !endif
+- # MU_CHANGE End
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
+ [LibraryClasses.ARM]
+ RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
+index 9ee805a284..665aff7d72 100644
+--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp
+@@ -1,301 +1,570 @@
+-/** @file\r
+- Host based unit test for PxeBcDhcp6.c.\r
+-\r
+- Copyright (c) Microsoft Corporation\r
+- SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-**/\r
+-#include <gtest/gtest.h>\r
+-\r
+-extern "C" {\r
+-#include <Uefi.h>\r
+-#include <Library/BaseLib.h>\r
+-#include <Library/DebugLib.h>\r
+-#include "../PxeBcImpl.h"\r
+-#include "../PxeBcDhcp6.h"\r
+-#include "PxeBcDhcp6GoogleTest.h"\r
+-}\r
+-\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-// Definitions\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-\r
+-#define PACKET_SIZE (1500)\r
+-\r
+-typedef struct {\r
+- UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03)\r
+- UINT16 OptionLen; // The length of the option (e.g., 16 bytes)\r
+- UINT8 ServerId[16]; // The 16-byte DHCPv6 Server Identifier\r
+-} DHCP6_OPTION_SERVER_ID;\r
+-\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-/// Symbol Definitions\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-\r
+-EFI_STATUS\r
+-MockUdpWrite (\r
+- IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+- IN UINT16 OpFlags,\r
+- IN EFI_IP_ADDRESS *DestIp,\r
+- IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort,\r
+- IN EFI_IP_ADDRESS *GatewayIp OPTIONAL,\r
+- IN EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
+- IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL,\r
+- IN UINTN *HeaderSize OPTIONAL,\r
+- IN VOID *HeaderPtr OPTIONAL,\r
+- IN UINTN *BufferSize,\r
+- IN VOID *BufferPtr\r
+- )\r
+-{\r
+- return EFI_SUCCESS;\r
+-}\r
+-\r
+-EFI_STATUS\r
+-MockUdpRead (\r
+- IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
+- IN UINT16 OpFlags,\r
+- IN OUT EFI_IP_ADDRESS *DestIp OPTIONAL,\r
+- IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort OPTIONAL,\r
+- IN OUT EFI_IP_ADDRESS *SrcIp OPTIONAL,\r
+- IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort OPTIONAL,\r
+- IN UINTN *HeaderSize OPTIONAL,\r
+- IN VOID *HeaderPtr OPTIONAL,\r
+- IN OUT UINTN *BufferSize,\r
+- IN VOID *BufferPtr\r
+- )\r
+-{\r
+- return EFI_SUCCESS;\r
+-}\r
+-\r
+-EFI_STATUS\r
+-MockConfigure (\r
+- IN EFI_UDP6_PROTOCOL *This,\r
+- IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL\r
+- )\r
+-{\r
+- return EFI_SUCCESS;\r
+-}\r
+-\r
+-// Needed by PxeBcSupport\r
+-EFI_STATUS\r
+-EFIAPI\r
+-QueueDpc (\r
+- IN EFI_TPL DpcTpl,\r
+- IN EFI_DPC_PROCEDURE DpcProcedure,\r
+- IN VOID *DpcContext OPTIONAL\r
+- )\r
+-{\r
+- return EFI_SUCCESS;\r
+-}\r
+-\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-// PxeBcHandleDhcp6OfferTest Tests\r
+-///////////////////////////////////////////////////////////////////////////////\r
+-\r
+-class PxeBcHandleDhcp6OfferTest : public ::testing::Test {\r
+-public:\r
+-PXEBC_PRIVATE_DATA Private = { 0 };\r
+-EFI_UDP6_PROTOCOL Udp6Read;\r
+-EFI_PXE_BASE_CODE_MODE Mode = { 0 };\r
+-\r
+-protected:\r
+-// Add any setup code if needed\r
+-virtual void\r
+-SetUp (\r
+- )\r
+-{\r
+- Private.Dhcp6Request = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE);\r
+-\r
+- // Need to setup the EFI_PXE_BASE_CODE_PROTOCOL\r
+- // The function under test really only needs the following:\r
+- // UdpWrite\r
+- // UdpRead\r
+-\r
+- Private.PxeBc.UdpWrite = (EFI_PXE_BASE_CODE_UDP_WRITE)MockUdpWrite;\r
+- Private.PxeBc.UdpRead = (EFI_PXE_BASE_CODE_UDP_READ)MockUdpRead;\r
+-\r
+- // Need to setup EFI_UDP6_PROTOCOL\r
+- // The function under test really only needs the following:\r
+- // Configure\r
+-\r
+- Udp6Read.Configure = (EFI_UDP6_CONFIGURE)MockConfigure;\r
+- Private.Udp6Read = &Udp6Read;\r
+-\r
+- // Need to setup the EFI_PXE_BASE_CODE_MODE\r
+- Private.PxeBc.Mode = &Mode;\r
+-\r
+- // for this test it doesn't really matter what the Dhcpv6 ack is set to\r
+-}\r
+-\r
+-// Add any cleanup code if needed\r
+-virtual void\r
+-TearDown (\r
+- )\r
+-{\r
+- if (Private.Dhcp6Request != NULL) {\r
+- FreePool (Private.Dhcp6Request);\r
+- }\r
+-\r
+- // Clean up any resources or variables\r
+-}\r
+-};\r
+-\r
+-// Note:\r
+-// Testing PxeBcHandleDhcp6Offer() is difficult because it depends on a\r
+-// properly setup Private structure. Attempting to properly test this function\r
+-// without a signficant refactor is a fools errand. Instead, we will test\r
+-// that we can prevent an overflow in the function.\r
+-TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) {\r
+- PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
+- EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
+-\r
+- Private.SelectIndex = 1; // SelectIndex is 1-based\r
+- Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
+-\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
+- // Setup the DHCPv6 offer packet\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337);\r
+-\r
+- ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR);\r
+-}\r
+-\r
+-class PxeBcCacheDnsServerAddressesTest : public ::testing::Test {\r
+-public:\r
+-PXEBC_PRIVATE_DATA Private = { 0 };\r
+-\r
+-protected:\r
+-// Add any setup code if needed\r
+-virtual void\r
+-SetUp (\r
+- )\r
+-{\r
+-}\r
+-\r
+-// Add any cleanup code if needed\r
+-virtual void\r
+-TearDown (\r
+- )\r
+-{\r
+-}\r
+-};\r
+-\r
+-// Test Description\r
+-// Test that we cache the DNS server address from the DHCPv6 offer packet\r
+-TEST_F (PxeBcCacheDnsServerAddressesTest, BasicUsageTest) {\r
+- UINT8 SearchPattern[16] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF };\r
+- EFI_DHCP6_PACKET_OPTION *Option;\r
+- PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
+-\r
+- Option = (EFI_DHCP6_PACKET_OPTION *)AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + sizeof (SearchPattern));\r
+- ASSERT_NE (Option, nullptr);\r
+-\r
+- Option->OpCode = DHCP6_OPT_SERVER_ID;\r
+- Option->OpLen = NTOHS (sizeof (SearchPattern));\r
+- CopyMem (Option->Data, SearchPattern, sizeof (SearchPattern));\r
+-\r
+- Private.SelectIndex = 1; // SelectIndex is 1-based\r
+- Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = Option;\r
+-\r
+- Private.DnsServer = nullptr;\r
+-\r
+- ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS);\r
+- ASSERT_NE (Private.DnsServer, nullptr);\r
+- ASSERT_EQ (CompareMem (Private.DnsServer, SearchPattern, sizeof (SearchPattern)), 0);\r
+-\r
+- if (Private.DnsServer) {\r
+- FreePool (Private.DnsServer);\r
+- }\r
+-\r
+- if (Option) {\r
+- FreePool (Option);\r
+- }\r
+-}\r
+-// Test Description\r
+-// Test that we can prevent an overflow in the function\r
+-TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptOverflowTest) {\r
+- EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
+- PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
+-\r
+- Private.SelectIndex = 1; // SelectIndex is 1-based\r
+- Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
+- // Setup the DHCPv6 offer packet\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (1337);\r
+-\r
+- Private.DnsServer = NULL;\r
+-\r
+- ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR);\r
+- ASSERT_EQ (Private.DnsServer, nullptr);\r
+-\r
+- if (Private.DnsServer) {\r
+- FreePool (Private.DnsServer);\r
+- }\r
+-}\r
+-\r
+-// Test Description\r
+-// Test that we can prevent an underflow in the function\r
+-TEST_F (PxeBcCacheDnsServerAddressesTest, AttemptUnderflowTest) {\r
+- EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
+- PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
+-\r
+- Private.SelectIndex = 1; // SelectIndex is 1-based\r
+- Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
+- // Setup the DHCPv6 offer packet\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (2);\r
+-\r
+- Private.DnsServer = NULL;\r
+-\r
+- ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_DEVICE_ERROR);\r
+- ASSERT_EQ (Private.DnsServer, nullptr);\r
+-\r
+- if (Private.DnsServer) {\r
+- FreePool (Private.DnsServer);\r
+- }\r
+-}\r
+-\r
+-\r
+-// Test Description\r
+-// Test that we can handle recursive dns (multiple dns entries)\r
+-TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) {\r
+- EFI_DHCP6_PACKET_OPTION Option = { 0 };\r
+- PXEBC_DHCP6_PACKET_CACHE *Cache6 = NULL;\r
+-\r
+- Private.SelectIndex = 1; // SelectIndex is 1-based\r
+- Cache6 = &Private.OfferBuffer[Private.SelectIndex - 1].Dhcp6;\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] = &Option;\r
+- // Setup the DHCPv6 offer packet\r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpCode = DHCP6_OPT_SERVER_ID;\r
+-\r
+- EFI_IPv6_ADDRESS addresses[2] = {\r
+- // 2001:db8:85a3::8a2e:370:7334\r
+- {0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},\r
+- // fe80::d478:91c3:ecd7:4ff9\r
+- {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x78, 0x91, 0xc3, 0xec, 0xd7, 0x4f, 0xf9}\r
+- };\r
+-\r
+-\r
+- CopyMem(Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, &addresses, sizeof(addresses));\r
+- \r
+- Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen = NTOHS (sizeof(addresses));\r
+-\r
+- Private.DnsServer = NULL;\r
+-\r
+- ASSERT_EQ (PxeBcCacheDnsServerAddresses (&(PxeBcCacheDnsServerAddressesTest::Private), Cache6), EFI_SUCCESS);\r
+-\r
+- ASSERT_NE (Private.DnsServer, nullptr);\r
+- \r
+- //\r
+- // This is expected to fail until DnsServer supports multiple DNS servers \r
+- //\r
+- // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886\r
+- //\r
+- ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0);\r
+-\r
+- if (Private.DnsServer) {\r
+- FreePool (Private.DnsServer);\r
+- }\r
+-}\r
++/** @file
++ Host based unit test for PxeBcDhcp6.c.
++
++ 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>
++#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
++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 (
++ 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
++ //
++ ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0);
++
++ if (Private.DnsServer) {
++ 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;
++
++ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_OUT_OF_RESOURCES);
++}
++
++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
++ );
++}
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
+index 724ee468cb..4d40594d51 100644
+--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h
+@@ -45,4 +45,22 @@ PxeBcCacheDnsServerAddresses (
+ IN PXEBC_DHCP6_PACKET_CACHE *Cache6\r
+ );\r
+ \r
++/**\r
++ Build and send out the request packet for the bootfile, and parse the reply.\r
++\r
++ @param[in] Private The pointer to PxeBc private data.\r
++ @param[in] Index PxeBc option boot item type.\r
++\r
++ @retval EFI_SUCCESS Successfully discovered the boot file.\r
++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
++ @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
++ @retval Others Failed to discover the boot file.\r
++\r
++**/\r
++EFI_STATUS\r
++PxeBcRequestBootService (\r
++ IN PXEBC_PRIVATE_DATA *Private,\r
++ IN UINT32 Index\r
++ );\r
++\r
+ #endif // __PXE_BC_DHCP6_GOOGLE_TEST_H__
+\ No newline at end of file
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
+index cc295f5c88..32270d0dcb 100644
+--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp
+@@ -1,21 +1,21 @@
+-/** @file\r
+- Acts as the main entry point for the tests for the UefiPxeBcDxe module.\r
+- Copyright (c) Microsoft Corporation\r
+- SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-**/\r
+-#include <gtest/gtest.h>\r
+-\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-// Add test files here\r
+-// Google Test will only pick up the tests from the files that are included\r
+-// here.\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-#include "PxeBcDhcp6GoogleTest.cpp"\r
+-\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-// Run the tests\r
+-////////////////////////////////////////////////////////////////////////////////\r
+-int main(int argc, char* argv[]) {\r
+- testing::InitGoogleTest (&argc, argv);\r
+- return RUN_ALL_TESTS ();\r
+-}
+\ No newline at end of file
++/** @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>
++
++////////////////////////////////////////////////////////////////////////////////
++// Add test files here
++// Google Test will only pick up the tests from the files that are included
++// here.
++////////////////////////////////////////////////////////////////////////////////
++#include "PxeBcDhcp6GoogleTest.cpp"
++
++////////////////////////////////////////////////////////////////////////////////
++// Run the tests
++////////////////////////////////////////////////////////////////////////////////
++int main(int argc, char* argv[]) {
++ testing::InitGoogleTest (&argc, argv);
++ return RUN_ALL_TESTS ();
++}
+diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
+index c2fd7ae7a9..2d23db0e46 100644
+--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf
+@@ -1,47 +1,47 @@
+-## @file\r
+-# Unit test suite for the UefiPxeBcDxe using Google Test\r
+-#\r
+-# Copyright (c) Microsoft Corporation.<BR>\r
+-# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+-##\r
+-[Defines]\r
+-INF_VERSION = 0x00010005\r
+-BASE_NAME = UefiPxeBcDxeGoogleTest\r
+-FILE_GUID = 77D45C64-EC1E-4174-887B-886E89FD1EDF\r
+-MODULE_TYPE = HOST_APPLICATION\r
+-VERSION_STRING = 1.0\r
+-\r
+-#\r
+-# The following information is for reference only and not required by the build tools.\r
+-#\r
+-# VALID_ARCHITECTURES = IA32 X64\r
+-#\r
+- \r
+-[Sources]\r
+- UefiPxeBcDxeGoogleTest.cpp\r
+- PxeBcDhcp6GoogleTest.cpp\r
+- ../PxeBcDhcp6.c\r
+- ../PxeBcSupport.c\r
+-\r
+-[Packages]\r
+- MdePkg/MdePkg.dec\r
+- MdeModulePkg/MdeModulePkg.dec\r
+- UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec\r
+- NetworkPkg/NetworkPkg.dec\r
+-\r
+-[LibraryClasses]\r
+- GoogleTestLib\r
+- DebugLib\r
+- NetLib\r
+- PcdLib\r
+-\r
+-[Protocols]\r
+- gEfiDhcp6ServiceBindingProtocolGuid\r
+- gEfiDns6ServiceBindingProtocolGuid\r
+- gEfiDns6ProtocolGuid\r
+-\r
+-[Pcd]\r
+- gEfiNetworkPkgTokenSpaceGuid.PcdDhcp6UidType\r
+-\r
+-[Guids]\r
++## @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
++ ../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
+\ No newline at end of file
+--
+2.41.0
+