]> git.proxmox.com Git - pve-edk2-firmware.git/commitdiff
cherry-pick patches for PXE CVEs
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 17 Jan 2024 07:59:17 +0000 (08:59 +0100)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 17 Jan 2024 07:59:17 +0000 (08:59 +0100)
CVE-2023-45229-CVE-2023-45237, taken from upstream announcement/issue at
https://bugzilla.tianocore.org/show_bug.cgi?id=4518

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
debian/patches/CVE-2023-45229_45237.patch [new file with mode: 0644]
debian/patches/series

diff --git a/debian/patches/CVE-2023-45229_45237.patch b/debian/patches/CVE-2023-45229_45237.patch
new file mode 100644 (file)
index 0000000..53dc806
--- /dev/null
@@ -0,0 +1,7277 @@
+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
+
index c18b4e8e0ec8a035aaa95b9c4f2832e76e3c3aae..a87e813eebef90835365de7ad92cebd8cb3db13c 100644 (file)
@@ -3,3 +3,4 @@ brotlicompress-disable.diff
 x64-baseline-abi.patch
 Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-executabl.patch
 ArmVirtPkg-disable-the-EFI_MEMORY_ATTRIBUTE-protocol.patch
+CVE-2023-45229_45237.patch