Skip to content

Commit fac2977

Browse files
Flickdmmergify[bot]
authored andcommitted
NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Patch
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 Bug Details: PixieFail Bug #7 CVE-2023-45235 CVSS 8.3 : CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H CWE-119 Improper Restriction of Operations within the Bounds of a Memory Buffer Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message Change Overview: Performs two checks 1. Checks that the length of the duid is accurate > + // > + // Check that the minimum and maximum requirements are met > + // > + if ((OpLen < PXEBC_MIN_SIZE_OF_DUID) || (OpLen > PXEBC_MAX_SIZE_OF_DUID)) { > + Status = EFI_INVALID_PARAMETER; > + goto ON_ERROR; > + } 2. Ensures that the amount of data written to the buffer is tracked and never exceeds that > + // > + // Check that the option length is valid. > + // > + if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) { > + Status = EFI_OUT_OF_RESOURCES; > + goto ON_ERROR; > + } Additional code clean up and fix for memory leak in case Option was NULL Cc: Saloni Kasbekar <[email protected]> Cc: Zachary Clark-williams <[email protected]> Signed-off-by: Doug Flick [MSFT] <[email protected]> Reviewed-by: Saloni Kasbekar <[email protected]>
1 parent 7f04c7a commit fac2977

File tree

2 files changed

+78
-16
lines changed

2 files changed

+78
-16
lines changed

NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c

+61-16
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ PxeBcRequestBootService (
887887
EFI_STATUS Status;
888888
EFI_DHCP6_PACKET *IndexOffer;
889889
UINT8 *Option;
890+
UINTN DiscoverLenNeeded;
890891

891892
PxeBc = &Private->PxeBc;
892893
Request = Private->Dhcp6Request;
@@ -899,7 +900,8 @@ PxeBcRequestBootService (
899900
return EFI_DEVICE_ERROR;
900901
}
901902

902-
Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
903+
DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET);
904+
Discover = AllocateZeroPool (DiscoverLenNeeded);
903905
if (Discover == NULL) {
904906
return EFI_OUT_OF_RESOURCES;
905907
}
@@ -924,16 +926,34 @@ PxeBcRequestBootService (
924926
DHCP6_OPT_SERVER_ID
925927
);
926928
if (Option == NULL) {
927-
return EFI_NOT_FOUND;
929+
Status = EFI_NOT_FOUND;
930+
goto ON_ERROR;
928931
}
929932

930933
//
931934
// Add Server ID Option.
932935
//
933936
OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen);
934-
CopyMem (DiscoverOpt, Option, OpLen + 4);
935-
DiscoverOpt += (OpLen + 4);
936-
DiscoverLen += (OpLen + 4);
937+
938+
//
939+
// Check that the minimum and maximum requirements are met
940+
//
941+
if ((OpLen < PXEBC_MIN_SIZE_OF_DUID) || (OpLen > PXEBC_MAX_SIZE_OF_DUID)) {
942+
Status = EFI_INVALID_PARAMETER;
943+
goto ON_ERROR;
944+
}
945+
946+
//
947+
// Check that the option length is valid.
948+
//
949+
if ((DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN) > DiscoverLenNeeded) {
950+
Status = EFI_OUT_OF_RESOURCES;
951+
goto ON_ERROR;
952+
}
953+
954+
CopyMem (DiscoverOpt, Option, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
955+
DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
956+
DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
937957
}
938958

939959
while (RequestLen < Request->Length) {
@@ -944,16 +964,24 @@ PxeBcRequestBootService (
944964
(OpCode != DHCP6_OPT_SERVER_ID)
945965
)
946966
{
967+
//
968+
// Check that the option length is valid.
969+
//
970+
if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) {
971+
Status = EFI_OUT_OF_RESOURCES;
972+
goto ON_ERROR;
973+
}
974+
947975
//
948976
// Copy all the options except IA option and Server ID
949977
//
950-
CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
951-
DiscoverOpt += (OpLen + 4);
952-
DiscoverLen += (OpLen + 4);
978+
CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
979+
DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
980+
DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
953981
}
954982

955-
RequestOpt += (OpLen + 4);
956-
RequestLen += (OpLen + 4);
983+
RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
984+
RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
957985
}
958986

959987
//
@@ -2154,6 +2182,7 @@ PxeBcDhcp6Discover (
21542182
UINT16 OpLen;
21552183
UINT32 Xid;
21562184
EFI_STATUS Status;
2185+
UINTN DiscoverLenNeeded;
21572186

21582187
PxeBc = &Private->PxeBc;
21592188
Mode = PxeBc->Mode;
@@ -2169,7 +2198,8 @@ PxeBcDhcp6Discover (
21692198
return EFI_DEVICE_ERROR;
21702199
}
21712200

2172-
Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
2201+
DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET);
2202+
Discover = AllocateZeroPool (DiscoverLenNeeded);
21732203
if (Discover == NULL) {
21742204
return EFI_OUT_OF_RESOURCES;
21752205
}
@@ -2185,22 +2215,37 @@ PxeBcDhcp6Discover (
21852215
DiscoverLen = sizeof (EFI_DHCP6_HEADER);
21862216
RequestLen = DiscoverLen;
21872217

2218+
//
2219+
// The request packet is generated by the UEFI network stack. In the DHCP4 DORA and DHCP6 SARR sequence,
2220+
// the first (discover in DHCP4 and solicit in DHCP6) and third (request in both DHCP4 and DHCP6) are
2221+
// generated by the DHCP client (the UEFI network stack in this case). By the time this function executes,
2222+
// the DHCP sequence already has been executed once (see UEFI Specification Figures 24.2 and 24.3), with
2223+
// Private->Dhcp6Request being a cached copy of the DHCP6 request packet that UEFI network stack previously
2224+
// generated and sent.
2225+
//
2226+
// Therefore while this code looks like it could overflow, in practice it's not possible.
2227+
//
21882228
while (RequestLen < Request->Length) {
21892229
OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode);
21902230
OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen);
21912231
if ((OpCode != EFI_DHCP6_IA_TYPE_NA) &&
21922232
(OpCode != EFI_DHCP6_IA_TYPE_TA))
21932233
{
2234+
if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) {
2235+
Status = EFI_OUT_OF_RESOURCES;
2236+
goto ON_ERROR;
2237+
}
2238+
21942239
//
21952240
// Copy all the options except IA option.
21962241
//
2197-
CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
2198-
DiscoverOpt += (OpLen + 4);
2199-
DiscoverLen += (OpLen + 4);
2242+
CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
2243+
DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
2244+
DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
22002245
}
22012246

2202-
RequestOpt += (OpLen + 4);
2203-
RequestLen += (OpLen + 4);
2247+
RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
2248+
RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN);
22042249
}
22052250

22062251
Status = PxeBc->UdpWrite (

NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h

+17
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@
3434
#define PXEBC_ADDR_START_DELIMITER '['
3535
#define PXEBC_ADDR_END_DELIMITER ']'
3636

37+
//
38+
// A DUID consists of a 2-octet type code represented in network byte
39+
// order, followed by a variable number of octets that make up the
40+
// actual identifier. The length of the DUID (not including the type
41+
// code) is at least 1 octet and at most 128 octets.
42+
//
43+
#define PXEBC_MIN_SIZE_OF_DUID (sizeof(UINT16) + 1)
44+
#define PXEBC_MAX_SIZE_OF_DUID (sizeof(UINT16) + 128)
45+
46+
//
47+
// This define represents the combineds code and length field from
48+
// https://datatracker.ietf.org/doc/html/rfc3315#section-22.1
49+
//
50+
#define PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN \
51+
(sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode) + \
52+
sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen))
53+
3754
#define GET_NEXT_DHCP6_OPTION(Opt) \
3855
(EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \
3956
sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1)

0 commit comments

Comments
 (0)