From 1dbb10cc52dc8ef49bb700daa1cefc76b26d52e0 Mon Sep 17 00:00:00 2001
From: "Doug Flick via groups.io" <dougflick=microsoft.com@groups.io>
Date: Fri, 26 Jan 2024 05:54:46 +0800
Subject: [PATCH] NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534

Bug Details:
PixieFail Bug #1
CVE-2023-45229
CVSS 6.5 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
CWE-125 Out-of-bounds Read

Change Overview:

Introduce Dhcp6SeekInnerOptionSafe which performs checks before seeking
the Inner Option from a DHCP6 Option.

>
> EFI_STATUS
> Dhcp6SeekInnerOptionSafe (
>  IN  UINT16  IaType,
>  IN  UINT8   *Option,
>  IN  UINT32  OptionLen,
>  OUT UINT8   **IaInnerOpt,
>  OUT UINT16  *IaInnerLen
>  );
>

Lots of code cleanup to improve code readability.

Cc: Saloni Kasbekar <saloni.kasbekar@intel.com>
Cc: Zachary Clark-williams <zachary.clark-williams@intel.com>

Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com>
Reviewed-by: Saloni Kasbekar <saloni.kasbekar@intel.com>

CVE: CVE-2023-45229

Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1dbb10cc52dc8ef49bb700daa1cefc76b26d52e0]

Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
---
 NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 138 +++++++++++++++++++---
 NetworkPkg/Dhcp6Dxe/Dhcp6Io.c   | 203 +++++++++++++++++++++-----------
 2 files changed, 256 insertions(+), 85 deletions(-)

diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h
index f2422c2f28..220e7c68f1 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')
 #define DHCP6_INSTANCE_SIGNATURE  SIGNATURE_32 ('D', 'H', '6', 'I')
 
+#define DHCP6_PACKET_ALL        0
+#define DHCP6_PACKET_STATEFUL   1
+#define DHCP6_PACKET_STATELESS  2
+
+#define DHCP6_BASE_PACKET_SIZE  1024
+
+#define DHCP6_PORT_CLIENT  546
+#define DHCP6_PORT_SERVER  547
+
+#define DHCP_CHECK_MEDIA_WAITING_TIME  EFI_TIMER_PERIOD_SECONDS(20)
+
+#define DHCP6_INSTANCE_FROM_THIS(Instance)  CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE)
+#define DHCP6_SERVICE_FROM_THIS(Service)    CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE)
+
 //
 // For more information on DHCP options see RFC 8415, Section 21.1
 //
@@ -59,12 +73,10 @@ typedef struct _DHCP6_INSTANCE  DHCP6_INSTANCE;
 //    |                      (option-len octets)                      |
 //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //
-#define DHCP6_SIZE_OF_OPT_CODE  (sizeof(UINT16))
-#define DHCP6_SIZE_OF_OPT_LEN   (sizeof(UINT16))
+#define DHCP6_SIZE_OF_OPT_CODE  (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode))
+#define DHCP6_SIZE_OF_OPT_LEN   (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen))
 
-//
 // Combined size of Code and Length
-//
 #define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN  (DHCP6_SIZE_OF_OPT_CODE + \
                                               DHCP6_SIZE_OF_OPT_LEN)
 
@@ -73,34 +85,122 @@ STATIC_ASSERT (
   "Combined size of Code and Length must be 4 per RFC 8415"
   );
 
-//
 // Offset to the length is just past the code
-//
-#define DHCP6_OPT_LEN_OFFSET(a)  (a + DHCP6_SIZE_OF_OPT_CODE)
+#define DHCP6_OFFSET_OF_OPT_LEN(a)  (a + DHCP6_SIZE_OF_OPT_CODE)
 STATIC_ASSERT (
-  DHCP6_OPT_LEN_OFFSET (0) == 2,
+  DHCP6_OFFSET_OF_OPT_LEN (0) == 2,
   "Offset of length is + 2 past start of option"
   );
 
-#define DHCP6_OPT_DATA_OFFSET(a)  (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)
+#define DHCP6_OFFSET_OF_OPT_DATA(a)  (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)
 STATIC_ASSERT (
-  DHCP6_OPT_DATA_OFFSET (0) == 4,
+  DHCP6_OFFSET_OF_OPT_DATA (0) == 4,
   "Offset to option data should be +4 from start of option"
   );
+//
+// Identity Association options (both NA (Non-Temporary) and TA (Temporary Association))
+// are defined in RFC 8415 and are a deriviation of a TLV stucture
+// For more information on IA_NA see Section 21.4
+// For more information on IA_TA see Section 21.5
+//
+//
+//  The format of IA_NA and IA_TA option:
+//
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |          OPTION_IA_NA         |          option-len           |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |                        IAID (4 octets)                        |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |                        T1 (only for IA_NA)                    |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |                        T2 (only for IA_NA)                    |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |                                                               |
+//    .                  IA_NA-options/IA_TA-options                  .
+//    .                                                               .
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+#define DHCP6_SIZE_OF_IAID           (sizeof(UINT32))
+#define DHCP6_SIZE_OF_TIME_INTERVAL  (sizeof(UINT32))
 
-#define DHCP6_PACKET_ALL        0
-#define DHCP6_PACKET_STATEFUL   1
-#define DHCP6_PACKET_STATELESS  2
+// Combined size of IAID, T1, and T2
+#define DHCP6_SIZE_OF_COMBINED_IAID_T1_T2  (DHCP6_SIZE_OF_IAID +  \
+                                            DHCP6_SIZE_OF_TIME_INTERVAL + \
+                                            DHCP6_SIZE_OF_TIME_INTERVAL)
+STATIC_ASSERT (
+  DHCP6_SIZE_OF_COMBINED_IAID_T1_T2 == 12,
+  "Combined size of IAID, T1, T2 must be 12 per RFC 8415"
+  );
 
-#define DHCP6_BASE_PACKET_SIZE  1024
+// This is the size of IA_TA without options
+#define DHCP6_MIN_SIZE_OF_IA_TA  (DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \
+                                  DHCP6_SIZE_OF_IAID)
+STATIC_ASSERT (
+  DHCP6_MIN_SIZE_OF_IA_TA == 8,
+  "Minimum combined size of IA_TA per RFC 8415"
+  );
 
-#define DHCP6_PORT_CLIENT  546
-#define DHCP6_PORT_SERVER  547
+// Offset to a IA_TA inner option
+#define DHCP6_OFFSET_OF_IA_TA_INNER_OPT(a)  (a + DHCP6_MIN_SIZE_OF_IA_TA)
+STATIC_ASSERT (
+  DHCP6_OFFSET_OF_IA_TA_INNER_OPT (0) == 8,
+  "Offset of IA_TA Inner option is + 8 past start of option"
+  );
 
-#define DHCP_CHECK_MEDIA_WAITING_TIME  EFI_TIMER_PERIOD_SECONDS(20)
+// This is the size of IA_NA without options (16)
+#define DHCP6_MIN_SIZE_OF_IA_NA  DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \
+                                 DHCP6_SIZE_OF_COMBINED_IAID_T1_T2
+STATIC_ASSERT (
+  DHCP6_MIN_SIZE_OF_IA_NA == 16,
+  "Minimum combined size of IA_TA per RFC 8415"
+  );
 
-#define DHCP6_INSTANCE_FROM_THIS(Instance)  CR ((Instance), DHCP6_INSTANCE, Dhcp6, DHCP6_INSTANCE_SIGNATURE)
-#define DHCP6_SERVICE_FROM_THIS(Service)    CR ((Service), DHCP6_SERVICE, ServiceBinding, DHCP6_SERVICE_SIGNATURE)
+#define DHCP6_OFFSET_OF_IA_NA_INNER_OPT(a)  (a + DHCP6_MIN_SIZE_OF_IA_NA)
+STATIC_ASSERT (
+  DHCP6_OFFSET_OF_IA_NA_INNER_OPT (0) == 16,
+  "Offset of IA_NA Inner option is + 16 past start of option"
+  );
+
+#define DHCP6_OFFSET_OF_IA_NA_T1(a)  (a + \
+                                   DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + \
+                                   DHCP6_SIZE_OF_IAID)
+STATIC_ASSERT (
+  DHCP6_OFFSET_OF_IA_NA_T1 (0) == 8,
+  "Offset of IA_NA Inner option is + 8 past start of option"
+  );
+
+#define DHCP6_OFFSET_OF_IA_NA_T2(a)  (a + \
+                                   DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN +\
+                                   DHCP6_SIZE_OF_IAID + \
+                                   DHCP6_SIZE_OF_TIME_INTERVAL)
+STATIC_ASSERT (
+  DHCP6_OFFSET_OF_IA_NA_T2 (0) == 12,
+  "Offset of IA_NA Inner option is + 12 past start of option"
+  );
+
+//
+// For more information see RFC 8415 Section 21.13
+//
+// The format of the Status Code Option:
+//
+//     0                   1                   2                   3
+//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |       OPTION_STATUS_CODE      |         option-len            |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//    |          status-code          |                               |
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
+//    .                                                               .
+//    .                        status-message                         .
+//    .                                                               .
+//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+#define DHCP6_OFFSET_OF_STATUS_CODE(a)  (a + DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN)
+STATIC_ASSERT (
+  DHCP6_OFFSET_OF_STATUS_CODE (0) == 4,
+  "Offset of status is + 4 past start of option"
+  );
 
 extern EFI_IPv6_ADDRESS    mAllDhcpRelayAndServersAddress;
 extern EFI_DHCP6_PROTOCOL  gDhcp6ProtocolTemplate;
diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
index bf5aa7a769..89d16484a5 100644
--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
+++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c
@@ -598,8 +598,8 @@ Dhcp6UpdateIaInfo (
   // The inner options still start with 2 bytes option-code and 2 bytes option-len.
   //
   if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
-    T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 8)));
-    T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 12)));
+    T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T1 (Option))));
+    T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(DHCP6_OFFSET_OF_IA_NA_T2 (Option))));
     //
     // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
     // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
@@ -609,13 +609,14 @@ Dhcp6UpdateIaInfo (
       return EFI_DEVICE_ERROR;
     }
 
-    IaInnerOpt = Option + 16;
-    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 12);
+    IaInnerOpt = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option);
+    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_COMBINED_IAID_T1_T2);
   } else {
-    T1         = 0;
-    T2         = 0;
-    IaInnerOpt = Option + 8;
-    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 4);
+    T1 = 0;
+    T2 = 0;
+
+    IaInnerOpt = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option);
+    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_IAID);
   }
 
   //
@@ -641,7 +642,7 @@ Dhcp6UpdateIaInfo (
   Option  = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
 
   if (Option != NULL) {
-    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));
+    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option))));
     if (StsCode != Dhcp6StsSuccess) {
       return EFI_DEVICE_ERROR;
     }
@@ -661,6 +662,87 @@ Dhcp6UpdateIaInfo (
   return Status;
 }
 
+/**
+  Seeks the Inner Options from a DHCP6 Option
+
+  @param[in]  IaType          The type of the IA option.
+  @param[in]  Option          The pointer to the DHCP6 Option.
+  @param[in]  OptionLen       The length of the DHCP6 Option.
+  @param[out] IaInnerOpt      The pointer to the IA inner option.
+  @param[out] IaInnerLen      The length of the IA inner option.
+
+  @retval EFI_SUCCESS         Seek the inner option successfully.
+  @retval EFI_DEVICE_ERROR    The OptionLen is invalid. On Error,
+                              the pointers are not modified
+**/
+EFI_STATUS
+Dhcp6SeekInnerOptionSafe (
+  IN  UINT16  IaType,
+  IN  UINT8   *Option,
+  IN  UINT32  OptionLen,
+  OUT UINT8   **IaInnerOpt,
+  OUT UINT16  *IaInnerLen
+  )
+{
+  UINT16  IaInnerLenTmp;
+  UINT8   *IaInnerOptTmp;
+
+  if (Option == NULL) {
+    ASSERT (Option != NULL);
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (IaInnerOpt == NULL) {
+    ASSERT (IaInnerOpt != NULL);
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (IaInnerLen == NULL) {
+    ASSERT (IaInnerLen != NULL);
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (IaType == Dhcp6OptIana) {
+    // Verify we have a fully formed IA_NA
+    if (OptionLen < DHCP6_MIN_SIZE_OF_IA_NA) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    IaInnerOptTmp = DHCP6_OFFSET_OF_IA_NA_INNER_OPT (Option);
+
+    // Verify the IaInnerLen is valid.
+    IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)DHCP6_OFFSET_OF_OPT_LEN (Option)));
+    if (IaInnerLenTmp < DHCP6_SIZE_OF_COMBINED_IAID_T1_T2) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    IaInnerLenTmp -= DHCP6_SIZE_OF_COMBINED_IAID_T1_T2;
+  } else if (IaType == Dhcp6OptIata) {
+    // Verify the OptionLen is valid.
+    if (OptionLen < DHCP6_MIN_SIZE_OF_IA_TA) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    IaInnerOptTmp = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option);
+
+    // Verify the IaInnerLen is valid.
+    IaInnerLenTmp = (UINT16)NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option))));
+    if (IaInnerLenTmp < DHCP6_SIZE_OF_IAID) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    IaInnerLenTmp -= DHCP6_SIZE_OF_IAID;
+  } else {
+    return EFI_DEVICE_ERROR;
+  }
+
+  *IaInnerOpt = IaInnerOptTmp;
+  *IaInnerLen = IaInnerLenTmp;
+
+  return EFI_SUCCESS;
+}
+
 /**
   Seek StatusCode Option in package. A Status Code option may appear in the
   options field of a DHCP message and/or in the options field of another option.
@@ -684,6 +766,12 @@ Dhcp6SeekStsOption (
   UINT8   *IaInnerOpt;
   UINT16  IaInnerLen;
   UINT16  StsCode;
+  UINT32  OptionLen;
+
+  // OptionLen is the length of the Options excluding the DHCP header.
+  // Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last
+  // byte of the Option[] field.
+  OptionLen = Packet->Length - sizeof (Packet->Dhcp6.Header);
 
   //
   // Seek StatusCode option directly in DHCP message body. That is, search in
@@ -691,12 +779,12 @@ Dhcp6SeekStsOption (
   //
   *Option = Dhcp6SeekOption (
               Packet->Dhcp6.Option,
-              Packet->Length - 4,
+              OptionLen,
               Dhcp6OptStatusCode
               );
 
   if (*Option != NULL) {
-    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));
+    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_STATUS_CODE (*Option))));
     if (StsCode != Dhcp6StsSuccess) {
       return EFI_DEVICE_ERROR;
     }
@@ -707,7 +795,7 @@ Dhcp6SeekStsOption (
   //
   *Option = Dhcp6SeekIaOption (
               Packet->Dhcp6.Option,
-              Packet->Length - sizeof (EFI_DHCP6_HEADER),
+              OptionLen,
               &Instance->Config->IaDescriptor
               );
   if (*Option == NULL) {
@@ -715,52 +803,35 @@ Dhcp6SeekStsOption (
   }
 
   //
-  // The format of the IA_NA option is:
+  // Calculate the distance from Packet->Dhcp6.Option to the IA option.
   //
-  //     0                   1                   2                   3
-  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |          OPTION_IA_NA         |          option-len           |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                        IAID (4 octets)                        |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                              T1                               |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                              T2                               |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                                                               |
-  //    .                         IA_NA-options                         .
-  //    .                                                               .
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // Packet->Size and Packet->Length are both UINT32 type, and Packet->Size is
+  // the size of the whole packet, including the DHCP header, and Packet->Length
+  // is the length of the DHCP message body, excluding the DHCP header.
   //
-  // The format of the IA_TA option is:
+  // (*Option - Packet->Dhcp6.Option) is the number of bytes from the start of
+  // DHCP6 option area to the start of the IA option.
   //
-  //     0                   1                   2                   3
-  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |         OPTION_IA_TA          |          option-len           |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                        IAID (4 octets)                        |
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-  //    |                                                               |
-  //    .                         IA_TA-options                         .
-  //    .                                                               .
-  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  // Dhcp6SeekInnerOptionSafe() is searching starting from the start of the
+  // IA option to the end of the DHCP6 option area, thus subtract the space
+  // up until this option
   //
+  OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option);
 
   //
-  // sizeof (option-code + option-len + IaId)           = 8
-  // sizeof (option-code + option-len + IaId + T1)      = 12
-  // sizeof (option-code + option-len + IaId + T1 + T2) = 16
-  //
-  // The inner options still start with 2 bytes option-code and 2 bytes option-len.
+  // Seek the inner option
   //
-  if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
-    IaInnerOpt = *Option + 16;
-    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 12);
-  } else {
-    IaInnerOpt = *Option + 8;
-    IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 4);
+  if (EFI_ERROR (
+        Dhcp6SeekInnerOptionSafe (
+          Instance->Config->IaDescriptor.Type,
+          *Option,
+          OptionLen,
+          &IaInnerOpt,
+          &IaInnerLen
+          )
+        ))
+  {
+    return EFI_DEVICE_ERROR;
   }
 
   //
@@ -784,7 +855,7 @@ Dhcp6SeekStsOption (
   //
   *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
   if (*Option != NULL) {
-    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));
+    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (*Option)))));
     if (StsCode != Dhcp6StsSuccess) {
       return EFI_DEVICE_ERROR;
     }
@@ -1105,7 +1176,7 @@ Dhcp6SendRequestMsg (
   //
   Option = Dhcp6SeekOption (
              Instance->AdSelect->Dhcp6.Option,
-             Instance->AdSelect->Length - 4,
+             Instance->AdSelect->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptServerId
              );
   if (Option == NULL) {
@@ -1289,7 +1360,7 @@ Dhcp6SendDeclineMsg (
   //
   Option = Dhcp6SeekOption (
              LastReply->Dhcp6.Option,
-             LastReply->Length - 4,
+             LastReply->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptServerId
              );
   if (Option == NULL) {
@@ -1448,7 +1519,7 @@ Dhcp6SendReleaseMsg (
   //
   Option = Dhcp6SeekOption (
              LastReply->Dhcp6.Option,
-             LastReply->Length - 4,
+             LastReply->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptServerId
              );
   if (Option == NULL) {
@@ -1673,7 +1744,7 @@ Dhcp6SendRenewRebindMsg (
 
     Option = Dhcp6SeekOption (
                LastReply->Dhcp6.Option,
-               LastReply->Length - 4,
+               LastReply->Length - sizeof (EFI_DHCP6_HEADER),
                Dhcp6OptServerId
                );
     if (Option == NULL) {
@@ -2208,7 +2279,7 @@ Dhcp6HandleReplyMsg (
   //
   Option = Dhcp6SeekOption (
              Packet->Dhcp6.Option,
-             Packet->Length - 4,
+             Packet->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptRapidCommit
              );
 
@@ -2354,7 +2425,7 @@ Dhcp6HandleReplyMsg (
     //
     // Any error status code option is found.
     //
-    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));
+    StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)((DHCP6_OFFSET_OF_STATUS_CODE (Option)))));
     switch (StsCode) {
       case Dhcp6StsUnspecFail:
         //
@@ -2487,7 +2558,7 @@ Dhcp6SelectAdvertiseMsg (
   //
   Option = Dhcp6SeekOption (
              AdSelect->Dhcp6.Option,
-             AdSelect->Length - 4,
+             AdSelect->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptServerUnicast
              );
 
@@ -2498,7 +2569,7 @@ Dhcp6SelectAdvertiseMsg (
       return EFI_OUT_OF_RESOURCES;
     }
 
-    CopyMem (Instance->Unicast, Option + 4, sizeof (EFI_IPv6_ADDRESS));
+    CopyMem (Instance->Unicast, DHCP6_OFFSET_OF_OPT_DATA (Option), sizeof (EFI_IPv6_ADDRESS));
   }
 
   //
@@ -2551,7 +2622,7 @@ Dhcp6HandleAdvertiseMsg (
   //
   Option = Dhcp6SeekOption (
              Packet->Dhcp6.Option,
-             Packet->Length - 4,
+             Packet->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptRapidCommit
              );
 
@@ -2645,7 +2716,7 @@ Dhcp6HandleAdvertiseMsg (
       CopyMem (Instance->AdSelect, Packet, Packet->Size);
 
       if (Option != NULL) {
-        Instance->AdPref = *(Option + 4);
+        Instance->AdPref = *(DHCP6_OFFSET_OF_OPT_DATA (Option));
       }
     } else {
       //
@@ -2714,11 +2785,11 @@ Dhcp6HandleStateful (
   //
   Option = Dhcp6SeekOption (
              Packet->Dhcp6.Option,
-             Packet->Length - 4,
+             Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN,
              Dhcp6OptClientId
              );
 
-  if ((Option == NULL) || (CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0)) {
+  if ((Option == NULL) || (CompareMem (DHCP6_OFFSET_OF_OPT_DATA (Option), ClientId->Duid, ClientId->Length) != 0)) {
     goto ON_CONTINUE;
   }
 
@@ -2727,7 +2798,7 @@ Dhcp6HandleStateful (
   //
   Option = Dhcp6SeekOption (
              Packet->Dhcp6.Option,
-             Packet->Length - 4,
+             Packet->Length - DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN,
              Dhcp6OptServerId
              );
 
@@ -2832,7 +2903,7 @@ Dhcp6HandleStateless (
   //
   Option = Dhcp6SeekOption (
              Packet->Dhcp6.Option,
-             Packet->Length - 4,
+             Packet->Length - sizeof (EFI_DHCP6_HEADER),
              Dhcp6OptServerId
              );
 
-- 
2.40.0

