EFI_STATUS Status;\r
EFI_DHCP6_PACKET *IndexOffer;\r
UINT8 *Option;\r
+ UINTN DiscoverLenNeeded;\r
\r
PxeBc = &Private->PxeBc;\r
Request = Private->Dhcp6Request;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\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
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
(OpCode != DHCP6_OPT_SERVER_ID)\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
UINT16 OpLen;\r
UINT32 Xid;\r
EFI_STATUS Status;\r
+ UINTN DiscoverLenNeeded;\r
\r
PxeBc = &Private->PxeBc;\r
Mode = PxeBc->Mode;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));\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
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
+ 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
#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