From patchwork Thu Jul 11 04:55:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46190 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9E29CC3271E for ; Thu, 11 Jul 2024 04:56:08 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web10.4971.1720673763628059277 for ; Wed, 10 Jul 2024 21:56:03 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250809.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4f2pR015514 for ; Wed, 10 Jul 2024 21:56:03 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4075eg48ns-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:02 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:55:59 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 01/11] ovmf: Fix CVE-2022-36763 Date: Thu, 11 Jul 2024 04:55:31 +0000 Message-ID: <20240711045541.2155076-1-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: rq33zvKv5a_1z3oob6TUQFzfUDby27kr X-Proofpoint-ORIG-GUID: rq33zvKv5a_1z3oob6TUQFzfUDby27kr X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 malwarescore=0 clxscore=1011 adultscore=0 bulkscore=0 mlxscore=0 spamscore=0 mlxlogscore=999 suspectscore=0 phishscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:08 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201751 From: Soumya Sambu EDK2 is susceptible to a vulnerability in the Tcg2MeasureGptTable() function, allowing a user to trigger a heap buffer overflow via a local network. Successful exploitation of this vulnerability may result in a compromise of confidentiality, integrity, and/or availability. References: https://nvd.nist.gov/vuln/detail/CVE-2022-36763 Upstream-patches: https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3 https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2022-36763-0001.patch | 985 ++++++++++++++++++ .../ovmf/ovmf/CVE-2022-36763-0002.patch | 889 ++++++++++++++++ .../ovmf/ovmf/CVE-2022-36763-0003.patch | 55 + meta/recipes-core/ovmf/ovmf_git.bb | 3 + 4 files changed, 1932 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch new file mode 100644 index 0000000000..93cefe7740 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0001.patch @@ -0,0 +1,985 @@ +From 224446543206450ddb5830e6abd026d61d3c7f4b Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:01 +0800 +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4117 - CVE + 2022-36763 + +This commit contains the patch files and tests for DxeTpm2MeasureBootLib +CVE 2022-36763. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/224446543206450ddb5830e6abd026d61d3c7f4b] + +Signed-off-by: Soumya Sambu +--- + .../DxeTpm2MeasureBootLib.c | 69 ++-- + .../DxeTpm2MeasureBootLib.inf | 4 +- + .../DxeTpm2MeasureBootLibSanitization.c | 275 ++++++++++++++++ + .../DxeTpm2MeasureBootLibSanitization.h | 113 +++++++ + .../DxeTpm2MeasureBootLibSanitizationTest.c | 303 ++++++++++++++++++ + ...Tpm2MeasureBootLibSanitizationTestHost.inf | 28 ++ + SecurityPkg/SecurityPkg.ci.yaml | 1 + + 7 files changed, 763 insertions(+), 30 deletions(-) + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c + create mode 100644 SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf + +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +index 36a256a7af..0475103d6e 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +@@ -20,6 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + ++Copyright (c) Microsoft Corporation.
++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include +@@ -44,6 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ + typedef struct { + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; +@@ -144,10 +148,11 @@ Tcg2MeasureGptTable ( + EFI_TCG2_EVENT *Tcg2Event; + EFI_CC_EVENT *CcEvent; + EFI_GPT_DATA *GptData; +- UINT32 EventSize; ++ UINT32 TcgEventSize; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; + EFI_CC_MR_INDEX MrIndex; ++ UINT32 AllocSize; + + if (mTcg2MeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -195,25 +200,22 @@ Tcg2MeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + + // +- // PrimaryHeader->SizeOfPartitionEntry should not be zero ++ // Read the partition entry. + // +- if (PrimaryHeader->SizeOfPartitionEntry == 0) { +- DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry should not be zero!\n")); ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + return EFI_BAD_BUFFER_SIZE; + } + +- // +- // Read the partition entry. +- // +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -223,7 +225,7 @@ Tcg2MeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -248,16 +250,21 @@ Tcg2MeasureGptTable ( + // + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) + // +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); +- EventPtr = (UINT8 *)AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ FreePool (EntryPtr); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); + if (EventPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); ++ Tcg2Event->Size = TcgEventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = 5; +@@ -310,7 +317,7 @@ Tcg2MeasureGptTable ( + CcProtocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)EventSize, ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + CcEvent + ); + if (!EFI_ERROR (Status)) { +@@ -326,7 +333,7 @@ Tcg2MeasureGptTable ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)EventSize, ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + Tcg2Event + ); + if (!EFI_ERROR (Status)) { +@@ -443,11 +450,13 @@ Tcg2MeasurePeImage ( + Tcg2Event->Header.PCRIndex = 2; + break; + default: +- DEBUG (( +- DEBUG_ERROR, +- "Tcg2MeasurePeImage: Unknown subsystem type %d", +- ImageType +- )); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +@@ -515,7 +524,7 @@ Finish: + + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. + +- @retval EFI_SUCCESS Sucessfully locate the measure boot protocol instances (at least one instance). ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). + @retval EFI_UNSUPPORTED Measure boot is not supported. + **/ + EFI_STATUS +@@ -646,12 +655,14 @@ DxeTpm2MeasureBootHandler ( + return EFI_SUCCESS; + } + +- DEBUG (( +- DEBUG_INFO, +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", +- MeasureBootProtocols.Tcg2Protocol, +- MeasureBootProtocols.CcProtocol +- )); ++ DEBUG ( ++ ( ++ DEBUG_INFO, ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", ++ MeasureBootProtocols.Tcg2Protocol, ++ MeasureBootProtocols.CcProtocol ++ ) ++ ); + + // + // Copy File Device Path +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf +index 6dca79a20c..28995f438d 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf +@@ -37,6 +37,8 @@ + + [Sources] + DxeTpm2MeasureBootLib.c ++ DxeTpm2MeasureBootLibSanitization.c ++ DxeTpm2MeasureBootLibSanitization.h + + [Packages] + MdePkg/MdePkg.dec +@@ -46,6 +48,7 @@ + + [LibraryClasses] + BaseMemoryLib ++ SafeIntLib + DebugLib + MemoryAllocationLib + DevicePathLib +@@ -65,4 +68,3 @@ + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES +- +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +new file mode 100644 +index 0000000000..e2309655d3 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +@@ -0,0 +1,275 @@ ++/** @file ++ The library instance provides security service of TPM2 measure boot and ++ Confidential Computing (CC) measure boot. ++ ++ Caution: This file requires additional review when modified. ++ This library will have external input - PE/COFF image and GPT partition. ++ This external input must be validated carefully to avoid security issue like ++ buffer overflow, integer overflow. ++ ++ This file will pull out the validation logic from the following functions, in an ++ attempt to validate the untrusted input in the form of unit tests ++ ++ These are those functions: ++ ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ ++#define GPT_HEADER_REVISION_V1 0x00010000 ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ) ++{ ++ // ++ // Verify that the input parameters are safe to use ++ // ++ if (PrimaryHeader == NULL) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) ++ // ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) ++ // ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size ++ // ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // The partition entries should all be before the first usable block ++ // ++ if (PrimaryHeader->FirstUsableLBA <= PrimaryHeader->PartitionEntryLBA) { ++ DEBUG ((DEBUG_ERROR, "GPT PartitionEntryLBA is not less than FirstUsableLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // Check that the PartitionEntryLBA greater than the Max LBA ++ // This will be used later for multiplication ++ // ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // Check that the number of partition entries is greater than zero ++ // ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory ++ // ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // This check is to prevent overflow when calculating the allocation size for the partition entries ++ // This check will be used later for multiplication ++ // ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (AllocationSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Replacing logic: ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; ++ // ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) ++ from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINT32 SafeNumberOfPartitions; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (EventSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 ++ // ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Replacing logic: ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ // ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ // ++ // Replacing logic: ++ // *EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); ++ // ++ Status = SafeUint32Add ( ++ OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions), ++ *EventSize, ++ EventSize ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +new file mode 100644 +index 0000000000..048b738987 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +@@ -0,0 +1,113 @@ ++/** @file ++ This file includes the function prototypes for the sanitization functions. ++ ++ These are those functions: ++ ++ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ ++#define DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ); ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ); ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including ++ (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) . When hashing the buffer allocated with this ++ size, the caller must subtract the size of the (sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)) ++ from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ); ++ ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +new file mode 100644 +index 0000000000..3eb9763e3c +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +@@ -0,0 +1,303 @@ ++/** @file ++ This file includes the unit test cases for the DxeTpm2MeasureBootLibSanitizationTest.c. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../DxeTpm2MeasureBootLibSanitization.h" ++ ++#define UNIT_TEST_NAME "DxeTpm2MeasureBootLibSanitizationTest" ++#define UNIT_TEST_VERSION "1.0" ++ ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 ++ ++/** ++ This function tests the SanitizeEfiPartitionTableHeader function. ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER ++ structure will not cause undefined or unexpected behavior. ++ ++ In general the TPM should still be able to measure the data, but ++ be the header should be sanitized to prevent any unexpected behavior. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizeEfiPartitionTableHeader ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ EFI_BLOCK_IO_PROTOCOL BlockIo; ++ EFI_BLOCK_IO_MEDIA BlockMedia; ++ ++ // Generate EFI_BLOCK_IO_MEDIA test data ++ BlockMedia.MediaId = 1; ++ BlockMedia.RemovableMedia = FALSE; ++ BlockMedia.MediaPresent = TRUE; ++ BlockMedia.LogicalPartition = FALSE; ++ BlockMedia.ReadOnly = FALSE; ++ BlockMedia.WriteCaching = FALSE; ++ BlockMedia.BlockSize = 512; ++ BlockMedia.IoAlign = 1; ++ BlockMedia.LastBlock = 0; ++ ++ // Generate EFI_BLOCK_IO_PROTOCOL test data ++ BlockIo.Revision = 1; ++ BlockIo.Media = &BlockMedia; ++ BlockIo.Reset = NULL; ++ BlockIo.ReadBlocks = NULL; ++ BlockIo.WriteBlocks = NULL; ++ BlockIo.FlushBlocks = NULL; ++ ++ // Geneate EFI_PARTITION_TABLE_HEADER test data ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ PrimaryHeader.MyLBA = 1; ++ PrimaryHeader.AlternateLBA = 2; ++ PrimaryHeader.FirstUsableLBA = 3; ++ PrimaryHeader.LastUsableLBA = 4; ++ PrimaryHeader.PartitionEntryLBA = 5; ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid ++ ++ // Calculate the CRC32 of the PrimaryHeader ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); ++ ++ // Test that a normal PrimaryHeader passes validation ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" ++ PrimaryHeader.NumberOfPartitionEntries = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header Size!" ++ PrimaryHeader.Header.HeaderSize = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" ++ PrimaryHeader.SizeOfPartitionEntry = 1; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderAllocationSize function. ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER ++ structure will not cause an overflow when calculating the allocation size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderAllocationSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 AllocationSize; ++ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that the allocation size is correct compared to the existing logic ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Test that an overflow is detected ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = 5; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the inverse ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the worst case scenario ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderGptEventSize function. ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure ++ will not cause an overflow when calculating the event size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderGptEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINT32 ExistingLogicEventSize; ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ UINTN NumberOfPartition; ++ EFI_GPT_DATA *GptData; ++ EFI_TCG2_EVENT *Tcg2Event; ++ ++ Tcg2Event = NULL; ++ GptData = NULL; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // set the number of partitions ++ NumberOfPartition = 13; ++ ++ // that the primary event size is correct ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Calculate the existing logic event size ++ ExistingLogicEventSize = (UINT32)(OFFSET_OF (EFI_TCG2_EVENT, Event) + OFFSET_OF (EFI_GPT_DATA, Partitions) ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Check that the event size is correct ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); ++ ++ // Tests that the primary event size may not overflow ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test that the size of partition entries may not overflow ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++// *--------------------------------------------------------------------* ++// * Unit Test Code Main Function ++// *--------------------------------------------------------------------* ++ ++/** ++ This function acts as the entry point for the unit tests. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++ @retval others The test failed. ++**/ ++EFI_STATUS ++EFIAPI ++UefiTestMain ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; ++ UNIT_TEST_SUITE_HANDLE Tcg2MeasureBootLibValidationTestSuite; ++ ++ Framework = NULL; ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); ++ ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); ++ goto EXIT; ++ } ++ ++ Status = CreateUnitTestSuite (&Tcg2MeasureBootLibValidationTestSuite, Framework, "Tcg2MeasureBootLibValidationTestSuite", "Common.Tcg2MeasureBootLibValidation", NULL, NULL); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for Tcg2MeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); ++ Status = EFI_OUT_OF_RESOURCES; ++ goto EXIT; ++ } ++ ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ ++ Status = RunAllTestSuites (Framework); ++ ++EXIT: ++ if (Framework != NULL) { ++ FreeUnitTestFramework (Framework); ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); ++ return Status; ++} ++ ++/// ++/// Avoid ECC error for function name that starts with lower case letter ++/// ++#define DxeTpm2MeasureBootLibUnitTestMain main ++ ++/** ++ Standard POSIX C entry point for host based unit test execution. ++ ++ @param[in] Argc Number of arguments ++ @param[in] Argv Array of pointers to arguments ++ ++ @retval 0 Success ++ @retval other Error ++**/ ++INT32 ++DxeTpm2MeasureBootLibUnitTestMain ( ++ IN INT32 Argc, ++ IN CHAR8 *Argv[] ++ ) ++{ ++ return (INT32)UefiTestMain (); ++} +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf +new file mode 100644 +index 0000000000..2999aa2a44 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTestHost.inf +@@ -0,0 +1,28 @@ ++## @file ++# This file builds the unit tests for DxeTpm2MeasureBootLib ++# ++# Copyright (C) Microsoft Corporation.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 0x00010006 ++ BASE_NAME = DxeTpm2MeasuredBootLibTest ++ FILE_GUID = 144d757f-d423-484e-9309-a23695fad5bd ++ MODULE_TYPE = HOST_APPLICATION ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = main ++ ++[Sources] ++ DxeTpm2MeasureBootLibSanitizationTest.c ++ ../DxeTpm2MeasureBootLibSanitization.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UnitTestLib ++ PrintLib ++ SafeIntLib +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml +index 7912142398..da811fdf93 100644 +--- a/SecurityPkg/SecurityPkg.ci.yaml ++++ b/SecurityPkg/SecurityPkg.ci.yaml +@@ -15,6 +15,7 @@ + ## "", "" + ## ] + "ExceptionList": [ ++ "8001", "DxeTpm2MeasureBootLibUnitTestMain", + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch new file mode 100644 index 0000000000..6c20cc305e --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0002.patch @@ -0,0 +1,889 @@ +From 4776a1b39ee08fc45c70c1eab5a0195f325000d3 Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:02 +0800 +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4117 - CVE + 2022-36763 + +This commit contains the patch files and tests for DxeTpmMeasureBootLib +CVE 2022-36763. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Jiewen Yao + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4776a1b39ee08fc45c70c1eab5a0195f325000d3] + +Signed-off-by: Soumya Sambu +--- + .../DxeTpmMeasureBootLib.c | 40 ++- + .../DxeTpmMeasureBootLib.inf | 4 +- + .../DxeTpmMeasureBootLibSanitization.c | 241 ++++++++++++++ + .../DxeTpmMeasureBootLibSanitization.h | 114 +++++++ + .../DxeTpmMeasureBootLibSanitizationTest.c | 301 ++++++++++++++++++ + ...eTpmMeasureBootLibSanitizationTestHost.inf | 28 ++ + SecurityPkg/SecurityPkg.ci.yaml | 1 + + 7 files changed, 715 insertions(+), 14 deletions(-) + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c + create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf + +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +index 220393dd2b..669ab19134 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +@@ -18,6 +18,8 @@ + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + ++Copyright (c) Microsoft Corporation.
++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include +@@ -40,6 +42,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + ++#include "DxeTpmMeasureBootLibSanitization.h" ++ + // + // Flag to check GPT partition. It only need be measured once. + // +@@ -136,6 +140,9 @@ TcgMeasureGptTable ( + UINT32 EventSize; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; ++ UINT32 AllocSize; ++ ++ GptData = NULL; + + if (mMeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -166,8 +173,8 @@ TcgMeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_ERROR, "Failed to Read Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } +@@ -175,7 +182,13 @@ TcgMeasureGptTable ( + // + // Read the partition entry. + // +- EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); ++ Status = SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -185,7 +198,7 @@ TcgMeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -210,9 +223,8 @@ TcgMeasureGptTable ( + // + // Prepare Data for Measurement + // +- EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) +- + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); +- TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT_HDR)); ++ Status = SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &EventSize); ++ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (EventSize); + if (TcgEvent == NULL) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); +@@ -221,7 +233,7 @@ TcgMeasureGptTable ( + + TcgEvent->PCRIndex = 5; + TcgEvent->EventType = EV_EFI_GPT_EVENT; +- TcgEvent->EventSize = EventSize; ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); + GptData = (EFI_GPT_DATA *)TcgEvent->Event; + + // +@@ -361,11 +373,13 @@ TcgMeasurePeImage ( + TcgEvent->PCRIndex = 2; + break; + default: +- DEBUG (( +- DEBUG_ERROR, +- "TcgMeasurePeImage: Unknown subsystem type %d", +- ImageType +- )); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "TcgMeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf +index ebab6f7c1e..414c654d15 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf +@@ -32,6 +32,8 @@ + + [Sources] + DxeTpmMeasureBootLib.c ++ DxeTpmMeasureBootLibSanitization.c ++ DxeTpmMeasureBootLibSanitization.h + + [Packages] + MdePkg/MdePkg.dec +@@ -41,6 +43,7 @@ + + [LibraryClasses] + BaseMemoryLib ++ SafeIntLib + DebugLib + MemoryAllocationLib + DevicePathLib +@@ -59,4 +62,3 @@ + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES +- +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +new file mode 100644 +index 0000000000..a3fa46f5e6 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +@@ -0,0 +1,241 @@ ++/** @file ++ The library instance provides security service of TPM2 measure boot and ++ Confidential Computing (CC) measure boot. ++ ++ Caution: This file requires additional review when modified. ++ This library will have external input - PE/COFF image and GPT partition. ++ This external input must be validated carefully to avoid security issue like ++ buffer overflow, integer overflow. ++ ++ This file will pull out the validation logic from the following functions, in an ++ attempt to validate the untrusted input in the form of unit tests ++ ++ These are those functions: ++ ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "DxeTpmMeasureBootLibSanitization.h" ++ ++#define GPT_HEADER_REVISION_V1 0x00010000 ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ) ++{ ++ // Verify that the input parameters are safe to use ++ if (PrimaryHeader == NULL) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((BlockIo == NULL) || (BlockIo->Media == NULL)) { ++ DEBUG ((DEBUG_ERROR, "Invalid BlockIo!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The signature must be EFI_PTAB_HEADER_ID ("EFI PART" in ASCII) ++ if (PrimaryHeader->Header.Signature != EFI_PTAB_HEADER_ID) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // The version must be GPT_HEADER_REVISION_V1 (0x00010000) ++ if (PrimaryHeader->Header.Revision != GPT_HEADER_REVISION_V1) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header Revision!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // The HeaderSize must be greater than or equal to 92 and must be less than or equal to the logical block size ++ if ((PrimaryHeader->Header.HeaderSize < sizeof (EFI_PARTITION_TABLE_HEADER)) || (PrimaryHeader->Header.HeaderSize > BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header HeaderSize!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // check that the PartitionEntryLBA greater than the Max LBA ++ // This will be used later for multiplication ++ if (PrimaryHeader->PartitionEntryLBA > DivU64x32 (MAX_UINT64, BlockIo->Media->BlockSize)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header PartitionEntryLBA!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // Check that the number of partition entries is greater than zero ++ if (PrimaryHeader->NumberOfPartitionEntries == 0) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // SizeOfPartitionEntry must be 128, 256, 512... improper size may lead to accessing uninitialized memory ++ if ((PrimaryHeader->SizeOfPartitionEntry < 128) || ((PrimaryHeader->SizeOfPartitionEntry & (PrimaryHeader->SizeOfPartitionEntry - 1)) != 0)) { ++ DEBUG ((DEBUG_ERROR, "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // This check is to prevent overflow when calculating the allocation size for the partition entries ++ // This check will be used later for multiplication ++ if (PrimaryHeader->NumberOfPartitionEntries > DivU64x32 (MAX_UINT64, PrimaryHeader->SizeOfPartitionEntry)) { ++ DEBUG ((DEBUG_ERROR, "Invalid Partition Table Header NumberOfPartitionEntries!\n")); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (AllocationSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Replacing logic: ++ // PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry; ++ Status = SafeUint32Mult (PrimaryHeader->NumberOfPartitionEntries, PrimaryHeader->SizeOfPartitionEntry, AllocationSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Allocation Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including the ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINT32 SafeNumberOfPartitions; ++ ++ if (PrimaryHeader == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (EventSize == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // We shouldn't even attempt to perform the multiplication if the number of partitions is greater than the maximum value of UINT32 ++ Status = SafeUintnToUint32 (NumberOfPartition, &SafeNumberOfPartitions); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "NumberOfPartition would have overflowed!\n")); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Replacing logic: ++ // (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry + sizeof (TCG_PCR_EVENT_HDR)); ++ Status = SafeUint32Mult (SafeNumberOfPartitions, PrimaryHeader->SizeOfPartitionEntry, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ Status = SafeUint32Add ( ++ sizeof (TCG_PCR_EVENT_HDR) + ++ OFFSET_OF (EFI_GPT_DATA, Partitions), ++ *EventSize, ++ EventSize ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Event Size would have overflowed because of GPTData!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +new file mode 100644 +index 0000000000..0d9d00c281 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +@@ -0,0 +1,114 @@ ++/** @file ++ This file includes the function prototypes for the sanitization functions. ++ ++ These are those functions: ++ ++ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its ++ data structure within this image buffer before use. ++ ++ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse ++ partition data carefully. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#ifndef DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ ++#define DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ ++ ++#include ++#include ++#include ++#include ++ ++/** ++ This function will validate the EFI_PARTITION_TABLE_HEADER structure is safe to parse ++ However this function will not attempt to verify the validity of the GPT partition ++ It will check the following: ++ - Signature ++ - Revision ++ - AlternateLBA ++ - FirstUsableLBA ++ - LastUsableLBA ++ - PartitionEntryLBA ++ - NumberOfPartitionEntries ++ - SizeOfPartitionEntry ++ - BlockIo ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[in] BlockIo ++ Pointer to the EFI_BLOCK_IO_PROTOCOL structure. ++ ++ @retval EFI_SUCCESS ++ The EFI_PARTITION_TABLE_HEADER structure is valid. ++ ++ @retval EFI_INVALID_PARAMETER ++ The EFI_PARTITION_TABLE_HEADER structure is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizeEfiPartitionTableHeader ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN CONST EFI_BLOCK_IO_PROTOCOL *BlockIo ++ ); ++ ++/** ++ This function will validate that the allocation size from the primary header is sane ++ It will check the following: ++ - AllocationSize does not overflow ++ ++ @param[in] PrimaryHeader ++ Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ ++ @param[out] AllocationSize ++ Pointer to the allocation size. ++ ++ @retval EFI_SUCCESS ++ The allocation size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ The allocation size is invalid. ++**/ ++EFI_STATUS ++EFIAPI ++SanitizePrimaryHeaderAllocationSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ OUT UINT32 *AllocationSize ++ ); ++ ++/** ++ This function will validate that the Gpt Event Size calculated from the primary header is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ Important: This function includes the entire length of the allocated space, including the ++ TCG_PCR_EVENT_HDR. When hashing the buffer allocated with this size, the caller must subtract ++ the size of the TCG_PCR_EVENT_HDR from the size of the buffer before hashing. ++ ++ @param[in] PrimaryHeader - Pointer to the EFI_PARTITION_TABLE_HEADER structure. ++ @param[in] NumberOfPartition - Number of partitions. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePrimaryHeaderGptEventSize ( ++ IN CONST EFI_PARTITION_TABLE_HEADER *PrimaryHeader, ++ IN UINTN NumberOfPartition, ++ OUT UINT32 *EventSize ++ ); ++ ++#endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +new file mode 100644 +index 0000000000..eeb928cdb0 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +@@ -0,0 +1,301 @@ ++/** @file ++This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. ++ ++Copyright (c) Microsoft Corporation.
++SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../DxeTpmMeasureBootLibSanitization.h" ++ ++#define UNIT_TEST_NAME "DxeTpmMeasureBootLibSanitizationTest" ++#define UNIT_TEST_VERSION "1.0" ++ ++#define DEFAULT_PRIMARY_TABLE_HEADER_REVISION 0x00010000 ++#define DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES 1 ++#define DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY 128 ++ ++/** ++ This function tests the SanitizeEfiPartitionTableHeader function. ++ It's intent is to test that a malicious EFI_PARTITION_TABLE_HEADER ++ structure will not cause undefined or unexpected behavior. ++ ++ In general the TPM should still be able to measure the data, but ++ be the header should be sanitized to prevent any unexpected behavior. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizeEfiPartitionTableHeader ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ EFI_BLOCK_IO_PROTOCOL BlockIo; ++ EFI_BLOCK_IO_MEDIA BlockMedia; ++ ++ // Generate EFI_BLOCK_IO_MEDIA test data ++ BlockMedia.MediaId = 1; ++ BlockMedia.RemovableMedia = FALSE; ++ BlockMedia.MediaPresent = TRUE; ++ BlockMedia.LogicalPartition = FALSE; ++ BlockMedia.ReadOnly = FALSE; ++ BlockMedia.WriteCaching = FALSE; ++ BlockMedia.BlockSize = 512; ++ BlockMedia.IoAlign = 1; ++ BlockMedia.LastBlock = 0; ++ ++ // Generate EFI_BLOCK_IO_PROTOCOL test data ++ BlockIo.Revision = 1; ++ BlockIo.Media = &BlockMedia; ++ BlockIo.Reset = NULL; ++ BlockIo.ReadBlocks = NULL; ++ BlockIo.WriteBlocks = NULL; ++ BlockIo.FlushBlocks = NULL; ++ ++ // Geneate EFI_PARTITION_TABLE_HEADER test data ++ PrimaryHeader.Header.Signature = EFI_PTAB_HEADER_ID; ++ PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ PrimaryHeader.MyLBA = 1; ++ PrimaryHeader.AlternateLBA = 2; ++ PrimaryHeader.FirstUsableLBA = 3; ++ PrimaryHeader.LastUsableLBA = 4; ++ PrimaryHeader.PartitionEntryLBA = 5; ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid ++ ++ // Calculate the CRC32 of the PrimaryHeader ++ PrimaryHeader.Header.CRC32 = CalculateCrc32 ((UINT8 *)&PrimaryHeader, PrimaryHeader.Header.HeaderSize); ++ ++ // Test that a normal PrimaryHeader passes validation ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that when number of partition entries is 0, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header NumberOfPartitionEntries!"" ++ PrimaryHeader.NumberOfPartitionEntries = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // Test that when the header size is too small, the function returns EFI_DEVICE_ERROR ++ // Should print "Invalid Partition Table Header Size!" ++ PrimaryHeader.Header.HeaderSize = 0; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); ++ ++ // Test that when the SizeOfPartitionEntry is too small, the function returns EFI_DEVICE_ERROR ++ // should print: "SizeOfPartitionEntry shall be set to a value of 128 x 2^n where n is an integer greater than or equal to zero (e.g., 128, 256, 512, etc.)!" ++ PrimaryHeader.SizeOfPartitionEntry = 1; ++ Status = SanitizeEfiPartitionTableHeader (&PrimaryHeader, &BlockIo); ++ UT_ASSERT_EQUAL (Status, EFI_DEVICE_ERROR); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderAllocationSize function. ++ It's intent is to test that the untrusted input from a EFI_PARTITION_TABLE_HEADER ++ structure will not cause an overflow when calculating the allocation size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderAllocationSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 AllocationSize; ++ ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Test that the allocation size is correct compared to the existing logic ++ UT_ASSERT_EQUAL (AllocationSize, PrimaryHeader.NumberOfPartitionEntries * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Test that an overflow is detected ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = 5; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the inverse ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test the worst case scenario ++ PrimaryHeader.NumberOfPartitionEntries = MAX_UINT32; ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderAllocationSize (&PrimaryHeader, &AllocationSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++/** ++ This function tests the SanitizePrimaryHeaderGptEventSize function. ++ It's intent is to test that the untrusted input from a EFI_GPT_DATA structure ++ will not cause an overflow when calculating the event size. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePrimaryHeaderGptEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINT32 ExistingLogicEventSize; ++ EFI_STATUS Status; ++ EFI_PARTITION_TABLE_HEADER PrimaryHeader; ++ UINTN NumberOfPartition; ++ EFI_GPT_DATA *GptData; ++ ++ GptData = NULL; ++ ++ // Test that a normal PrimaryHeader passes validation ++ PrimaryHeader.NumberOfPartitionEntries = 5; ++ PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; ++ ++ // set the number of partitions ++ NumberOfPartition = 13; ++ ++ // that the primary event size is correct ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_NOT_EFI_ERROR (Status); ++ ++ // Calculate the existing logic event size ++ ExistingLogicEventSize = (UINT32)(sizeof (TCG_PCR_EVENT_HDR) + OFFSET_OF (EFI_GPT_DATA, Partitions) ++ + NumberOfPartition * PrimaryHeader.SizeOfPartitionEntry); ++ ++ // Check that the event size is correct ++ UT_ASSERT_EQUAL (EventSize, ExistingLogicEventSize); ++ ++ // Tests that the primary event size may not overflow ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, MAX_UINT32, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ // Test that the size of partition entries may not overflow ++ PrimaryHeader.SizeOfPartitionEntry = MAX_UINT32; ++ Status = SanitizePrimaryHeaderGptEventSize (&PrimaryHeader, NumberOfPartition, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ ++// *--------------------------------------------------------------------* ++// * Unit Test Code Main Function ++// *--------------------------------------------------------------------* ++ ++/** ++ This function acts as the entry point for the unit tests. ++ ++ @param argc - The number of command line arguments ++ @param argv - The command line arguments ++ ++ @return int - The status of the test ++**/ ++EFI_STATUS ++EFIAPI ++UefiTestMain ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UNIT_TEST_FRAMEWORK_HANDLE Framework; ++ UNIT_TEST_SUITE_HANDLE TcgMeasureBootLibValidationTestSuite; ++ ++ Framework = NULL; ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - Start\n", UNIT_TEST_NAME)); ++ ++ Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a: Failed in InitUnitTestFramework. Status = %r\n", UNIT_TEST_NAME, Status)); ++ goto EXIT; ++ } ++ ++ Status = CreateUnitTestSuite (&TcgMeasureBootLibValidationTestSuite, Framework, "TcgMeasureBootLibValidationTestSuite", "Common.TcgMeasureBootLibValidation", NULL, NULL); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%s: Failed in CreateUnitTestSuite for TcgMeasureBootLibValidationTestSuite\n", UNIT_TEST_NAME)); ++ Status = EFI_OUT_OF_RESOURCES; ++ goto EXIT; ++ } ++ ++ // -----------Suite---------------------------------Description----------------------------Class----------------------------------Test Function------------------------Pre---Clean-Context ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ ++ Status = RunAllTestSuites (Framework); ++ ++EXIT: ++ if (Framework != NULL) { ++ FreeUnitTestFramework (Framework); ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: TestMain() - End\n", UNIT_TEST_NAME)); ++ return Status; ++} ++ ++/// ++/// Avoid ECC error for function name that starts with lower case letter ++/// ++#define DxeTpmMeasureBootLibUnitTestMain main ++ ++/** ++ Standard POSIX C entry point for host based unit test execution. ++ ++ @param[in] Argc Number of arguments ++ @param[in] Argv Array of pointers to arguments ++ ++ @retval 0 Success ++ @retval other Error ++**/ ++INT32 ++DxeTpmMeasureBootLibUnitTestMain ( ++ IN INT32 Argc, ++ IN CHAR8 *Argv[] ++ ) ++{ ++ return (INT32)UefiTestMain (); ++} +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf +new file mode 100644 +index 0000000000..47b0811b00 +--- /dev/null ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTestHost.inf +@@ -0,0 +1,28 @@ ++## @file ++# This file builds the unit tests for DxeTpmMeasureBootLib ++# ++# Copyright (C) Microsoft Corporation.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 0x00010006 ++ BASE_NAME = DxeTpmMeasuredBootLibTest ++ FILE_GUID = eb01bc38-309c-4d3e-967e-9f078c90772f ++ MODULE_TYPE = HOST_APPLICATION ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = main ++ ++[Sources] ++ DxeTpmMeasureBootLibSanitizationTest.c ++ ../DxeTpmMeasureBootLibSanitization.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UnitTestLib ++ PrintLib ++ SafeIntLib +diff --git a/SecurityPkg/SecurityPkg.ci.yaml b/SecurityPkg/SecurityPkg.ci.yaml +index da811fdf93..0e40eaa0fe 100644 +--- a/SecurityPkg/SecurityPkg.ci.yaml ++++ b/SecurityPkg/SecurityPkg.ci.yaml +@@ -16,6 +16,7 @@ + ## ] + "ExceptionList": [ + "8001", "DxeTpm2MeasureBootLibUnitTestMain", ++ "8001", "DxeTpmMeasureBootLibUnitTestMain" + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch new file mode 100644 index 0000000000..59bd5c4910 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36763-0003.patch @@ -0,0 +1,55 @@ +From 1ddcb9fc6b4164e882687b031e8beacfcf7df29e Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:03 +0800 +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml + +This creates / adds a security file that tracks the security fixes +found in this package and can be used to find the fixes that were +applied. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Jiewen Yao + +CVE: CVE-2022-36763 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1ddcb9fc6b4164e882687b031e8beacfcf7df29e] + +Signed-off-by: Soumya Sambu +--- + SecurityPkg/SecurityFixes.yaml | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 SecurityPkg/SecurityFixes.yaml + +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml +new file mode 100644 +index 0000000000..f9e3e7be74 +--- /dev/null ++++ b/SecurityPkg/SecurityFixes.yaml +@@ -0,0 +1,22 @@ ++## @file ++# Security Fixes for SecurityPkg ++# ++# Copyright (c) Microsoft Corporation ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++CVE_2022_36763: ++ commit_titles: ++ - "SecurityPkg: DxeTpm2Measurement: SECURITY PATCH 4117 - CVE 2022-36763" ++ - "SecurityPkg: DxeTpmMeasurement: SECURITY PATCH 4117 - CVE 2022-36763" ++ - "SecurityPkg: : Adding CVE 2022-36763 to SecurityFixes.yaml" ++ cve: CVE-2022-36763 ++ date_reported: 2022-10-25 11:31 UTC ++ description: (CVE-2022-36763) - Heap Buffer Overflow in Tcg2MeasureGptTable() ++ note: This patch is related to and supersedes TCBZ2168 ++ files_impacted: ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4117 ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=2168 ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=1990 +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 84e3360a3a..78d86ad879 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -27,6 +27,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://0006-reproducible.patch \ file://0001-BaseTools-fix-gcc12-warning.patch \ file://0001-BaseTools-fix-gcc12-warning-1.patch \ + file://CVE-2022-36763-0001.patch \ + file://CVE-2022-36763-0002.patch \ + file://CVE-2022-36763-0003.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46189 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9BECEC3DA41 for ; Thu, 11 Jul 2024 04:56:08 +0000 (UTC) Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) by mx.groups.io with SMTP id smtpd.web11.4940.1720673765903724346 for ; Wed, 10 Jul 2024 21:56:06 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.178.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250811.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4sHgG026206 for ; Thu, 11 Jul 2024 04:56:05 GMT Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 406u4x4jm2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Jul 2024 04:56:04 +0000 (GMT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:01 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 02/11] ovmf: Fix CVE-2022-36764 Date: Thu, 11 Jul 2024 04:55:32 +0000 Message-ID: <20240711045541.2155076-2-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-ORIG-GUID: YniUuXeH0cyLq_jhki1kKbcL5KVevvjK X-Proofpoint-GUID: YniUuXeH0cyLq_jhki1kKbcL5KVevvjK X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 adultscore=0 malwarescore=0 bulkscore=0 clxscore=1015 spamscore=0 mlxlogscore=999 priorityscore=1501 lowpriorityscore=0 suspectscore=0 phishscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:08 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201752 From: Soumya Sambu EDK2 is susceptible to a vulnerability in the Tcg2MeasurePeImage() function, allowing a user to trigger a heap buffer overflow via a local network. Successful exploitation of this vulnerability may result in a compromise of confidentiality, integrity, and/or availability. References: https://nvd.nist.gov/vuln/detail/CVE-2022-36764 Upstream-patches: https://github.com/tianocore/edk2/commit/c7b27944218130cca3bbb20314ba5b88b5de4aa4 https://github.com/tianocore/edk2/commit/0d341c01eeabe0ab5e76693b36e728b8f538a40e https://github.com/tianocore/edk2/commit/8f6d343ae639fba8e4b80e45257275e23083431f Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2022-36764-0001.patch | 271 +++++++++++++++++ .../ovmf/ovmf/CVE-2022-36764-0002.patch | 281 ++++++++++++++++++ .../ovmf/ovmf/CVE-2022-36764-0003.patch | 48 +++ meta/recipes-core/ovmf/ovmf_git.bb | 3 + 4 files changed, 603 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0002.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0003.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0001.patch new file mode 100644 index 0000000000..a552f36b2c --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0001.patch @@ -0,0 +1,271 @@ +From c7b27944218130cca3bbb20314ba5b88b5de4aa4 Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:04 +0800 +Subject: [PATCH] SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4118 - CVE + 2022-36764 + +This commit contains the patch files and tests for DxeTpm2MeasureBootLib +CVE 2022-36764. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Jiewen Yao + +CVE: CVE-2022-36764 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/c7b27944218130cca3bbb20314ba5b88b5de4aa4] + +Signed-off-by: Soumya Sambu +--- + .../DxeTpm2MeasureBootLib.c | 12 ++-- + .../DxeTpm2MeasureBootLibSanitization.c | 46 +++++++++++++- + .../DxeTpm2MeasureBootLibSanitization.h | 28 ++++++++- + .../DxeTpm2MeasureBootLibSanitizationTest.c | 60 ++++++++++++++++--- + 4 files changed, 131 insertions(+), 15 deletions(-) + +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +index 0475103d6e..714cc8e03e 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +@@ -378,7 +378,6 @@ Exit: + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. + @retval other error value +- + **/ + EFI_STATUS + EFIAPI +@@ -405,6 +404,7 @@ Tcg2MeasurePeImage ( + Status = EFI_UNSUPPORTED; + ImageLoad = NULL; + EventPtr = NULL; ++ Tcg2Event = NULL; + + Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol; + CcProtocol = MeasureBootProtocols->CcProtocol; +@@ -420,18 +420,22 @@ Tcg2MeasurePeImage ( + } + + FilePathSize = (UINT32)GetDevicePathSize (FilePath); ++ Status = SanitizePeImageEventSize (FilePathSize, &EventSize); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } + + // + // Determine destination PCR by BootPolicy + // +- EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; +- EventPtr = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event)); ++ // from a malicious GPT disk partition ++ EventPtr = AllocateZeroPool (EventSize); + if (EventPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event); ++ Tcg2Event->Size = EventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event; +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +index e2309655d3..2a4d52c6d5 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.c +@@ -151,7 +151,7 @@ SanitizeEfiPartitionTableHeader ( + } + + /** +- This function will validate that the allocation size from the primary header is sane ++ This function will validate that the allocation size from the primary header is sane + It will check the following: + - AllocationSize does not overflow + +@@ -273,3 +273,47 @@ SanitizePrimaryHeaderGptEventSize ( + + return EFI_SUCCESS; + } ++ ++/** ++ This function will validate that the PeImage Event Size from the loaded image is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ @param[in] FilePathSize - Size of the file path. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePeImageEventSize ( ++ IN UINT32 FilePathSize, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // Replacing logic: ++ // sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; ++ Status = SafeUint32Add (OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath), FilePathSize, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ // Replacing logic: ++ // EventSize + sizeof (EFI_TCG2_EVENT) - sizeof (Tcg2Event->Event) ++ Status = SafeUint32Add (*EventSize, OFFSET_OF (EFI_TCG2_EVENT, Event), EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +index 048b738987..8f72ba4240 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLibSanitization.h +@@ -9,6 +9,9 @@ + Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse + partition data carefully. + ++ Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its ++ data structure within this image buffer before use. ++ + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +@@ -110,4 +113,27 @@ SanitizePrimaryHeaderGptEventSize ( + OUT UINT32 *EventSize + ); + +-#endif // DXE_TPM2_MEASURE_BOOT_LIB_SANITATION_ ++/** ++ This function will validate that the PeImage Event Size from the loaded image is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ @param[in] FilePathSize - Size of the file path. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePeImageEventSize ( ++ IN UINT32 FilePathSize, ++ OUT UINT32 *EventSize ++ ); ++ ++#endif // DXE_TPM2_MEASURE_BOOT_LIB_VALIDATION_ +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +index 3eb9763e3c..820e99aeb9 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/InternalUnitTest/DxeTpm2MeasureBootLibSanitizationTest.c +@@ -72,10 +72,10 @@ TestSanitizeEfiPartitionTableHeader ( + PrimaryHeader.Header.Revision = DEFAULT_PRIMARY_TABLE_HEADER_REVISION; + PrimaryHeader.Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER); + PrimaryHeader.MyLBA = 1; +- PrimaryHeader.AlternateLBA = 2; +- PrimaryHeader.FirstUsableLBA = 3; +- PrimaryHeader.LastUsableLBA = 4; +- PrimaryHeader.PartitionEntryLBA = 5; ++ PrimaryHeader.PartitionEntryLBA = 2; ++ PrimaryHeader.AlternateLBA = 3; ++ PrimaryHeader.FirstUsableLBA = 4; ++ PrimaryHeader.LastUsableLBA = 5; + PrimaryHeader.NumberOfPartitionEntries = DEFAULT_PRIMARY_TABLE_HEADER_NUMBER_OF_PARTITION_ENTRIES; + PrimaryHeader.SizeOfPartitionEntry = DEFAULT_PRIMARY_TABLE_HEADER_SIZE_OF_PARTITION_ENTRY; + PrimaryHeader.PartitionEntryArrayCRC32 = 0; // Purposely invalid +@@ -187,11 +187,6 @@ TestSanitizePrimaryHeaderGptEventSize ( + EFI_STATUS Status; + EFI_PARTITION_TABLE_HEADER PrimaryHeader; + UINTN NumberOfPartition; +- EFI_GPT_DATA *GptData; +- EFI_TCG2_EVENT *Tcg2Event; +- +- Tcg2Event = NULL; +- GptData = NULL; + + // Test that a normal PrimaryHeader passes validation + PrimaryHeader.NumberOfPartitionEntries = 5; +@@ -225,6 +220,52 @@ TestSanitizePrimaryHeaderGptEventSize ( + return UNIT_TEST_PASSED; + } + ++/** ++ This function tests the SanitizePeImageEventSize function. ++ It's intent is to test that the untrusted input from a file path when generating a ++ EFI_IMAGE_LOAD_EVENT structure will not cause an overflow when calculating ++ the event size when allocating space ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePeImageEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINTN ExistingLogicEventSize; ++ UINT32 FilePathSize; ++ EFI_STATUS Status; ++ ++ FilePathSize = 255; ++ ++ // Test that a normal PE image passes validation ++ Status = SanitizePeImageEventSize (FilePathSize, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_SUCCESS); ++ ++ // Test that the event size is correct compared to the existing logic ++ ExistingLogicEventSize = OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath) + FilePathSize; ++ ExistingLogicEventSize += OFFSET_OF (EFI_TCG2_EVENT, Event); ++ ++ if (EventSize != ExistingLogicEventSize) { ++ UT_LOG_ERROR ("SanitizePeImageEventSize returned an incorrect event size. Expected %u, got %u\n", ExistingLogicEventSize, EventSize); ++ return UNIT_TEST_ERROR_TEST_FAILED; ++ } ++ ++ // Test that the event size may not overflow ++ Status = SanitizePeImageEventSize (MAX_UINT32, &EventSize); ++ UT_ASSERT_EQUAL (Status, EFI_BAD_BUFFER_SIZE); ++ ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ ++ return UNIT_TEST_PASSED; ++} ++ + // *--------------------------------------------------------------------* + // * Unit Test Code Main Function + // *--------------------------------------------------------------------* +@@ -267,6 +308,7 @@ UefiTestMain ( + AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.Tcg2MeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); + AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); + AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ AddTestCase (Tcg2MeasureBootLibValidationTestSuite, "Tests PE Image and FileSize checks for overflow", "Common.Tcg2MeasureBootLibValidation", TestSanitizePeImageEventSize, NULL, NULL, NULL); + + Status = RunAllTestSuites (Framework); + +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0002.patch new file mode 100644 index 0000000000..22a7713f52 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0002.patch @@ -0,0 +1,281 @@ +From 0d341c01eeabe0ab5e76693b36e728b8f538a40e Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:05 +0800 +Subject: [PATCH] SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4118 - CVE + 2022-36764 + +This commit contains the patch files and tests for DxeTpmMeasureBootLib +CVE 2022-36764. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Jiewen Yao + +CVE: CVE-2022-36764 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/0d341c01eeabe0ab5e76693b36e728b8f538a40e] + +Signed-off-by: Soumya Sambu +--- + .../DxeTpmMeasureBootLib.c | 13 ++- + .../DxeTpmMeasureBootLibSanitization.c | 44 +++++++++ + .../DxeTpmMeasureBootLibSanitization.h | 23 +++++ + .../DxeTpmMeasureBootLibSanitizationTest.c | 98 +++++++++++++++++-- + 4 files changed, 168 insertions(+), 10 deletions(-) + +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +index 669ab19134..a9fc440a09 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +@@ -17,6 +17,7 @@ + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent ++Copyright (c) Microsoft Corporation.
+ + Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +@@ -345,18 +346,22 @@ TcgMeasurePeImage ( + ImageLoad = NULL; + SectionHeader = NULL; + Sha1Ctx = NULL; ++ TcgEvent = NULL; + FilePathSize = (UINT32)GetDevicePathSize (FilePath); + +- // + // Determine destination PCR by BootPolicy + // +- EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; +- TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT)); ++ Status = SanitizePeImageEventSize (FilePathSize, &EventSize); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ TcgEvent = AllocateZeroPool (EventSize); + if (TcgEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + +- TcgEvent->EventSize = EventSize; ++ TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); + ImageLoad = (EFI_IMAGE_LOAD_EVENT *)TcgEvent->Event; + + switch (ImageType) { +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +index a3fa46f5e6..c989851cec 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.c +@@ -239,3 +239,47 @@ SanitizePrimaryHeaderGptEventSize ( + + return EFI_SUCCESS; + } ++ ++/** ++ This function will validate that the PeImage Event Size from the loaded image is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ @param[in] FilePathSize - Size of the file path. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePeImageEventSize ( ++ IN UINT32 FilePathSize, ++ OUT UINT32 *EventSize ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // Replacing logic: ++ // sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; ++ Status = SafeUint32Add (OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath), FilePathSize, EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ // Replacing logic: ++ // EventSize + sizeof (TCG_PCR_EVENT_HDR) ++ Status = SafeUint32Add (*EventSize, sizeof (TCG_PCR_EVENT_HDR), EventSize); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "EventSize would overflow!\n")); ++ return EFI_BAD_BUFFER_SIZE; ++ } ++ ++ return EFI_SUCCESS; ++} +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +index 0d9d00c281..2248495813 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLibSanitization.h +@@ -111,4 +111,27 @@ SanitizePrimaryHeaderGptEventSize ( + OUT UINT32 *EventSize + ); + ++/** ++ This function will validate that the PeImage Event Size from the loaded image is sane ++ It will check the following: ++ - EventSize does not overflow ++ ++ @param[in] FilePathSize - Size of the file path. ++ @param[out] EventSize - Pointer to the event size. ++ ++ @retval EFI_SUCCESS ++ The event size is valid. ++ ++ @retval EFI_OUT_OF_RESOURCES ++ Overflow would have occurred. ++ ++ @retval EFI_INVALID_PARAMETER ++ One of the passed parameters was invalid. ++**/ ++EFI_STATUS ++SanitizePeImageEventSize ( ++ IN UINT32 FilePathSize, ++ OUT UINT32 *EventSize ++ ); ++ + #endif // DXE_TPM_MEASURE_BOOT_LIB_VALIDATION_ +diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +index eeb928cdb0..c41498be45 100644 +--- a/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c ++++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/InternalUnitTest/DxeTpmMeasureBootLibSanitizationTest.c +@@ -1,8 +1,8 @@ + /** @file +-This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. ++ This file includes the unit test cases for the DxeTpmMeasureBootLibSanitizationTest.c. + +-Copyright (c) Microsoft Corporation.
+-SPDX-License-Identifier: BSD-2-Clause-Patent ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include +@@ -186,9 +186,6 @@ TestSanitizePrimaryHeaderGptEventSize ( + EFI_STATUS Status; + EFI_PARTITION_TABLE_HEADER PrimaryHeader; + UINTN NumberOfPartition; +- EFI_GPT_DATA *GptData; +- +- GptData = NULL; + + // Test that a normal PrimaryHeader passes validation + PrimaryHeader.NumberOfPartitionEntries = 5; +@@ -222,6 +219,94 @@ TestSanitizePrimaryHeaderGptEventSize ( + return UNIT_TEST_PASSED; + } + ++/** ++ This function tests the SanitizePeImageEventSize function. ++ It's intent is to test that the untrusted input from a file path for an ++ EFI_IMAGE_LOAD_EVENT structure will not cause an overflow when calculating ++ the event size when allocating space. ++ ++ @param[in] Context The unit test context. ++ ++ @retval UNIT_TEST_PASSED The test passed. ++ @retval UNIT_TEST_ERROR_TEST_FAILED The test failed. ++**/ ++UNIT_TEST_STATUS ++EFIAPI ++TestSanitizePeImageEventSize ( ++ IN UNIT_TEST_CONTEXT Context ++ ) ++{ ++ UINT32 EventSize; ++ UINTN ExistingLogicEventSize; ++ UINT32 FilePathSize; ++ EFI_STATUS Status; ++ EFI_DEVICE_PATH_PROTOCOL DevicePath; ++ EFI_IMAGE_LOAD_EVENT *ImageLoadEvent; ++ UNIT_TEST_STATUS TestStatus; ++ ++ TestStatus = UNIT_TEST_ERROR_TEST_FAILED; ++ ++ // Generate EFI_DEVICE_PATH_PROTOCOL test data ++ DevicePath.Type = 0; ++ DevicePath.SubType = 0; ++ DevicePath.Length[0] = 0; ++ DevicePath.Length[1] = 0; ++ ++ // Generate EFI_IMAGE_LOAD_EVENT test data ++ ImageLoadEvent = AllocateZeroPool (sizeof (EFI_IMAGE_LOAD_EVENT) + sizeof (EFI_DEVICE_PATH_PROTOCOL)); ++ if (ImageLoadEvent == NULL) { ++ DEBUG ((DEBUG_ERROR, "%a: AllocateZeroPool failed\n", __func__)); ++ goto Exit; ++ } ++ ++ // Populate EFI_IMAGE_LOAD_EVENT54 test data ++ ImageLoadEvent->ImageLocationInMemory = (EFI_PHYSICAL_ADDRESS)0x12345678; ++ ImageLoadEvent->ImageLengthInMemory = 0x1000; ++ ImageLoadEvent->ImageLinkTimeAddress = (UINTN)ImageLoadEvent; ++ ImageLoadEvent->LengthOfDevicePath = sizeof (EFI_DEVICE_PATH_PROTOCOL); ++ CopyMem (ImageLoadEvent->DevicePath, &DevicePath, sizeof (EFI_DEVICE_PATH_PROTOCOL)); ++ ++ FilePathSize = 255; ++ ++ // Test that a normal PE image passes validation ++ Status = SanitizePeImageEventSize (FilePathSize, &EventSize); ++ if (EFI_ERROR (Status)) { ++ UT_LOG_ERROR ("SanitizePeImageEventSize failed with %r\n", Status); ++ goto Exit; ++ } ++ ++ // Test that the event size is correct compared to the existing logic ++ ExistingLogicEventSize = OFFSET_OF (EFI_IMAGE_LOAD_EVENT, DevicePath) + FilePathSize; ++ ExistingLogicEventSize += sizeof (TCG_PCR_EVENT_HDR); ++ ++ if (EventSize != ExistingLogicEventSize) { ++ UT_LOG_ERROR ("SanitizePeImageEventSize returned an incorrect event size. Expected %u, got %u\n", ExistingLogicEventSize, EventSize); ++ goto Exit; ++ } ++ ++ // Test that the event size may not overflow ++ Status = SanitizePeImageEventSize (MAX_UINT32, &EventSize); ++ if (Status != EFI_BAD_BUFFER_SIZE) { ++ UT_LOG_ERROR ("SanitizePeImageEventSize succeded when it was supposed to fail with %r\n", Status); ++ goto Exit; ++ } ++ ++ TestStatus = UNIT_TEST_PASSED; ++Exit: ++ ++ if (ImageLoadEvent != NULL) { ++ FreePool (ImageLoadEvent); ++ } ++ ++ if (TestStatus == UNIT_TEST_ERROR_TEST_FAILED) { ++ DEBUG ((DEBUG_ERROR, "%a: Test failed\n", __func__)); ++ } else { ++ DEBUG ((DEBUG_INFO, "%a: Test passed\n", __func__)); ++ } ++ ++ return TestStatus; ++} ++ + // *--------------------------------------------------------------------* + // * Unit Test Code Main Function + // *--------------------------------------------------------------------* +@@ -265,6 +350,7 @@ UefiTestMain ( + AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Validating EFI Partition Table", "Common.TcgMeasureBootLibValidation", TestSanitizeEfiPartitionTableHeader, NULL, NULL, NULL); + AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header gpt event checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderAllocationSize, NULL, NULL, NULL); + AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests Primary header allocation size checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePrimaryHeaderGptEventSize, NULL, NULL, NULL); ++ AddTestCase (TcgMeasureBootLibValidationTestSuite, "Tests PE Image and FileSize checks for overflow", "Common.TcgMeasureBootLibValidation", TestSanitizePeImageEventSize, NULL, NULL, NULL); + + Status = RunAllTestSuites (Framework); + +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0003.patch new file mode 100644 index 0000000000..89386c0c29 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36764-0003.patch @@ -0,0 +1,48 @@ +From 8f6d343ae639fba8e4b80e45257275e23083431f Mon Sep 17 00:00:00 2001 +From: "Douglas Flick [MSFT]" +Date: Fri, 12 Jan 2024 02:16:06 +0800 +Subject: [PATCH] SecurityPkg: : Adding CVE 2022-36764 to SecurityFixes.yaml + +This creates / adds a security file that tracks the security fixes +found in this package and can be used to find the fixes that were +applied. + +Cc: Jiewen Yao + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Jiewen Yao + +CVE: CVE-2022-36764 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/8f6d343ae639fba8e4b80e45257275e23083431f] + +Signed-off-by: Soumya Sambu +--- + SecurityPkg/SecurityFixes.yaml | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/SecurityPkg/SecurityFixes.yaml b/SecurityPkg/SecurityFixes.yaml +index f9e3e7be74..833fb827a9 100644 +--- a/SecurityPkg/SecurityFixes.yaml ++++ b/SecurityPkg/SecurityFixes.yaml +@@ -20,3 +20,17 @@ CVE_2022_36763: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4117 + - https://bugzilla.tianocore.org/show_bug.cgi?id=2168 + - https://bugzilla.tianocore.org/show_bug.cgi?id=1990 ++CVE_2022_36764: ++ commit_titles: ++ - "SecurityPkg: DxeTpm2MeasureBootLib: SECURITY PATCH 4118 - CVE 2022-36764" ++ - "SecurityPkg: DxeTpmMeasureBootLib: SECURITY PATCH 4118 - CVE 2022-36764" ++ - "SecurityPkg: : Adding CVE 2022-36764 to SecurityFixes.yaml" ++ cve: CVE-2022-36764 ++ date_reported: 2022-10-25 12:23 UTC ++ description: Heap Buffer Overflow in Tcg2MeasurePeImage() ++ note: ++ files_impacted: ++ - Library\DxeTpm2MeasureBootLib\DxeTpm2MeasureBootLib.c ++ - Library\DxeTpmMeasureBootLib\DxeTpmMeasureBootLib.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4118 +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 78d86ad879..59e5598a1b 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -30,6 +30,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2022-36763-0001.patch \ file://CVE-2022-36763-0002.patch \ file://CVE-2022-36763-0003.patch \ + file://CVE-2022-36764-0001.patch \ + file://CVE-2022-36764-0002.patch \ + file://CVE-2022-36764-0003.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46191 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED405C3DA49 for ; Thu, 11 Jul 2024 04:56:08 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web10.4973.1720673766814059242 for ; Wed, 10 Jul 2024 21:56:06 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250810.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4oSoO024907 for ; Wed, 10 Jul 2024 21:56:06 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 407170mcjm-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:06 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:04 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 03/11] ovmf: Fix CVE-2023-45230 Date: Thu, 11 Jul 2024 04:55:33 +0000 Message-ID: <20240711045541.2155076-3-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: g833UaVjJefnDp4vvx1ADWZPzNBTqxOO X-Proofpoint-ORIG-GUID: g833UaVjJefnDp4vvx1ADWZPzNBTqxOO X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 impostorscore=0 malwarescore=0 phishscore=0 adultscore=0 lowpriorityscore=0 spamscore=0 suspectscore=0 bulkscore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:08 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201753 From: Soumya Sambu EDK2's Network Package is susceptible to a buffer overflow vulnerability via a long server ID option in DHCPv6 client. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality, Integrity and/or Availability. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45230 Upstream-patches: https://github.com/tianocore/edk2/commit/f31453e8d6542461d92d835e0b79fec8b039174d https://github.com/tianocore/edk2/commit/5f3658197bf29c83b3349b0ab1d99cdb0c3814bc Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45230-0001.patch | 1617 +++++++++++++++++ .../ovmf/ovmf/CVE-2023-45230-0002.patch | 604 ++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 2223 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0001.patch new file mode 100644 index 0000000000..b0e13c1613 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0001.patch @@ -0,0 +1,1617 @@ +From f31453e8d6542461d92d835e0b79fec8b039174d Mon Sep 17 00:00:00 2001 +From: "Doug Flick via groups.io" +Date: Fri, 26 Jan 2024 05:54:43 +0800 +Subject: [PATCH] NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4535 + +Bug Details: +PixieFail Bug #2 +CVE-2023-45230 +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 + +Changes Overview: +> -UINT8 * +> +EFI_STATUS +> Dhcp6AppendOption ( +> - IN OUT UINT8 *Buf, +> - IN UINT16 OptType, +> - IN UINT16 OptLen, +> - IN UINT8 *Data +> + IN OUT EFI_DHCP6_PACKET *Packet, +> + IN OUT UINT8 **PacketCursor, +> + IN UINT16 OptType, +> + IN UINT16 OptLen, +> + IN UINT8 *Data +> ); + +Dhcp6AppendOption() and variants can return errors now. All callsites +are adapted accordingly. + +It gets passed in EFI_DHCP6_PACKET as additional parameter ... + +> + // +> + // Verify the PacketCursor is within the packet +> + // +> + if ( (*PacketCursor < Packet->Dhcp6.Option) +> + || (*PacketCursor >= Packet->Dhcp6.Option + + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) +> + { +> + return EFI_INVALID_PARAMETER; +> + } + +... so it can look at Packet->Size when checking buffer space. +Also to allow Packet->Length updates. + +Lots of checks added. + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45230 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/f31453e8d6542461d92d835e0b79fec8b039174d] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h | 43 +++ + NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 409 +++++++++++++++++++---------- + NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c | 373 +++++++++++++++++++++----- + NetworkPkg/Dhcp6Dxe/Dhcp6Utility.h | 82 +++--- + 4 files changed, 668 insertions(+), 239 deletions(-) + +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +index 0eb9c669b5..f2422c2f28 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +@@ -45,6 +45,49 @@ 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') + ++// ++// For more information on DHCP options see RFC 8415, Section 21.1 ++// ++// The format of DHCP options is: ++// ++// 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-code | option-len | ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++// | option-data | ++// | (option-len octets) | ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++// ++#define DHCP6_SIZE_OF_OPT_CODE (sizeof(UINT16)) ++#define DHCP6_SIZE_OF_OPT_LEN (sizeof(UINT16)) ++ ++// ++// Combined size of Code and Length ++// ++#define DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN (DHCP6_SIZE_OF_OPT_CODE + \ ++ DHCP6_SIZE_OF_OPT_LEN) ++ ++STATIC_ASSERT ( ++ DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN == 4, ++ "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) ++STATIC_ASSERT ( ++ DHCP6_OPT_LEN_OFFSET (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) ++STATIC_ASSERT ( ++ DHCP6_OPT_DATA_OFFSET (0) == 4, ++ "Offset to option data should be +4 from start of option" ++ ); ++ + #define DHCP6_PACKET_ALL 0 + #define DHCP6_PACKET_STATEFUL 1 + #define DHCP6_PACKET_STATELESS 2 +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +index dcd01e6268..bf5aa7a769 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +@@ -3,9 +3,9 @@ + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
++ Copyright (c) Microsoft Corporation + + SPDX-License-Identifier: BSD-2-Clause-Patent +- + **/ + + #include "Dhcp6Impl.h" +@@ -930,7 +930,8 @@ Dhcp6SendSolicitMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; +@@ -944,54 +945,64 @@ Dhcp6SendSolicitMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption ( +- Cursor, ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, + Instance->IaCb.Ia, + Instance->IaCb.T1, + Instance->IaCb.T2, + Packet->Dhcp6.Header.MessageType + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + // + // Append user-defined when configurate Dhcp6 service. + // + for (Index = 0; Index < Instance->Config->OptionCount; Index++) { + UserOpt = Instance->Config->OptionList[Index]; +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + UserOpt->OpCode, + UserOpt->OpLen, + UserOpt->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // + // Callback to user with the packet to be sent and check the user's feedback. + // + Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1005,10 +1016,8 @@ Dhcp6SendSolicitMsg ( + Instance->StartTime = 0; + + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1020,6 +1029,14 @@ Dhcp6SendSolicitMsg ( + Elapsed, + Instance->Config->SolicitRetransmission + ); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1110,7 +1127,8 @@ Dhcp6SendRequestMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; +@@ -1124,51 +1142,67 @@ Dhcp6SendRequestMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptServerId), + ServerId->Length, + ServerId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption ( +- Cursor, ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, + Instance->IaCb.Ia, + Instance->IaCb.T1, + Instance->IaCb.T2, + Packet->Dhcp6.Header.MessageType + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + // + // Append user-defined when configurate Dhcp6 service. + // + for (Index = 0; Index < Instance->Config->OptionCount; Index++) { + UserOpt = Instance->Config->OptionList[Index]; +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + UserOpt->OpCode, + UserOpt->OpLen, + UserOpt->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // +@@ -1177,8 +1211,7 @@ Dhcp6SendRequestMsg ( + Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet); + + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1194,14 +1227,21 @@ Dhcp6SendRequestMsg ( + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); + + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1266,7 +1306,8 @@ Dhcp6SendDeclineMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE; +@@ -1280,42 +1321,58 @@ Dhcp6SendDeclineMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptServerId), + ServerId->Length, + ServerId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType); ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, ++ DecIa, ++ 0, ++ 0, ++ Packet->Dhcp6.Header.MessageType ++ ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // + // Callback to user with the packet to be sent and check the user's feedback. + // + Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1329,16 +1386,22 @@ Dhcp6SendDeclineMsg ( + Instance->StartTime = 0; + + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1399,7 +1462,8 @@ Dhcp6SendReleaseMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE; +@@ -1413,45 +1477,61 @@ Dhcp6SendReleaseMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + // + // ServerId is extracted from packet, it's network order. + // +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptServerId), + ServerId->Length, + ServerId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType); ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, ++ RelIa, ++ 0, ++ 0, ++ Packet->Dhcp6.Header.MessageType ++ ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- // +- // Determine the size/length of packet +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // + // Callback to user with the packet to be sent and check the user's feedback. + // + Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1461,16 +1541,22 @@ Dhcp6SendReleaseMsg ( + Instance->IaCb.Ia->State = Dhcp6Releasing; + + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1529,7 +1615,8 @@ Dhcp6SendRenewRebindMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; +@@ -1543,26 +1630,38 @@ Dhcp6SendRenewRebindMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption ( +- Cursor, ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, + Instance->IaCb.Ia, + Instance->IaCb.T1, + Instance->IaCb.T2, + Packet->Dhcp6.Header.MessageType + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + if (!RebindRequest) { + // +@@ -1578,18 +1677,22 @@ Dhcp6SendRenewRebindMsg ( + Dhcp6OptServerId + ); + if (Option == NULL) { +- FreePool (Packet); +- return EFI_DEVICE_ERROR; ++ Status = EFI_DEVICE_ERROR; ++ goto ON_ERROR; + } + + ServerId = (EFI_DHCP6_DUID *)(Option + 2); + +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptServerId), + ServerId->Length, + ServerId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + + // +@@ -1597,18 +1700,18 @@ Dhcp6SendRenewRebindMsg ( + // + for (Index = 0; Index < Instance->Config->OptionCount; Index++) { + UserOpt = Instance->Config->OptionList[Index]; +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + UserOpt->OpCode, + UserOpt->OpLen, + UserOpt->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // +@@ -1618,10 +1721,8 @@ Dhcp6SendRenewRebindMsg ( + Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing; + + Status = Dhcp6CallbackUser (Instance, Event, &Packet); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -1638,16 +1739,22 @@ Dhcp6SendRenewRebindMsg ( + Instance->StartTime = 0; + + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1811,7 +1918,8 @@ Dhcp6SendInfoRequestMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; +@@ -1828,44 +1936,56 @@ Dhcp6SendInfoRequestMsg ( + + if (SendClientId) { + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + OptionRequest->OpCode, + OptionRequest->OpLen, + OptionRequest->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + // + // Append user-defined when configurate Dhcp6 service. + // + for (Index = 0; Index < OptionCount; Index++) { + UserOpt = OptionList[Index]; +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + UserOpt->OpCode, + UserOpt->OpLen, + UserOpt->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // +@@ -1877,16 +1997,22 @@ Dhcp6SendInfoRequestMsg ( + // Send info-request packet with no state. + // + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +@@ -1937,7 +2063,8 @@ Dhcp6SendConfirmMsg ( + // + Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen); + if (Packet == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; + } + + Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen; +@@ -1951,54 +2078,64 @@ Dhcp6SendConfirmMsg ( + Cursor = Packet->Dhcp6.Option; + + Length = HTONS (ClientId->Length); +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + HTONS (Dhcp6OptClientId), + Length, + ClientId->Duid + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendETOption ( +- Cursor, ++ Status = Dhcp6AppendETOption ( ++ Packet, ++ &Cursor, + Instance, + &Elapsed + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + +- Cursor = Dhcp6AppendIaOption ( +- Cursor, ++ Status = Dhcp6AppendIaOption ( ++ Packet, ++ &Cursor, + Instance->IaCb.Ia, + Instance->IaCb.T1, + Instance->IaCb.T2, + Packet->Dhcp6.Header.MessageType + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + + // + // Append user-defined when configurate Dhcp6 service. + // + for (Index = 0; Index < Instance->Config->OptionCount; Index++) { + UserOpt = Instance->Config->OptionList[Index]; +- Cursor = Dhcp6AppendOption ( +- Cursor, ++ Status = Dhcp6AppendOption ( ++ Packet, ++ &Cursor, + UserOpt->OpCode, + UserOpt->OpLen, + UserOpt->Data + ); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } + } + +- // +- // Determine the size/length of packet. +- // +- Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option); + ASSERT (Packet->Size > Packet->Length + 8); + + // + // Callback to user with the packet to be sent and check the user's feedback. + // + Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // +@@ -2012,16 +2149,22 @@ Dhcp6SendConfirmMsg ( + Instance->StartTime = 0; + + Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed); +- + if (EFI_ERROR (Status)) { +- FreePool (Packet); +- return Status; ++ goto ON_ERROR; + } + + // + // Enqueue the sent packet for the retransmission in case reply timeout. + // + return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL); ++ ++ON_ERROR: ++ ++ if (Packet) { ++ FreePool (Packet); ++ } ++ ++ return Status; + } + + /** +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c +index e6368b5b1c..705c665c51 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Utility.c +@@ -577,24 +577,33 @@ Dhcp6OnTransmitted ( + } + + /** +- Append the option to Buf, and move Buf to the end. ++ Append the option to Buf, update the length of packet, and move Buf to the end. + +- @param[in, out] Buf The pointer to the buffer. +- @param[in] OptType The option type. +- @param[in] OptLen The length of option contents. +- @param[in] Data The pointer to the option content. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ will be updated. ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. ++ @param[in] OptType The option type. ++ @param[in] OptLen The length of option contents. ++ @param[in] Data The pointer to the option content. + +- @return Buf The position to append the next option. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendOption ( +- IN OUT UINT8 *Buf, +- IN UINT16 OptType, +- IN UINT16 OptLen, +- IN UINT8 *Data ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN UINT16 OptType, ++ IN UINT16 OptLen, ++ IN UINT8 *Data + ) + { ++ UINT32 Length; ++ UINT32 BytesNeeded; ++ + // + // The format of Dhcp6 option: + // +@@ -607,35 +616,95 @@ Dhcp6AppendOption ( + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + +- ASSERT (OptLen != 0); ++ // ++ // Verify the arguments are valid ++ // ++ if (Packet == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (Data == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (OptLen == 0) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Verify the PacketCursor is within the packet ++ // ++ if ( (*PacketCursor < Packet->Dhcp6.Option) ++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Calculate the bytes needed for the option ++ // ++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN + NTOHS (OptLen); ++ ++ // ++ // Space remaining in the packet ++ // ++ Length = Packet->Size - Packet->Length; ++ if (Length < BytesNeeded) { ++ return EFI_BUFFER_TOO_SMALL; ++ } ++ ++ // ++ // Verify the PacketCursor is within the packet ++ // ++ if ( (*PacketCursor < Packet->Dhcp6.Option) ++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, OptType); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, OptLen); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; ++ CopyMem (*PacketCursor, Data, NTOHS (OptLen)); ++ *PacketCursor += NTOHS (OptLen); + +- WriteUnaligned16 ((UINT16 *)Buf, OptType); +- Buf += 2; +- WriteUnaligned16 ((UINT16 *)Buf, OptLen); +- Buf += 2; +- CopyMem (Buf, Data, NTOHS (OptLen)); +- Buf += NTOHS (OptLen); ++ // Update the packet length by the length of the option + 4 bytes ++ Packet->Length += BytesNeeded; + +- return Buf; ++ return EFI_SUCCESS; + } + + /** + Append the appointed IA Address option to Buf, and move Buf to the end. + +- @param[in, out] Buf The pointer to the position to append. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ will be updated. ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. + @param[in] IaAddr The pointer to the IA Address. + @param[in] MessageType Message type of DHCP6 package. + +- @return Buf The position to append the next option. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendIaAddrOption ( +- IN OUT UINT8 *Buf, ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, + IN EFI_DHCP6_IA_ADDRESS *IaAddr, + IN UINT32 MessageType + ) + { ++ UINT32 BytesNeeded; ++ UINT32 Length; ++ + // The format of the IA Address option is: + // + // 0 1 2 3 +@@ -657,17 +726,60 @@ Dhcp6AppendIaAddrOption ( + // . . + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++ // ++ // Verify the arguments are valid ++ // ++ if (Packet == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (IaAddr == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Verify the PacketCursor is within the packet ++ // ++ if ( (*PacketCursor < Packet->Dhcp6.Option) ++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; ++ BytesNeeded += sizeof (EFI_IPv6_ADDRESS); ++ // ++ // Even if the preferred-lifetime is 0, it still needs to store it. ++ // ++ BytesNeeded += sizeof (IaAddr->PreferredLifetime); ++ // ++ // Even if the valid-lifetime is 0, it still needs to store it. ++ // ++ BytesNeeded += sizeof (IaAddr->ValidLifetime); ++ ++ // ++ // Space remaining in the packet ++ // ++ Length = Packet->Size - Packet->Length; ++ if (Length < BytesNeeded) { ++ return EFI_BUFFER_TOO_SMALL; ++ } ++ + // + // Fill the value of Ia Address option type + // +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptIaAddr)); +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptIaAddr)); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; + +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (sizeof (EFI_DHCP6_IA_ADDRESS))); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; + +- CopyMem (Buf, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); +- Buf += sizeof (EFI_IPv6_ADDRESS); ++ CopyMem (*PacketCursor, &IaAddr->IpAddress, sizeof (EFI_IPv6_ADDRESS)); ++ *PacketCursor += sizeof (EFI_IPv6_ADDRESS); + + // + // Fill the value of preferred-lifetime and valid-lifetime. +@@ -675,44 +787,58 @@ Dhcp6AppendIaAddrOption ( + // should set to 0 when initiate a Confirm message. + // + if (MessageType != Dhcp6MsgConfirm) { +- WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->PreferredLifetime)); ++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->PreferredLifetime)); + } + +- Buf += 4; ++ *PacketCursor += sizeof (IaAddr->PreferredLifetime); + + if (MessageType != Dhcp6MsgConfirm) { +- WriteUnaligned32 ((UINT32 *)Buf, HTONL (IaAddr->ValidLifetime)); ++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (IaAddr->ValidLifetime)); + } + +- Buf += 4; ++ *PacketCursor += sizeof (IaAddr->ValidLifetime); ++ ++ // ++ // Update the packet length ++ // ++ Packet->Length += BytesNeeded; + +- return Buf; ++ return EFI_SUCCESS; + } + + /** + Append the appointed Ia option to Buf, and move Buf to the end. + +- @param[in, out] Buf The pointer to the position to append. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ will be updated. ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. + @param[in] Ia The pointer to the Ia. + @param[in] T1 The time of T1. + @param[in] T2 The time of T2. + @param[in] MessageType Message type of DHCP6 package. + +- @return Buf The position to append the next Ia option. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendIaOption ( +- IN OUT UINT8 *Buf, +- IN EFI_DHCP6_IA *Ia, +- IN UINT32 T1, +- IN UINT32 T2, +- IN UINT32 MessageType ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN EFI_DHCP6_IA *Ia, ++ IN UINT32 T1, ++ IN UINT32 T2, ++ IN UINT32 MessageType + ) + { +- UINT8 *AddrOpt; +- UINT16 *Len; +- UINTN Index; ++ UINT8 *AddrOpt; ++ UINT16 *Len; ++ UINTN Index; ++ UINT32 BytesNeeded; ++ UINT32 Length; ++ EFI_STATUS Status; + + // + // The format of IA_NA and IA_TA option: +@@ -733,32 +859,74 @@ Dhcp6AppendIaOption ( + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + ++ // ++ // Verify the arguments are valid ++ // ++ if (Packet == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (Ia == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Verify the PacketCursor is within the packet ++ // ++ if ( (*PacketCursor < Packet->Dhcp6.Option) ++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; ++ BytesNeeded += sizeof (Ia->Descriptor.IaId); ++ // ++ // + N for the IA_NA-options/IA_TA-options ++ // Dhcp6AppendIaAddrOption will need to check the length for each address ++ // ++ if (Ia->Descriptor.Type == Dhcp6OptIana) { ++ BytesNeeded += sizeof (T1) + sizeof (T2); ++ } ++ ++ // ++ // Space remaining in the packet ++ // ++ Length = (UINT16)(Packet->Size - Packet->Length); ++ if (Length < BytesNeeded) { ++ return EFI_BUFFER_TOO_SMALL; ++ } ++ + // + // Fill the value of Ia option type + // +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Ia->Descriptor.Type)); +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Ia->Descriptor.Type)); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; + + // + // Fill the len of Ia option later, keep the pointer first + // +- Len = (UINT16 *)Buf; +- Buf += 2; ++ Len = (UINT16 *)*PacketCursor; ++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; + + // + // Fill the value of iaid + // +- WriteUnaligned32 ((UINT32 *)Buf, HTONL (Ia->Descriptor.IaId)); +- Buf += 4; ++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL (Ia->Descriptor.IaId)); ++ *PacketCursor += sizeof (Ia->Descriptor.IaId); + + // + // Fill the value of t1 and t2 if iana, keep it 0xffffffff if no specified. + // + if (Ia->Descriptor.Type == Dhcp6OptIana) { +- WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T1 != 0) ? T1 : 0xffffffff)); +- Buf += 4; +- WriteUnaligned32 ((UINT32 *)Buf, HTONL ((T2 != 0) ? T2 : 0xffffffff)); +- Buf += 4; ++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T1 != 0) ? T1 : 0xffffffff)); ++ *PacketCursor += sizeof (T1); ++ WriteUnaligned32 ((UINT32 *)*PacketCursor, HTONL ((T2 != 0) ? T2 : 0xffffffff)); ++ *PacketCursor += sizeof (T2); + } + + // +@@ -766,35 +934,51 @@ Dhcp6AppendIaOption ( + // + for (Index = 0; Index < Ia->IaAddressCount; Index++) { + AddrOpt = (UINT8 *)Ia->IaAddress + Index * sizeof (EFI_DHCP6_IA_ADDRESS); +- Buf = Dhcp6AppendIaAddrOption (Buf, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); ++ Status = Dhcp6AppendIaAddrOption (Packet, PacketCursor, (EFI_DHCP6_IA_ADDRESS *)AddrOpt, MessageType); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } + } + + // + // Fill the value of Ia option length + // +- *Len = HTONS ((UINT16)(Buf - (UINT8 *)Len - 2)); ++ *Len = HTONS ((UINT16)(*PacketCursor - (UINT8 *)Len - 2)); + +- return Buf; ++ // ++ // Update the packet length ++ // ++ Packet->Length += BytesNeeded; ++ ++ return EFI_SUCCESS; + } + + /** + Append the appointed Elapsed time option to Buf, and move Buf to the end. + +- @param[in, out] Buf The pointer to the position to append. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. + @param[in] Instance The pointer to the Dhcp6 instance. + @param[out] Elapsed The pointer to the elapsed time value in +- the generated packet. ++ the generated packet. + +- @return Buf The position to append the next Ia option. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendETOption ( +- IN OUT UINT8 *Buf, +- IN DHCP6_INSTANCE *Instance, +- OUT UINT16 **Elapsed ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN DHCP6_INSTANCE *Instance, ++ OUT UINT16 **Elapsed + ) + { ++ UINT32 BytesNeeded; ++ UINT32 Length; ++ + // + // The format of elapsed time option: + // +@@ -806,27 +990,70 @@ Dhcp6AppendETOption ( + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + ++ // ++ // Verify the arguments are valid ++ // ++ if (Packet == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((PacketCursor == NULL) || (*PacketCursor == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (Instance == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if ((Elapsed == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Verify the PacketCursor is within the packet ++ // ++ if ( (*PacketCursor < Packet->Dhcp6.Option) ++ || (*PacketCursor >= Packet->Dhcp6.Option + (Packet->Size - sizeof (EFI_DHCP6_HEADER)))) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BytesNeeded = DHCP6_SIZE_OF_COMBINED_CODE_AND_LEN; ++ // ++ // + 2 for elapsed-time ++ // ++ BytesNeeded += sizeof (UINT16); ++ // ++ // Space remaining in the packet ++ // ++ Length = Packet->Size - Packet->Length; ++ if (Length < BytesNeeded) { ++ return EFI_BUFFER_TOO_SMALL; ++ } ++ + // + // Fill the value of elapsed-time option type. + // +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (Dhcp6OptElapsedTime)); +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (Dhcp6OptElapsedTime)); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_CODE; + + // + // Fill the len of elapsed-time option, which is fixed. + // +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (2)); +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (2)); ++ *PacketCursor += DHCP6_SIZE_OF_OPT_LEN; + + // + // Fill in elapsed time value with 0 value for now. The actual value is + // filled in later just before the packet is transmitted. + // +- WriteUnaligned16 ((UINT16 *)Buf, HTONS (0)); +- *Elapsed = (UINT16 *)Buf; +- Buf += 2; ++ WriteUnaligned16 ((UINT16 *)*PacketCursor, HTONS (0)); ++ *Elapsed = (UINT16 *)*PacketCursor; ++ *PacketCursor += sizeof (UINT16); + +- return Buf; ++ Packet->Length += BytesNeeded; ++ ++ return EFI_SUCCESS; + } + + /** +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 ( + ); + + /** +- Append the appointed option to the buf, and move the buf to the end. +- +- @param[in, out] Buf The pointer to buffer. +- @param[in] OptType The option type. +- @param[in] OptLen The length of option content.s +- @param[in] Data The pointer to the option content. +- +- @return Buf The position to append the next option. +- ++ Append the option to Buf, update the length of packet, and move Buf to the end. ++ ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ will be updated. ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. ++ @param[in] OptType The option type. ++ @param[in] OptLen The length of option contents. ++ @param[in] Data The pointer to the option content. ++ ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendOption ( +- IN OUT UINT8 *Buf, +- IN UINT16 OptType, +- IN UINT16 OptLen, +- IN UINT8 *Data ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN UINT16 OptType, ++ IN UINT16 OptLen, ++ IN UINT8 *Data + ); + + /** +- Append the Ia option to Buf, and move Buf to the end. +- +- @param[in, out] Buf The pointer to the position to append. ++ Append the appointed Ia option to Buf, update the Ia option length, and move Buf ++ to the end of the option. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ will be updated. ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. + @param[in] Ia The pointer to the Ia. + @param[in] T1 The time of T1. + @param[in] T2 The time of T2. + @param[in] MessageType Message type of DHCP6 package. + +- @return Buf The position to append the next Ia option. +- ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendIaOption ( +- IN OUT UINT8 *Buf, +- IN EFI_DHCP6_IA *Ia, +- IN UINT32 T1, +- IN UINT32 T2, +- IN UINT32 MessageType ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN EFI_DHCP6_IA *Ia, ++ IN UINT32 T1, ++ IN UINT32 T2, ++ IN UINT32 MessageType + ); + + /** + Append the appointed Elapsed time option to Buf, and move Buf to the end. + +- @param[in, out] Buf The pointer to the position to append. ++ @param[in, out] Packet A pointer to the packet, on success Packet->Length ++ @param[in, out] PacketCursor The pointer in the packet, on success PacketCursor ++ will be moved to the end of the option. + @param[in] Instance The pointer to the Dhcp6 instance. + @param[out] Elapsed The pointer to the elapsed time value in + the generated packet. + +- @return Buf The position to append the next Ia option. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + + **/ +-UINT8 * ++EFI_STATUS + Dhcp6AppendETOption ( +- IN OUT UINT8 *Buf, +- IN DHCP6_INSTANCE *Instance, +- OUT UINT16 **Elapsed ++ IN OUT EFI_DHCP6_PACKET *Packet, ++ IN OUT UINT8 **PacketCursor, ++ IN DHCP6_INSTANCE *Instance, ++ OUT UINT16 **Elapsed + ); + + /** + Set the elapsed time based on the given instance and the pointer to the + elapsed time option. + +- @param[in] Elapsed The pointer to the position to append. +- @param[in] Instance The pointer to the Dhcp6 instance. ++ @retval EFI_INVALID_PARAMETER An argument provided to the function was invalid ++ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to append the option. ++ @retval EFI_SUCCESS The option is appended successfully. + **/ + VOID + SetElapsedTime ( +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0002.patch new file mode 100644 index 0000000000..1f891f8007 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45230-0002.patch @@ -0,0 +1,604 @@ +From 5f3658197bf29c83b3349b0ab1d99cdb0c3814bc Mon Sep 17 00:00:00 2001 +From: "Doug Flick via groups.io" +Date: Fri, 26 Jan 2024 05:54:45 +0800 +Subject: [PATCH] NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit + Tests + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4535 + +Confirms that reported issue... + +"Buffer overflow in the DHCPv6 client via a long Server ID option" + +..has been corrected by the provided patch. + +Tests the following functions to ensure they appropriately handle +untrusted data (either too long or too small) to prevent a buffer +overflow: + +Dhcp6AppendOption +Dhcp6AppendETOption +Dhcp6AppendIaOption + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45230 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/5f3658197bf29c83b3349b0ab1d99cdb0c3814bc] + +Signed-off-by: Soumya Sambu +--- + .../GoogleTest/Dhcp6DxeGoogleTest.cpp | 20 + + .../GoogleTest/Dhcp6DxeGoogleTest.inf | 43 ++ + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 478 ++++++++++++++++++ + 3 files changed, 541 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 + +diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp +new file mode 100644 +index 0000000000..9aeced2f91 +--- /dev/null ++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.cpp +@@ -0,0 +1,20 @@ ++/** @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 ++ ++//////////////////////////////////////////////////////////////////////////////// ++// 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 +new file mode 100644 +index 0000000000..8e9119a371 +--- /dev/null ++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf +@@ -0,0 +1,43 @@ ++## @file ++# Unit test suite for the Dhcp6Dxe using Google Test ++# ++# Copyright (c) Microsoft Corporation.
++# 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 +diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +new file mode 100644 +index 0000000000..7ee40e4af4 +--- /dev/null ++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +@@ -0,0 +1,478 @@ ++/** @file ++ Tests for Dhcp6Io.c. ++ ++ Copyright (c) Microsoft Corporation ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include ++ ++extern "C" { ++ #include ++ #include ++ #include ++ #include ++ #include "../Dhcp6Impl.h" ++ #include "../Dhcp6Utility.h" ++} ++ ++//////////////////////////////////////////////////////////////////////// ++// Defines ++//////////////////////////////////////////////////////////////////////// ++ ++#define DHCP6_PACKET_MAX_LEN 1500 ++ ++//////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////// ++// Symbol Definitions ++// These functions are not directly under test - but required to compile ++//////////////////////////////////////////////////////////////////////// ++ ++// This definition is used by this test but is also required to compile ++// by Dhcp6Io.c ++EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = { ++ { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 } ++}; ++ ++EFI_STATUS ++EFIAPI ++UdpIoSendDatagram ( ++ IN UDP_IO *UdpIo, ++ IN NET_BUF *Packet, ++ IN UDP_END_POINT *EndPoint OPTIONAL, ++ IN EFI_IP_ADDRESS *Gateway OPTIONAL, ++ IN UDP_IO_CALLBACK CallBack, ++ IN VOID *Context ++ ) ++{ ++ return EFI_SUCCESS; ++} ++ ++EFI_STATUS ++EFIAPI ++UdpIoRecvDatagram ( ++ IN UDP_IO *UdpIo, ++ IN UDP_IO_CALLBACK CallBack, ++ IN VOID *Context, ++ IN UINT32 HeadLen ++ ) ++{ ++ return EFI_SUCCESS; ++} ++ ++//////////////////////////////////////////////////////////////////////// ++// Dhcp6AppendOptionTest Tests ++//////////////////////////////////////////////////////////////////////// ++ ++class Dhcp6AppendOptionTest : public ::testing::Test { ++public: ++ UINT8 *Buffer = NULL; ++ EFI_DHCP6_PACKET *Packet; ++ ++protected: ++ // Add any setup code if needed ++ virtual void ++ SetUp ( ++ ) ++ { ++ // Initialize any resources or variables ++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); ++ ASSERT_NE (Buffer, (UINT8 *)NULL); ++ ++ Packet = (EFI_DHCP6_PACKET *)Buffer; ++ Packet->Size = DHCP6_PACKET_MAX_LEN; ++ } ++ ++ // Add any cleanup code if needed ++ virtual void ++ TearDown ( ++ ) ++ { ++ // Clean up any resources or variables ++ if (Buffer != NULL) { ++ FreePool (Buffer); ++ } ++ } ++}; ++ ++// Test Description: ++// Attempt to append an option to a packet that is too small by a duid that is too large ++TEST_F (Dhcp6AppendOptionTest, InvalidDataExpectBufferTooSmall) { ++ UINT8 *Cursor; ++ EFI_DHCP6_DUID *UntrustedDuid; ++ EFI_STATUS Status; ++ ++ UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); ++ ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); ++ ++ UntrustedDuid->Length = NTOHS (0xFFFF); ++ ++ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; ++ ++ Status = Dhcp6AppendOption ( ++ Dhcp6AppendOptionTest::Packet, ++ &Cursor, ++ HTONS (Dhcp6OptServerId), ++ UntrustedDuid->Length, ++ UntrustedDuid->Duid ++ ); ++ ++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); ++} ++ ++// Test Description: ++// Attempt to append an option to a packet that is large enough ++TEST_F (Dhcp6AppendOptionTest, ValidDataExpectSuccess) { ++ UINT8 *Cursor; ++ EFI_DHCP6_DUID *UntrustedDuid; ++ EFI_STATUS Status; ++ UINTN OriginalLength; ++ ++ UINT8 Duid[6] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; ++ ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ OriginalLength = Packet->Length; ++ ++ UntrustedDuid = (EFI_DHCP6_DUID *)AllocateZeroPool (sizeof (EFI_DHCP6_DUID)); ++ ASSERT_NE (UntrustedDuid, (EFI_DHCP6_DUID *)NULL); ++ ++ UntrustedDuid->Length = NTOHS (sizeof (Duid)); ++ CopyMem (UntrustedDuid->Duid, Duid, sizeof (Duid)); ++ ++ Cursor = Dhcp6AppendOptionTest::Packet->Dhcp6.Option; ++ ++ Status = Dhcp6AppendOption ( ++ Dhcp6AppendOptionTest::Packet, ++ &Cursor, ++ HTONS (Dhcp6OptServerId), ++ UntrustedDuid->Length, ++ UntrustedDuid->Duid ++ ); ++ ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ // verify that the pointer to cursor moved by the expected amount ++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendOptionTest::Packet->Dhcp6.Option + sizeof (Duid) + 4); ++ ++ // verify that the length of the packet is now the expected amount ++ ASSERT_EQ (Dhcp6AppendOptionTest::Packet->Length, OriginalLength + sizeof (Duid) + 4); ++} ++ ++//////////////////////////////////////////////////////////////////////// ++// Dhcp6AppendETOption Tests ++//////////////////////////////////////////////////////////////////////// ++ ++class Dhcp6AppendETOptionTest : public ::testing::Test { ++public: ++ UINT8 *Buffer = NULL; ++ EFI_DHCP6_PACKET *Packet; ++ ++protected: ++ // Add any setup code if needed ++ virtual void ++ SetUp ( ++ ) ++ { ++ // Initialize any resources or variables ++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); ++ ASSERT_NE (Buffer, (UINT8 *)NULL); ++ ++ Packet = (EFI_DHCP6_PACKET *)Buffer; ++ Packet->Size = DHCP6_PACKET_MAX_LEN; ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ } ++ ++ // Add any cleanup code if needed ++ virtual void ++ TearDown ( ++ ) ++ { ++ // Clean up any resources or variables ++ if (Buffer != NULL) { ++ FreePool (Buffer); ++ } ++ } ++}; ++ ++// Test Description: ++// Attempt to append an option to a packet that is too small by a duid that is too large ++TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ DHCP6_INSTANCE Instance; ++ UINT16 ElapsedTimeVal; ++ UINT16 *ElapsedTime; ++ ++ Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; ++ ElapsedTime = &ElapsedTimeVal; ++ ++ Packet->Length = Packet->Size - 2; ++ ++ Status = Dhcp6AppendETOption ( ++ Dhcp6AppendETOptionTest::Packet, ++ &Cursor, ++ &Instance, // Instance is not used in this function ++ &ElapsedTime ++ ); ++ ++ // verify that we error out because the packet is too small for the option header ++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); ++ ++ // reset the length ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++} ++ ++// Test Description: ++// Attempt to append an option to a packet that is large enough ++TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ DHCP6_INSTANCE Instance; ++ UINT16 ElapsedTimeVal; ++ UINT16 *ElapsedTime; ++ UINTN ExpectedSize; ++ UINTN OriginalLength; ++ ++ Cursor = Dhcp6AppendETOptionTest::Packet->Dhcp6.Option; ++ ElapsedTime = &ElapsedTimeVal; ++ ExpectedSize = 6; ++ OriginalLength = Packet->Length; ++ ++ Status = Dhcp6AppendETOption ( ++ Dhcp6AppendETOptionTest::Packet, ++ &Cursor, ++ &Instance, // Instance is not used in this function ++ &ElapsedTime ++ ); ++ ++ // verify that the status is EFI_SUCCESS ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ // verify that the pointer to cursor moved by the expected amount ++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendETOptionTest::Packet->Dhcp6.Option + ExpectedSize); ++ ++ // verify that the length of the packet is now the expected amount ++ ASSERT_EQ (Dhcp6AppendETOptionTest::Packet->Length, OriginalLength + ExpectedSize); ++} ++ ++//////////////////////////////////////////////////////////////////////// ++// Dhcp6AppendIaOption Tests ++//////////////////////////////////////////////////////////////////////// ++ ++class Dhcp6AppendIaOptionTest : public ::testing::Test { ++public: ++ UINT8 *Buffer = NULL; ++ EFI_DHCP6_PACKET *Packet; ++ EFI_DHCP6_IA *Ia; ++ ++protected: ++ // Add any setup code if needed ++ virtual void ++ SetUp ( ++ ) ++ { ++ // Initialize any resources or variables ++ Buffer = (UINT8 *)AllocateZeroPool (DHCP6_PACKET_MAX_LEN); ++ ASSERT_NE (Buffer, (UINT8 *)NULL); ++ ++ Packet = (EFI_DHCP6_PACKET *)Buffer; ++ Packet->Size = DHCP6_PACKET_MAX_LEN; ++ ++ Ia = (EFI_DHCP6_IA *)AllocateZeroPool (sizeof (EFI_DHCP6_IA) + sizeof (EFI_DHCP6_IA_ADDRESS) * 2); ++ ASSERT_NE (Ia, (EFI_DHCP6_IA *)NULL); ++ ++ CopyMem (Ia->IaAddress, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); ++ CopyMem (Ia->IaAddress + 1, mAllDhcpRelayAndServersAddress.Addr, sizeof (EFI_IPv6_ADDRESS)); ++ ++ Ia->IaAddressCount = 2; ++ } ++ ++ // Add any cleanup code if needed ++ virtual void ++ TearDown ( ++ ) ++ { ++ // Clean up any resources or variables ++ if (Buffer != NULL) { ++ FreePool (Buffer); ++ } ++ ++ if (Ia != NULL) { ++ FreePool (Ia); ++ } ++ } ++}; ++ ++// Test Description: ++// Attempt to append an option to a packet that doesn't have enough space ++// for the option header ++TEST_F (Dhcp6AppendIaOptionTest, IaNaInvalidDataExpectBufferTooSmall) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ ++ Packet->Length = Packet->Size - 2; ++ ++ Ia->Descriptor.Type = Dhcp6OptIana; ++ Ia->Descriptor.IaId = 0x12345678; ++ ++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; ++ ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6AppendIaOptionTest::Packet, ++ &Cursor, ++ Ia, ++ 0x12345678, ++ 0x11111111, ++ Dhcp6OptIana ++ ); ++ ++ // verify that we error out because the packet is too small for the option header ++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); ++ ++ // reset the length ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++} ++ ++// Test Description: ++// Attempt to append an option to a packet that doesn't have enough space ++// for the option header ++TEST_F (Dhcp6AppendIaOptionTest, IaTaInvalidDataExpectBufferTooSmall) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ ++ // Use up nearly all the space in the packet ++ Packet->Length = Packet->Size - 2; ++ ++ Ia->Descriptor.Type = Dhcp6OptIata; ++ Ia->Descriptor.IaId = 0x12345678; ++ ++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; ++ ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6AppendIaOptionTest::Packet, ++ &Cursor, ++ Ia, ++ 0, ++ 0, ++ Dhcp6OptIata ++ ); ++ ++ // verify that we error out because the packet is too small for the option header ++ ASSERT_EQ (Status, EFI_BUFFER_TOO_SMALL); ++ ++ // reset the length ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++} ++ ++TEST_F (Dhcp6AppendIaOptionTest, IaNaValidDataExpectSuccess) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ UINTN ExpectedSize; ++ UINTN OriginalLength; ++ ++ // ++ // 2 bytes for the option header type ++ // ++ ExpectedSize = 2; ++ // ++ // 2 bytes for the option header length ++ // ++ ExpectedSize += 2; ++ // ++ // 4 bytes for the IAID ++ // ++ ExpectedSize += 4; ++ // ++ // + 4 bytes for the T1 ++ // ++ ExpectedSize += 4; ++ // ++ // + 4 bytes for the T2 ++ // ++ ExpectedSize += 4; ++ // ++ // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; ++ // + 2 bytes for the option header type ++ // + 2 bytes for the option header length ++ // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address ++ // ++ ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; ++ ++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; ++ ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ OriginalLength = Packet->Length; ++ ++ Ia->Descriptor.Type = Dhcp6OptIana; ++ Ia->Descriptor.IaId = 0x12345678; ++ ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6AppendIaOptionTest::Packet, ++ &Cursor, ++ Ia, ++ 0x12345678, ++ 0x12345678, ++ Dhcp6OptIana ++ ); ++ ++ // verify that the pointer to cursor moved by the expected amount ++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); ++ ++ // verify that the length of the packet is now the expected amount ++ ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); ++ ++ // verify that the status is EFI_SUCCESS ++ ASSERT_EQ (Status, EFI_SUCCESS); ++} ++ ++TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { ++ UINT8 *Cursor; ++ EFI_STATUS Status; ++ UINTN ExpectedSize; ++ UINTN OriginalLength; ++ ++ // ++ // 2 bytes for the option header type ++ // ++ ExpectedSize = 2; ++ // ++ // 2 bytes for the option header length ++ // ++ ExpectedSize += 2; ++ // ++ // 4 bytes for the IAID ++ // ++ ExpectedSize += 4; ++ // ++ // + (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; ++ // + 2 bytes for the option header type ++ // + 2 bytes for the option header length ++ // + sizeof (EFI_DHCP6_IA_ADDRESS) for the IA Address ++ // ++ ExpectedSize += (4 + sizeof (EFI_DHCP6_IA_ADDRESS)) * 2; ++ ++ Cursor = Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option; ++ ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ OriginalLength = Packet->Length; ++ ++ Ia->Descriptor.Type = Dhcp6OptIata; ++ Ia->Descriptor.IaId = 0x12345678; ++ ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6AppendIaOptionTest::Packet, ++ &Cursor, ++ Ia, ++ 0, ++ 0, ++ Dhcp6OptIata ++ ); ++ ++ // verify that the pointer to cursor moved by the expected amount ++ ASSERT_EQ (Cursor, (UINT8 *)Dhcp6AppendIaOptionTest::Packet->Dhcp6.Option + ExpectedSize); ++ ++ // verify that the length of the packet is now the expected amount ++ ASSERT_EQ (Dhcp6AppendIaOptionTest::Packet->Length, OriginalLength + ExpectedSize); ++ ++ // verify that the status is EFI_SUCCESS ++ ASSERT_EQ (Status, EFI_SUCCESS); ++} +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 59e5598a1b..957a74aabe 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -33,6 +33,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2022-36764-0001.patch \ file://CVE-2022-36764-0002.patch \ file://CVE-2022-36764-0003.patch \ + file://CVE-2023-45230-0001.patch \ + file://CVE-2023-45230-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46192 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C14AEC41513 for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) by mx.groups.io with SMTP id smtpd.web10.4974.1720673769481776641 for ; Wed, 10 Jul 2024 21:56:09 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.178.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250812.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4Qe1Z013125 for ; Thu, 11 Jul 2024 04:56:08 GMT Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 406vw64gk6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Jul 2024 04:56:08 +0000 (GMT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:05 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 04/11] ovmf: Fix CVE-2023-45231 Date: Thu, 11 Jul 2024 04:55:34 +0000 Message-ID: <20240711045541.2155076-4-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-ORIG-GUID: M7FD_0MY_DnjI2wMJOMV24SiURqdX3xI X-Proofpoint-GUID: M7FD_0MY_DnjI2wMJOMV24SiURqdX3xI X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 lowpriorityscore=0 bulkscore=0 priorityscore=1501 phishscore=0 malwarescore=0 clxscore=1015 adultscore=0 impostorscore=0 mlxlogscore=999 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201754 From: Soumya Sambu EDK2's Network Package is susceptible to an out-of-bounds read vulnerability when processing Neighbor Discovery Redirect message. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45231 Upstream-patches: https://github.com/tianocore/edk2/commit/bbfee34f4188ac00371abe1389ae9c9fb989a0cd https://github.com/tianocore/edk2/commit/6f77463d72807ec7f4ed6518c3dac29a1040df9f Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45231-0001.patch | 65 +++++ .../ovmf/ovmf/CVE-2023-45231-0002.patch | 250 ++++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 317 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0001.patch new file mode 100644 index 0000000000..7aa9b27407 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0001.patch @@ -0,0 +1,65 @@ +From bbfee34f4188ac00371abe1389ae9c9fb989a0cd Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:48 +0800 +Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 Patch + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 + +Bug Overview: +PixieFail Bug #3 +CVE-2023-45231 +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 + +Out-of-bounds read when handling a ND Redirect message with truncated +options + +Change Overview: + +Adds a check to prevent truncated options from being parsed ++ // ++ // Cannot process truncated options. ++ // Cannot process options with a length of 0 as there is no Type +field. ++ // ++ if (OptionLen < sizeof (IP6_OPTION_HEADER)) { ++ return FALSE; ++ } + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45231 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/bbfee34f4188ac00371abe1389ae9c9fb989a0cd] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Ip6Dxe/Ip6Option.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c +index 199eea124d..8718d5d875 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Option.c ++++ b/NetworkPkg/Ip6Dxe/Ip6Option.c +@@ -137,6 +137,14 @@ Ip6IsNDOptionValid ( + return FALSE; + } + ++ // ++ // Cannot process truncated options. ++ // Cannot process options with a length of 0 as there is no Type field. ++ // ++ if (OptionLen < sizeof (IP6_OPTION_HEADER)) { ++ return FALSE; ++ } ++ + Offset = 0; + + // +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0002.patch new file mode 100644 index 0000000000..fbc2c4416e --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45231-0002.patch @@ -0,0 +1,250 @@ +From 6f77463d72807ec7f4ed6518c3dac29a1040df9f Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:49 +0800 +Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45231 Unit Tests + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4536 + +Validates that the patch for... + +Out-of-bounds read when handling a ND Redirect message with truncated +options + +.. has been fixed + +Tests the following function to ensure that an out of bounds read does +not occur +Ip6OptionValidation + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45231 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/6f77463d72807ec7f4ed6518c3dac29a1040df9f] + +Signed-off-by: Soumya Sambu +--- + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp | 20 +++ + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 42 ++++++ + .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 129 ++++++++++++++++++ + 3 files changed, 191 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..6ebfd5fdfb +--- /dev/null ++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.cpp +@@ -0,0 +1,20 @@ ++/** @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 ++ ++//////////////////////////////////////////////////////////////////////////////// ++// 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..6e4de0745f +--- /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.
++# 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 +diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp +new file mode 100644 +index 0000000000..f2cd90e1a9 +--- /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 ++ ++extern "C" { ++ #include ++ #include ++ #include ++ #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, sizeof (IP6_OPTION_HEADER)); ++ ++ EXPECT_TRUE (Ip6IsNDOptionValid (option, IP6_PREFIX_INFO_OPTION_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)); ++} +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 957a74aabe..e46b3ddebe 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -35,6 +35,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2022-36764-0003.patch \ file://CVE-2023-45230-0001.patch \ file://CVE-2023-45230-0002.patch \ + file://CVE-2023-45231-0001.patch \ + file://CVE-2023-45231-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46193 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BEE3DC3271E for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web11.4941.1720673771003024590 for ; Wed, 10 Jul 2024 21:56:11 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250810.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4tMnv031582 for ; Wed, 10 Jul 2024 21:56:10 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 407170mcjn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:09 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:07 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 05/11] ovmf: Fix CVE-2023-45232, CVE-2023-45233 Date: Thu, 11 Jul 2024 04:55:35 +0000 Message-ID: <20240711045541.2155076-5-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: wuu_JfsZRztxBMGcFw8L0uIEbJ4uIQZc X-Proofpoint-ORIG-GUID: wuu_JfsZRztxBMGcFw8L0uIEbJ4uIQZc X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 impostorscore=0 malwarescore=0 phishscore=0 adultscore=0 lowpriorityscore=0 spamscore=0 suspectscore=0 bulkscore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201755 From: Soumya Sambu CVE-2023-45232: EDK2's Network Package is susceptible to an infinite loop vulnerability when parsing unknown options in the Destination Options header of IPv6. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Availability. CVE-2023-45233: EDK2's Network Package is susceptible to an infinite lop vulnerability when parsing a PadN option in the Destination Options header of IPv6. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Availability. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45232 https://nvd.nist.gov/vuln/detail/CVE-2023-45233 Upstream-patches: https://github.com/tianocore/edk2/commit/4df0229ef992d4f2721a8508787ebf9dc81fbd6e https://github.com/tianocore/edk2/commit/c9c87f08dd6ace36fa843424522c3558a8374cac Signed-off-by: Soumya Sambu --- .../CVE-2023-45232-CVE-2023-45233-0001.patch | 360 +++++++++++++++ .../CVE-2023-45232-CVE-2023-45233-0002.patch | 417 ++++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 779 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch new file mode 100644 index 0000000000..d43e971d9d --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0001.patch @@ -0,0 +1,360 @@ +From 4df0229ef992d4f2721a8508787ebf9dc81fbd6e Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:50 +0800 +Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Patch + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 + +Bug Details: +PixieFail Bug #4 +CVE-2023-45232 +CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H +CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') + +Infinite loop when parsing unknown options in the Destination Options +header + +PixieFail Bug #5 +CVE-2023-45233 +CVSS 7.5 : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H +CWE-835 Loop with Unreachable Exit Condition ('Infinite Loop') + +Infinite loop when parsing a PadN option in the Destination Options +header + +Change Overview: + +Most importantly this change corrects the following incorrect math +and cleans up the code. + +> // It is a PadN option +> // +> - Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2); +> + OptDataLen = ((EFI_IP6_OPTION *)(Option + Offset))->Length; +> + Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); + +> case Ip6OptionSkip: +> - Offset = (UINT8)(Offset + *(Option + Offset + 1)); +> OptDataLen = ((EFI_IP6_OPTION *)(Option + Offset))->Length; +> Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); + +Additionally, this change also corrects incorrect math where the calling +function was calculating the HDR EXT optionLen as a uint8 instead of a +uint16 + +> - OptionLen = (UINT8)((*Option + 1) * 8 - 2); +> + OptionLen = IP6_HDR_EXT_LEN (*Option) - +IP6_COMBINED_SIZE_OF_NEXT_HDR_AND_LEN; + +Additionally this check adds additional logic to santize the incoming +data + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45232, CVE-2023-45233 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4df0229ef992d4f2721a8508787ebf9dc81fbd6e] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Ip6Dxe/Ip6Nd.h | 35 ++++++++++++++++ + NetworkPkg/Ip6Dxe/Ip6Option.c | 76 ++++++++++++++++++++++++++++++----- + NetworkPkg/Ip6Dxe/Ip6Option.h | 71 ++++++++++++++++++++++++++++++++ + 3 files changed, 171 insertions(+), 11 deletions(-) + +diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.h b/NetworkPkg/Ip6Dxe/Ip6Nd.h +index 860934a167..bf64e9114e 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Nd.h ++++ b/NetworkPkg/Ip6Dxe/Ip6Nd.h +@@ -56,13 +56,48 @@ VOID + VOID *Context + ); + ++// ++// Per RFC8200 Section 4.2 ++// ++// Two of the currently-defined extension headers -- the Hop-by-Hop ++// Options header and the Destination Options header -- carry a variable ++// number of type-length-value (TLV) encoded "options", of the following ++// format: ++// ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - ++// | Option Type | Opt Data Len | Option Data ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - - ++// ++// Option Type 8-bit identifier of the type of option. ++// ++// Opt Data Len 8-bit unsigned integer. Length of the Option ++// Data field of this option, in octets. ++// ++// Option Data Variable-length field. Option-Type-specific ++// data. ++// + typedef struct _IP6_OPTION_HEADER { ++ /// ++ /// identifier of the type of option. ++ /// + UINT8 Type; ++ /// ++ /// Length of the Option Data field of this option, in octets. ++ /// + UINT8 Length; ++ /// ++ /// Option-Type-specific data. ++ /// + } IP6_OPTION_HEADER; + + STATIC_ASSERT (sizeof (IP6_OPTION_HEADER) == 2, "IP6_OPTION_HEADER is expected to be exactly 2 bytes long."); + ++#define IP6_NEXT_OPTION_OFFSET(offset, length) (offset + sizeof(IP6_OPTION_HEADER) + length) ++STATIC_ASSERT ( ++ IP6_NEXT_OPTION_OFFSET (0, 0) == 2, ++ "The next option is minimally the combined size of the option tag and length" ++ ); ++ + typedef struct _IP6_ETHE_ADDR_OPTION { + UINT8 Type; + UINT8 Length; +diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.c b/NetworkPkg/Ip6Dxe/Ip6Option.c +index 8718d5d875..fd97ce116f 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Option.c ++++ b/NetworkPkg/Ip6Dxe/Ip6Option.c +@@ -17,7 +17,8 @@ + @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] OptionLen The length of all options, expressed in byte length of octets. ++ Maximum length is 2046 bytes or ((n + 1) * 8) - 2 where n is 255. + @param[in] Pointer Identifies the octet offset within + the invoking packet where the error was detected. + +@@ -31,12 +32,33 @@ Ip6IsOptionValid ( + IN IP6_SERVICE *IpSb, + IN NET_BUF *Packet, + IN UINT8 *Option, +- IN UINT8 OptionLen, ++ IN UINT16 OptionLen, + IN UINT32 Pointer + ) + { +- UINT8 Offset; +- UINT8 OptionType; ++ UINT16 Offset; ++ UINT8 OptionType; ++ UINT8 OptDataLen; ++ ++ if (Option == NULL) { ++ ASSERT (Option != NULL); ++ return FALSE; ++ } ++ ++ if ((OptionLen <= 0) || (OptionLen > IP6_MAX_EXT_DATA_LENGTH)) { ++ ASSERT (OptionLen > 0 && OptionLen <= IP6_MAX_EXT_DATA_LENGTH); ++ return FALSE; ++ } ++ ++ if (Packet == NULL) { ++ ASSERT (Packet != NULL); ++ return FALSE; ++ } ++ ++ if (IpSb == NULL) { ++ ASSERT (IpSb != NULL); ++ return FALSE; ++ } + + Offset = 0; + +@@ -54,7 +76,8 @@ Ip6IsOptionValid ( + // + // It is a PadN option + // +- Offset = (UINT8)(Offset + *(Option + Offset + 1) + 2); ++ OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length; ++ Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); + break; + case Ip6OptionRouterAlert: + // +@@ -69,7 +92,8 @@ Ip6IsOptionValid ( + // + switch (OptionType & Ip6OptionMask) { + case Ip6OptionSkip: +- Offset = (UINT8)(Offset + *(Option + Offset + 1)); ++ OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length; ++ Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen); + break; + case Ip6OptionDiscard: + return FALSE; +@@ -308,7 +332,7 @@ Ip6IsExtsValid ( + UINT32 Pointer; + UINT32 Offset; + UINT8 *Option; +- UINT8 OptionLen; ++ UINT16 OptionLen; + BOOLEAN Flag; + UINT8 CountD; + UINT8 CountA; +@@ -385,6 +409,36 @@ Ip6IsExtsValid ( + // Fall through + // + case IP6_DESTINATION: ++ // ++ // See https://www.rfc-editor.org/rfc/rfc2460#section-4.2 page 23 ++ // ++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ // | Next Header | Hdr Ext Len | | ++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++ // | | ++ // . . ++ // . Options . ++ // . . ++ // | | ++ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ // ++ // ++ // Next Header 8-bit selector. Identifies the type of header ++ // immediately following the Destination Options ++ // header. Uses the same values as the IPv4 ++ // Protocol field [RFC-1700 et seq.]. ++ // ++ // Hdr Ext Len 8-bit unsigned integer. Length of the ++ // Destination Options header in 8-octet units, not ++ // including the first 8 octets. ++ // ++ // Options Variable-length field, of length such that the ++ // complete Destination Options header is an ++ // integer multiple of 8 octets long. Contains one ++ // or more TLV-encoded options, as described in ++ // section 4.2. ++ // ++ + if (*NextHeader == IP6_DESTINATION) { + CountD++; + } +@@ -398,7 +452,7 @@ Ip6IsExtsValid ( + + Offset++; + Option = ExtHdrs + Offset; +- OptionLen = (UINT8)((*Option + 1) * 8 - 2); ++ OptionLen = IP6_HDR_EXT_LEN (*Option) - sizeof (IP6_EXT_HDR); + Option++; + Offset++; + +@@ -430,7 +484,7 @@ Ip6IsExtsValid ( + // + // Ignore the routing header and proceed to process the next header. + // +- Offset = Offset + (RoutingHead->HeaderLen + 1) * 8; ++ Offset = Offset + IP6_HDR_EXT_LEN (RoutingHead->HeaderLen); + + if (UnFragmentLen != NULL) { + *UnFragmentLen = Offset; +@@ -441,7 +495,7 @@ Ip6IsExtsValid ( + // to the packet's source address, pointing to the unrecognized routing + // type. + // +- Pointer = Offset + 2 + sizeof (EFI_IP6_HEADER); ++ Pointer = Offset + sizeof (IP6_EXT_HDR) + sizeof (EFI_IP6_HEADER); + if ((IpSb != NULL) && (Packet != NULL) && + !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) + { +@@ -527,7 +581,7 @@ Ip6IsExtsValid ( + // + // RFC2402, Payload length is specified in 32-bit words, minus "2". + // +- OptionLen = (UINT8)((*Option + 2) * 4); ++ OptionLen = ((UINT16)(*Option + 2) * 4); + Offset = Offset + OptionLen; + break; + +diff --git a/NetworkPkg/Ip6Dxe/Ip6Option.h b/NetworkPkg/Ip6Dxe/Ip6Option.h +index bd8e223c8a..fb07c28f5a 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Option.h ++++ b/NetworkPkg/Ip6Dxe/Ip6Option.h +@@ -12,6 +12,77 @@ + + #define IP6_FRAGMENT_OFFSET_MASK (~0x3) + ++// ++// For more information see RFC 8200, Section 4.3, 4.4, and 4.6 ++// ++// This example format is from section 4.6 ++// This does not apply to fragment headers ++// ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++// | Next Header | Hdr Ext Len | | ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ++// | | ++// . . ++// . Header-Specific Data . ++// . . ++// | | ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++// ++// Next Header 8-bit selector. Identifies the type of ++// header immediately following the extension ++// header. Uses the same values as the IPv4 ++// Protocol field [IANA-PN]. ++// ++// Hdr Ext Len 8-bit unsigned integer. Length of the ++// Destination Options header in 8-octet units, ++// not including the first 8 octets. ++ ++// ++// These defines apply to the following: ++// 1. Hop by Hop ++// 2. Routing ++// 3. Destination ++// ++typedef struct _IP6_EXT_HDR { ++ /// ++ /// The Next Header field identifies the type of header immediately ++ /// ++ UINT8 NextHeader; ++ /// ++ /// The Hdr Ext Len field specifies the length of the Hop-by-Hop Options ++ /// ++ UINT8 HdrExtLen; ++ /// ++ /// Header-Specific Data ++ /// ++} IP6_EXT_HDR; ++ ++STATIC_ASSERT ( ++ sizeof (IP6_EXT_HDR) == 2, ++ "The combined size of Next Header and Len is two 8 bit fields" ++ ); ++ ++// ++// IPv6 extension headers contain an 8-bit length field which describes the size of ++// the header. However, the length field only includes the size of the extension ++// header options, not the size of the first 8 bytes of the header. Therefore, in ++// order to calculate the full size of the extension header, we add 1 (to account ++// for the first 8 bytes omitted by the length field reporting) and then multiply ++// by 8 (since the size is represented in 8-byte units). ++// ++// a is the length field of the extension header (UINT8) ++// The result may be up to 2046 octets (UINT16) ++// ++#define IP6_HDR_EXT_LEN(a) (((UINT16)((UINT8)(a)) + 1) * 8) ++ ++// This is the maxmimum length permissible by a extension header ++// Length is UINT8 of 8 octets not including the first 8 octets ++#define IP6_MAX_EXT_DATA_LENGTH (IP6_HDR_EXT_LEN (MAX_UINT8) - sizeof(IP6_EXT_HDR)) ++STATIC_ASSERT ( ++ IP6_MAX_EXT_DATA_LENGTH == 2046, ++ "Maximum data length is ((MAX_UINT8 + 1) * 8) - 2" ++ ); ++ + typedef struct _IP6_FRAGMENT_HEADER { + UINT8 NextHeader; + UINT8 Reserved; +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch new file mode 100644 index 0000000000..c6834a852e --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45232-CVE-2023-45233-0002.patch @@ -0,0 +1,417 @@ +From c9c87f08dd6ace36fa843424522c3558a8374cac Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:51 +0800 +Subject: [PATCH] NetworkPkg: Ip6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4537 +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4538 + +Unit tests to confirm that.. + +Infinite loop when parsing unknown options in the Destination Options +header + +and + +Infinite loop when parsing a PadN option in the Destination Options +header + +... have been patched + +This patch tests the following functions: +Ip6IsOptionValid + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45232, CVE-2023-45233 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/c9c87f08dd6ace36fa843424522c3558a8374cac] + +Signed-off-by: Soumya Sambu +--- + .../Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf | 10 +- + .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp | 278 ++++++++++++++++++ + .../Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h | 40 +++ + 3 files changed, 324 insertions(+), 4 deletions(-) + create mode 100644 NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h + +diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf +index 6e4de0745f..ba29dbabad 100644 +--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf ++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6DxeGoogleTest.inf +@@ -1,13 +1,13 @@ + ## @file +-# Unit test suite for the Ip6Dxe using Google Test ++# Unit test suite for the Ip6DxeGoogleTest using Google Test + # + # Copyright (c) Microsoft Corporation.
+ # SPDX-License-Identifier: BSD-2-Clause-Patent + ## + [Defines] + INF_VERSION = 0x00010017 +- BASE_NAME = Ip6DxeUnitTest +- FILE_GUID = 4F05D17D-D3E7-4AAE-820C-576D46D2D34A ++ BASE_NAME = Ip6DxeGoogleTest ++ FILE_GUID = AE39981C-B7FE-41A8-A9C2-F41910477CA3 + VERSION_STRING = 1.0 + MODULE_TYPE = HOST_APPLICATION + # +@@ -16,9 +16,11 @@ + # VALID_ARCHITECTURES = IA32 X64 AARCH64 + # + [Sources] ++ ../Ip6Option.c ++ Ip6OptionGoogleTest.h + Ip6DxeGoogleTest.cpp + Ip6OptionGoogleTest.cpp +- ../Ip6Option.c ++ Ip6OptionGoogleTest.h + + [Packages] + MdePkg/MdePkg.dec +diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp +index f2cd90e1a9..29f8a4a96e 100644 +--- a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp ++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.cpp +@@ -12,6 +12,7 @@ extern "C" { + #include + #include "../Ip6Impl.h" + #include "../Ip6Option.h" ++ #include "Ip6OptionGoogleTest.h" + } + + ///////////////////////////////////////////////////////////////////////// +@@ -127,3 +128,280 @@ TEST_F (Ip6OptionValidationTest, InvalidPrefixInfoOptionLengthShouldReturnFalse) + + 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 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 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 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)); ++} +diff --git a/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h +new file mode 100644 +index 0000000000..0509b6ae30 +--- /dev/null ++++ b/NetworkPkg/Ip6Dxe/GoogleTest/Ip6OptionGoogleTest.h +@@ -0,0 +1,40 @@ ++/** @file ++ Exposes the functions needed to test the Ip6Option module. ++ ++ Copyright (c) Microsoft Corporation ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#ifndef IP6_OPTION_HEADER_GOOGLE_TEST_H_ ++#define IP6_OPTION_HEADER_GOOGLE_TEST_H_ ++ ++#include ++#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 // __IP6_OPTION_HEADER_GOOGLE_TEST_H__ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index e46b3ddebe..fc87cdf441 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -37,6 +37,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45230-0002.patch \ file://CVE-2023-45231-0001.patch \ file://CVE-2023-45231-0002.patch \ + file://CVE-2023-45232-CVE-2023-45233-0001.patch \ + file://CVE-2023-45232-CVE-2023-45233-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46195 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE23DC3DA41 for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) by mx.groups.io with SMTP id smtpd.web11.4942.1720673773216847989 for ; Wed, 10 Jul 2024 21:56:13 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.178.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250812.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B3USAX032019 for ; Thu, 11 Jul 2024 04:56:12 GMT Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 406vw64gkb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Jul 2024 04:56:12 +0000 (GMT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:09 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 06/11] ovmf: Fix CVE-2023-45234 Date: Thu, 11 Jul 2024 04:55:36 +0000 Message-ID: <20240711045541.2155076-6-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-ORIG-GUID: 0zo8tQM5Gt2O2X44ty8rCNrEF-TfWXco X-Proofpoint-GUID: 0zo8tQM5Gt2O2X44ty8rCNrEF-TfWXco X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 lowpriorityscore=0 bulkscore=0 priorityscore=1501 phishscore=0 malwarescore=0 clxscore=1015 adultscore=0 impostorscore=0 mlxlogscore=999 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201756 From: Soumya Sambu EDK2's Network Package is susceptible to a buffer overflow vulnerability when processing DNS Servers option from a DHCPv6 Advertise message. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality, Integrity and/or Availability. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45234 Upstream-patches: https://github.com/tianocore/edk2/commit/1b53515d53d303166b2bbd31e2cc7f16fd0aecd7 https://github.com/tianocore/edk2/commit/458c582685fc0e8057d2511c5a0394078d988c17 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45234-0001.patch | 154 ++++++ .../ovmf/ovmf/CVE-2023-45234-0002.patch | 485 ++++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 641 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0001.patch new file mode 100644 index 0000000000..463b4b824d --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0001.patch @@ -0,0 +1,154 @@ +From 1b53515d53d303166b2bbd31e2cc7f16fd0aecd7 Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:52 +0800 +Subject: [PATCH] NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Patch + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 + +Bug Details: +PixieFail Bug #6 +CVE-2023-45234 +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 processing DNS Servers option in a DHCPv6 +Advertise message + +Change Overview: + +Introduces a function to cache the Dns Server and perform sanitizing +on the incoming DnsServerLen to ensure that the length is valid + +> + EFI_STATUS +> + PxeBcCacheDnsServerAddresses ( +> + IN PXEBC_PRIVATE_DATA *Private, +> + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 +> + ) + +Additional code cleanup + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45234 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1b53515d53d303166b2bbd31e2cc7f16fd0aecd7] + +Signed-off-by: Soumya Sambu +--- + 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..2b2d372889 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +@@ -3,6 +3,7 @@ + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
++ Copyright (c) Microsoft Corporation + + SPDX-License-Identifier: BSD-2-Clause-Patent + +@@ -1312,6 +1313,65 @@ PxeBcSelectDhcp6Offer ( + } + } + ++/** ++ Cache the DHCPv6 DNS Server addresses ++ ++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA. ++ @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. ++ ++ @retval EFI_SUCCESS Cache the DHCPv6 DNS Server address successfully. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. ++ @retval EFI_DEVICE_ERROR The DNS Server Address Length provided by a untrusted ++ option is not a multiple of 16 bytes (sizeof (EFI_IPv6_ADDRESS)). ++**/ ++EFI_STATUS ++PxeBcCacheDnsServerAddresses ( ++ IN PXEBC_PRIVATE_DATA *Private, ++ IN PXEBC_DHCP6_PACKET_CACHE *Cache6 ++ ) ++{ ++ UINT16 DnsServerLen; ++ ++ DnsServerLen = NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen); ++ // ++ // Make sure that the number is nonzero ++ // ++ if (DnsServerLen == 0) { ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // Make sure the DnsServerlen is a multiple of EFI_IPv6_ADDRESS (16) ++ // ++ if (DnsServerLen % sizeof (EFI_IPv6_ADDRESS) != 0) { ++ return EFI_DEVICE_ERROR; ++ } ++ ++ // ++ // This code is currently written to only support a single DNS Server instead ++ // of multiple such as is spec defined (RFC3646, Section 3). The proper behavior ++ // would be to allocate the full space requested, CopyMem all of the data, ++ // and then add a DnsServerCount field to Private and update additional code ++ // that depends on this. ++ // ++ // To support multiple DNS servers the `AllocationSize` would need to be changed to DnsServerLen ++ // ++ // This is tracked in https://bugzilla.tianocore.org/show_bug.cgi?id=1886 ++ // ++ Private->DnsServer = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS)); ++ if (Private->DnsServer == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ // ++ // Intentionally only copy over the first server address. ++ // To support multiple DNS servers, the `Length` would need to be changed to DnsServerLen ++ // ++ CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); ++ ++ return EFI_SUCCESS; ++} ++ + /** + Handle the DHCPv6 offer packet. + +@@ -1335,6 +1395,7 @@ PxeBcHandleDhcp6Offer ( + UINT32 SelectIndex; + UINT32 Index; + ++ ASSERT (Private != NULL); + ASSERT (Private->SelectIndex > 0); + SelectIndex = (UINT32)(Private->SelectIndex - 1); + ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); +@@ -1342,15 +1403,13 @@ PxeBcHandleDhcp6Offer ( + Status = EFI_SUCCESS; + + // +- // First try to cache DNS server address if DHCP6 offer provides. ++ // First try to cache DNS server addresses if DHCP6 offer provides. + // + if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { +- Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); +- if (Private->DnsServer == NULL) { +- return EFI_OUT_OF_RESOURCES; ++ Status = PxeBcCacheDnsServerAddresses (Private, Cache6); ++ if (EFI_ERROR (Status)) { ++ return Status; + } +- +- CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); + } + + if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0002.patch new file mode 100644 index 0000000000..4bc7ac16d6 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45234-0002.patch @@ -0,0 +1,485 @@ +From 458c582685fc0e8057d2511c5a0394078d988c17 Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:53 +0800 +Subject: [PATCH] NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45234 Unit + Tests + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4539 + +Unit tests to that the bug.. + +Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise +message + +..has been patched + +This contains tests for the following functions: +PxeBcHandleDhcp6Offer +PxeBcCacheDnsServerAddresses + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45234 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/458c582685fc0e8057d2511c5a0394078d988c17] + +Signed-off-by: Soumya Sambu +--- + .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 300 ++++++++++++++++++ + .../GoogleTest/PxeBcDhcp6GoogleTest.h | 50 +++ + .../GoogleTest/UefiPxeBcDxeGoogleTest.cpp | 19 ++ + .../GoogleTest/UefiPxeBcDxeGoogleTest.inf | 48 +++ + 4 files changed, 417 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/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +new file mode 100644 +index 0000000000..8260eeee50 +--- /dev/null ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +@@ -0,0 +1,300 @@ ++/** @file ++ Host based unit test for PxeBcDhcp6.c. ++ ++ Copyright (c) Microsoft Corporation ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++#include ++ ++extern "C" { ++ #include ++ #include ++ #include ++ #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 ++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 ++ // ++ // Disabling: ++ // ASSERT_EQ (CompareMem(Private.DnsServer, &addresses, sizeof(addresses)), 0); ++ ++ if (Private.DnsServer) { ++ FreePool (Private.DnsServer); ++ } ++} +diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h +new file mode 100644 +index 0000000000..b17c314791 +--- /dev/null ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h +@@ -0,0 +1,50 @@ ++/** @file ++ This file exposes the internal interfaces which may be unit tested ++ for the PxeBcDhcp6Dxe driver. ++ ++ Copyright (c) Microsoft Corporation.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#ifndef PXE_BC_DHCP6_GOOGLE_TEST_H_ ++#define PXE_BC_DHCP6_GOOGLE_TEST_H_ ++ ++// ++// Minimal includes needed to compile ++// ++#include ++#include "../PxeBcImpl.h" ++ ++/** ++ Handle the DHCPv6 offer packet. ++ ++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA. ++ ++ @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. ++ @retval EFI_NO_RESPONSE No response to the following request packet. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. ++ @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet. ++ ++**/ ++EFI_STATUS ++PxeBcHandleDhcp6Offer ( ++ IN PXEBC_PRIVATE_DATA *Private ++ ); ++ ++/** ++ Cache the DHCPv6 Server address ++ ++ @param[in] Private The pointer to PXEBC_PRIVATE_DATA. ++ @param[in] Cache6 The pointer to PXEBC_DHCP6_PACKET_CACHE. ++ ++ @retval EFI_SUCCESS Cache the DHCPv6 Server address successfully. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. ++ @retval EFI_DEVICE_ERROR Failed to cache the DHCPv6 Server address. ++**/ ++EFI_STATUS ++PxeBcCacheDnsServerAddresses ( ++ IN PXEBC_PRIVATE_DATA *Private, ++ IN PXEBC_DHCP6_PACKET_CACHE *Cache6 ++ ); ++ ++#endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ +diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp +new file mode 100644 +index 0000000000..cc4fdf525b +--- /dev/null ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.cpp +@@ -0,0 +1,19 @@ ++/** @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 ++ ++//////////////////////////////////////////////////////////////////////////////// ++// 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 +new file mode 100644 +index 0000000000..301dcdf611 +--- /dev/null ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/UefiPxeBcDxeGoogleTest.inf +@@ -0,0 +1,48 @@ ++## @file ++# Unit test suite for the UefiPxeBcDxe using Google Test ++# ++# Copyright (c) Microsoft Corporation.
++# 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 ++ PxeBcDhcp6GoogleTest.h ++ ../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 +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index fc87cdf441..ac6a0a40e7 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -39,6 +39,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45231-0002.patch \ file://CVE-2023-45232-CVE-2023-45233-0001.patch \ file://CVE-2023-45232-CVE-2023-45233-0002.patch \ + file://CVE-2023-45234-0001.patch \ + file://CVE-2023-45234-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46194 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D4461C3DA4A for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web11.4943.1720673774361932422 for ; Wed, 10 Jul 2024 21:56:14 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250809.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4TWx6031011 for ; Wed, 10 Jul 2024 21:56:14 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4075eg48nw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:13 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:11 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 07/11] ovmf: Fix CVE-2023-45235 Date: Thu, 11 Jul 2024 04:55:37 +0000 Message-ID: <20240711045541.2155076-7-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: VMBnCmTwnsE6HYSIPPlTvNF9u-STte2q X-Proofpoint-ORIG-GUID: VMBnCmTwnsE6HYSIPPlTvNF9u-STte2q X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 malwarescore=0 clxscore=1015 adultscore=0 bulkscore=0 mlxscore=0 spamscore=0 mlxlogscore=999 suspectscore=0 phishscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201757 From: Soumya Sambu EDK2's Network Package is susceptible to a buffer overflow vulnerability when handling Server ID option from a DHCPv6 proxy Advertise message. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality, Integrity and/or Availability. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45235 Upstream-patches: https://github.com/tianocore/edk2/commit/fac297724e6cc343430cd0104e55cd7a96d1151e https://github.com/tianocore/edk2/commit/ff2986358f75d8f58ef08a66fe673539c9c48f41 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45235-0001.patch | 243 +++++++++++ .../ovmf/ovmf/CVE-2023-45235-0002.patch | 379 ++++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 624 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0001.patch new file mode 100644 index 0000000000..264172f623 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0001.patch @@ -0,0 +1,243 @@ +From fac297724e6cc343430cd0104e55cd7a96d1151e Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:55 +0800 +Subject: [PATCH] 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 +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45235 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/fac297724e6cc343430cd0104e55cd7a96d1151e] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 77 ++++++++++++++++++++++------ + NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 17 ++++++ + 2 files changed, 78 insertions(+), 16 deletions(-) + +diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +index 2b2d372889..7fd1281c11 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +@@ -887,6 +887,7 @@ PxeBcRequestBootService ( + EFI_STATUS Status; + EFI_DHCP6_PACKET *IndexOffer; + UINT8 *Option; ++ UINTN DiscoverLenNeeded; + + PxeBc = &Private->PxeBc; + Request = Private->Dhcp6Request; +@@ -899,7 +900,8 @@ PxeBcRequestBootService ( + return EFI_DEVICE_ERROR; + } + +- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); ++ DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); ++ Discover = AllocateZeroPool (DiscoverLenNeeded); + if (Discover == NULL) { + return EFI_OUT_OF_RESOURCES; + } +@@ -924,16 +926,34 @@ PxeBcRequestBootService ( + DHCP6_OPT_SERVER_ID + ); + if (Option == NULL) { +- return EFI_NOT_FOUND; ++ Status = EFI_NOT_FOUND; ++ goto ON_ERROR; + } + + // + // Add Server ID Option. + // + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen); +- CopyMem (DiscoverOpt, Option, OpLen + 4); +- DiscoverOpt += (OpLen + 4); +- DiscoverLen += (OpLen + 4); ++ ++ // ++ // 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; ++ } ++ ++ // ++ // 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; ++ } ++ ++ CopyMem (DiscoverOpt, Option, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + } + + while (RequestLen < Request->Length) { +@@ -944,16 +964,24 @@ PxeBcRequestBootService ( + (OpCode != DHCP6_OPT_SERVER_ID) + ) + { ++ // ++ // 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; ++ } ++ + // + // Copy all the options except IA option and Server ID + // +- CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); +- DiscoverOpt += (OpLen + 4); +- DiscoverLen += (OpLen + 4); ++ CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + } + +- RequestOpt += (OpLen + 4); +- RequestLen += (OpLen + 4); ++ RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + } + + // +@@ -2154,6 +2182,7 @@ PxeBcDhcp6Discover ( + UINT16 OpLen; + UINT32 Xid; + EFI_STATUS Status; ++ UINTN DiscoverLenNeeded; + + PxeBc = &Private->PxeBc; + Mode = PxeBc->Mode; +@@ -2169,7 +2198,8 @@ PxeBcDhcp6Discover ( + return EFI_DEVICE_ERROR; + } + +- Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); ++ DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); ++ Discover = AllocateZeroPool (DiscoverLenNeeded); + if (Discover == NULL) { + return EFI_OUT_OF_RESOURCES; + } +@@ -2185,22 +2215,37 @@ PxeBcDhcp6Discover ( + DiscoverLen = sizeof (EFI_DHCP6_HEADER); + RequestLen = DiscoverLen; + ++ // ++ // The request packet is generated by the UEFI network stack. In the DHCP4 DORA and DHCP6 SARR sequence, ++ // the first (discover in DHCP4 and solicit in DHCP6) and third (request in both DHCP4 and DHCP6) are ++ // generated by the DHCP client (the UEFI network stack in this case). By the time this function executes, ++ // the DHCP sequence already has been executed once (see UEFI Specification Figures 24.2 and 24.3), with ++ // Private->Dhcp6Request being a cached copy of the DHCP6 request packet that UEFI network stack previously ++ // generated and sent. ++ // ++ // Therefore while this code looks like it could overflow, in practice it's not possible. ++ // + while (RequestLen < Request->Length) { + OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode); + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen); + if ((OpCode != EFI_DHCP6_IA_TYPE_NA) && + (OpCode != EFI_DHCP6_IA_TYPE_TA)) + { ++ if (DiscoverLen + OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN > DiscoverLenNeeded) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto ON_ERROR; ++ } ++ + // + // Copy all the options except IA option. + // +- CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); +- DiscoverOpt += (OpLen + 4); +- DiscoverLen += (OpLen + 4); ++ CopyMem (DiscoverOpt, RequestOpt, OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ DiscoverLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + } + +- RequestOpt += (OpLen + 4); +- RequestLen += (OpLen + 4); ++ RequestOpt += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); ++ RequestLen += (OpLen + PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN); + } + + Status = PxeBc->UdpWrite ( +diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +index c86f6d391b..6357d27fae 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +@@ -34,6 +34,23 @@ + #define PXEBC_ADDR_START_DELIMITER '[' + #define PXEBC_ADDR_END_DELIMITER ']' + ++// ++// A DUID consists of a 2-octet type code represented in network byte ++// order, followed by a variable number of octets that make up the ++// actual identifier. The length of the DUID (not including the type ++// code) is at least 1 octet and at most 128 octets. ++// ++#define PXEBC_MIN_SIZE_OF_DUID (sizeof(UINT16) + 1) ++#define PXEBC_MAX_SIZE_OF_DUID (sizeof(UINT16) + 128) ++ ++// ++// This define represents the combineds code and length field from ++// https://datatracker.ietf.org/doc/html/rfc3315#section-22.1 ++// ++#define PXEBC_COMBINED_SIZE_OF_OPT_CODE_AND_LEN \ ++ (sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpCode) + \ ++ sizeof (((EFI_DHCP6_PACKET_OPTION *)0)->OpLen)) ++ + #define GET_NEXT_DHCP6_OPTION(Opt) \ + (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \ + sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1) +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0002.patch new file mode 100644 index 0000000000..0e814a0212 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45235-0002.patch @@ -0,0 +1,379 @@ +From ff2986358f75d8f58ef08a66fe673539c9c48f41 Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Fri, 26 Jan 2024 05:54:56 +0800 +Subject: [PATCH] NetworkPkg: UefiPxeBcDxe: SECURITY PATCH CVE-2023-45235 Unit + Tests + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4540 + +Unit tests to confirm that the bug.. + +Buffer overflow when handling Server ID option from a DHCPv6 proxy +Advertise message + +..has been patched. + +This patch contains unit tests for the following functions: +PxeBcRequestBootService +PxeBcDhcp6Discover + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45235 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/ff2986358f75d8f58ef08a66fe673539c9c48f41] + +Signed-off-by: Soumya Sambu +--- + .../GoogleTest/PxeBcDhcp6GoogleTest.cpp | 278 +++++++++++++++++- + .../GoogleTest/PxeBcDhcp6GoogleTest.h | 18 ++ + 2 files changed, 294 insertions(+), 2 deletions(-) + +diff --git a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +index 8260eeee50..bd423ebadf 100644 +--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.cpp +@@ -4,7 +4,9 @@ + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + **/ +-#include ++#include ++#include ++#include + + extern "C" { + #include +@@ -19,7 +21,8 @@ extern "C" { + // Definitions + /////////////////////////////////////////////////////////////////////////////// + +-#define PACKET_SIZE (1500) ++#define PACKET_SIZE (1500) ++#define REQUEST_OPTION_LENGTH (120) + + typedef struct { + UINT16 OptionCode; // The option code for DHCP6_OPT_SERVER_ID (e.g., 0x03) +@@ -76,6 +79,26 @@ MockConfigure ( + } + + // 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 ( +@@ -159,6 +182,10 @@ TEST_F (PxeBcHandleDhcp6OfferTest, BasicUsageTest) { + ASSERT_EQ (PxeBcHandleDhcp6Offer (&(PxeBcHandleDhcp6OfferTest::Private)), EFI_DEVICE_ERROR); + } + ++/////////////////////////////////////////////////////////////////////////////// ++// PxeBcCacheDnsServerAddresses Tests ++/////////////////////////////////////////////////////////////////////////////// ++ + class PxeBcCacheDnsServerAddressesTest : public ::testing::Test { + public: + PXEBC_PRIVATE_DATA Private = { 0 }; +@@ -298,3 +325,250 @@ TEST_F (PxeBcCacheDnsServerAddressesTest, MultipleDnsEntries) { + 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; ++ ++ // This is going to be stopped by the duid overflow check ++ ASSERT_EQ (PxeBcRequestBootService (&(PxeBcRequestBootServiceTest::Private), Index), EFI_INVALID_PARAMETER); ++} ++ ++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 b17c314791..0d825e4425 100644 +--- a/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h ++++ b/NetworkPkg/UefiPxeBcDxe/GoogleTest/PxeBcDhcp6GoogleTest.h +@@ -47,4 +47,22 @@ PxeBcCacheDnsServerAddresses ( + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ); + ++/** ++ Build and send out the request packet for the bootfile, and parse the reply. ++ ++ @param[in] Private The pointer to PxeBc private data. ++ @param[in] Index PxeBc option boot item type. ++ ++ @retval EFI_SUCCESS Successfully discovered the boot file. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. ++ @retval EFI_NOT_FOUND Can't get the PXE reply packet. ++ @retval Others Failed to discover the boot file. ++ ++**/ ++EFI_STATUS ++PxeBcRequestBootService ( ++ IN PXEBC_PRIVATE_DATA *Private, ++ IN UINT32 Index ++ ); ++ + #endif // PXE_BC_DHCP6_GOOGLE_TEST_H_ +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index ac6a0a40e7..ceebb53438 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -41,6 +41,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45232-CVE-2023-45233-0002.patch \ file://CVE-2023-45234-0001.patch \ file://CVE-2023-45234-0002.patch \ + file://CVE-2023-45235-0001.patch \ + file://CVE-2023-45235-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46197 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED7C7C3DA4E for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) by mx.groups.io with SMTP id smtpd.web10.4975.1720673777712201967 for ; Wed, 10 Jul 2024 21:56:17 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.178.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250811.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4OH8l017507 for ; Thu, 11 Jul 2024 04:56:17 GMT Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 406u4x4jmj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Jul 2024 04:56:16 +0000 (GMT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:13 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 08/11] ovmf: Fix CVE-2023-45229 Date: Thu, 11 Jul 2024 04:55:38 +0000 Message-ID: <20240711045541.2155076-8-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-ORIG-GUID: nocosJbKPLWcitirwjbQL4vycbaY776k X-Proofpoint-GUID: nocosJbKPLWcitirwjbQL4vycbaY776k X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 adultscore=0 malwarescore=0 bulkscore=0 clxscore=1015 spamscore=0 mlxlogscore=999 priorityscore=1501 lowpriorityscore=0 suspectscore=0 phishscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201758 From: Soumya Sambu EDK2's Network Package is susceptible to an out-of-bounds read vulnerability when processing the IA_NA or IA_TA option in a DHCPv6 Advertise message. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45229 Upstream-patches: https://github.com/tianocore/edk2/commit/1dbb10cc52dc8ef49bb700daa1cefc76b26d52e0 https://github.com/tianocore/edk2/commit/07362769ab7a7d74dbea1c7a7a3662c7b5d1f097 https://github.com/tianocore/edk2/commit/1c440a5eceedc64e892877eeac0f1a4938f5abbb https://github.com/tianocore/edk2/commit/1d0b95f6457d225c5108302a9da74b4ed7aa5a38 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45229-0001.patch | 604 ++++++++++++++++++ .../ovmf/ovmf/CVE-2023-45229-0002.patch | 539 ++++++++++++++++ .../ovmf/ovmf/CVE-2023-45229-0003.patch | 244 +++++++ .../ovmf/ovmf/CVE-2023-45229-0004.patch | 157 +++++ meta/recipes-core/ovmf/ovmf_git.bb | 4 + 5 files changed, 1548 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0002.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0003.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0004.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0001.patch new file mode 100644 index 0000000000..9d8549b27d --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0001.patch @@ -0,0 +1,604 @@ +From 1dbb10cc52dc8ef49bb700daa1cefc76b26d52e0 Mon Sep 17 00:00:00 2001 +From: "Doug Flick via 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 +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45229 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1dbb10cc52dc8ef49bb700daa1cefc76b26d52e0] + +Signed-off-by: Soumya Sambu +--- + 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 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0002.patch new file mode 100644 index 0000000000..7ce5c98789 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0002.patch @@ -0,0 +1,539 @@ +From 07362769ab7a7d74dbea1c7a7a3662c7b5d1f097 Mon Sep 17 00:00:00 2001 +From: "Doug Flick via groups.io" +Date: Fri, 26 Jan 2024 05:54:47 +0800 +Subject: [PATCH] NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit + Tests + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 + +These tests confirm that the report bug... + +"Out-of-bounds read when processing IA_NA/IA_TA options in a +DHCPv6 Advertise message" + +..has been patched. + +The following functions are tested to confirm an out of bounds read is +patched and that the correct statuses are returned: + +Dhcp6SeekInnerOptionSafe +Dhcp6SeekStsOption + +TCBZ4534 +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 + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45229 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/07362769ab7a7d74dbea1c7a7a3662c7b5d1f097] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 2 +- + .../GoogleTest/Dhcp6DxeGoogleTest.inf | 1 + + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp | 365 +++++++++++++++++- + .../Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h | 58 +++ + 4 files changed, 423 insertions(+), 3 deletions(-) + create mode 100644 NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h + +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +index 89d16484a5..3b8feb4a20 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +@@ -816,7 +816,7 @@ Dhcp6SeekStsOption ( + // IA option to the end of the DHCP6 option area, thus subtract the space + // up until this option + // +- OptionLen = OptionLen - (*Option - Packet->Dhcp6.Option); ++ OptionLen = OptionLen - (UINT32)(*Option - Packet->Dhcp6.Option); + + // + // Seek the inner option +diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf +index 8e9119a371..12532ed30c 100644 +--- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf ++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6DxeGoogleTest.inf +@@ -18,6 +18,7 @@ + [Sources] + Dhcp6DxeGoogleTest.cpp + Dhcp6IoGoogleTest.cpp ++ Dhcp6IoGoogleTest.h + ../Dhcp6Io.c + ../Dhcp6Utility.c + +diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +index 7ee40e4af4..7db253a7b8 100644 +--- a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp ++++ b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.cpp +@@ -13,6 +13,7 @@ extern "C" { + #include + #include "../Dhcp6Impl.h" + #include "../Dhcp6Utility.h" ++ #include "Dhcp6IoGoogleTest.h" + } + + //////////////////////////////////////////////////////////////////////// +@@ -21,7 +22,35 @@ extern "C" { + + #define DHCP6_PACKET_MAX_LEN 1500 + ++// This definition is used by this test but is also required to compile ++// by Dhcp6Io.c ++#define DHCPV6_OPTION_IA_NA 3 ++#define DHCPV6_OPTION_IA_TA 4 ++ ++#define SEARCH_PATTERN 0xDEADC0DE ++#define SEARCH_PATTERN_LEN sizeof(SEARCH_PATTERN) ++ + //////////////////////////////////////////////////////////////////////// ++// Test structures for IA_NA and IA_TA options ++//////////////////////////////////////////////////////////////////////// ++typedef struct { ++ UINT16 Code; ++ UINT16 Len; ++ UINT32 IAID; ++} DHCPv6_OPTION; ++ ++typedef struct { ++ DHCPv6_OPTION Header; ++ UINT32 T1; ++ UINT32 T2; ++ UINT8 InnerOptions[0]; ++} DHCPv6_OPTION_IA_NA; ++ ++typedef struct { ++ DHCPv6_OPTION Header; ++ UINT8 InnerOptions[0]; ++} DHCPv6_OPTION_IA_TA; ++ + //////////////////////////////////////////////////////////////////////// + // Symbol Definitions + // These functions are not directly under test - but required to compile +@@ -210,7 +239,7 @@ TEST_F (Dhcp6AppendETOptionTest, InvalidDataExpectBufferTooSmall) { + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, +- &Instance, // Instance is not used in this function ++ &Instance, // Instance is not used in this function + &ElapsedTime + ); + +@@ -240,7 +269,7 @@ TEST_F (Dhcp6AppendETOptionTest, ValidDataExpectSuccess) { + Status = Dhcp6AppendETOption ( + Dhcp6AppendETOptionTest::Packet, + &Cursor, +- &Instance, // Instance is not used in this function ++ &Instance, // Instance is not used in this function + &ElapsedTime + ); + +@@ -476,3 +505,335 @@ TEST_F (Dhcp6AppendIaOptionTest, IaTaValidDataExpectSuccess) { + // verify that the status is EFI_SUCCESS + ASSERT_EQ (Status, EFI_SUCCESS); + } ++ ++//////////////////////////////////////////////////////////////////////// ++// Dhcp6SeekInnerOptionSafe Tests ++//////////////////////////////////////////////////////////////////////// ++ ++// Define a fixture for your tests if needed ++class Dhcp6SeekInnerOptionSafeTest : 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: ++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IANA option is found. ++TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAValidOptionExpectSuccess) { ++ EFI_STATUS Result; ++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; ++ UINT32 OptionLength = sizeof (Option); ++ DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ ++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT8 *InnerOptionPtr = NULL; ++ UINT16 InnerOptionLength = 0; ++ ++ OptionPtr->Header.Code = Dhcp6OptIana; ++ OptionPtr->Header.Len = HTONS (4 + 12); // Valid length has to be more than 12 ++ OptionPtr->Header.IAID = 0x12345678; ++ OptionPtr->T1 = 0x11111111; ++ OptionPtr->T2 = 0x22222222; ++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); ++ ++ Result = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIana, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Result, EFI_SUCCESS); ++ ASSERT_EQ (InnerOptionLength, 4); ++ ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); ++} ++ ++// Test Description: ++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_DEIVCE_ERROR when the IANA option size is invalid. ++TEST_F (Dhcp6SeekInnerOptionSafeTest, IANAInvalidSizeExpectFail) { ++ // Lets add an inner option of bytes we expect to find ++ EFI_STATUS Status; ++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_NA) + SEARCH_PATTERN_LEN] = { 0 }; ++ UINT32 OptionLength = sizeof (Option); ++ DHCPv6_OPTION_IA_NA *OptionPtr = (DHCPv6_OPTION_IA_NA *)Option; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ ++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT8 *InnerOptionPtr = NULL; ++ UINT16 InnerOptionLength = 0; ++ ++ OptionPtr->Header.Code = Dhcp6OptIana; ++ OptionPtr->Header.Len = HTONS (4); // Set the length to lower than expected (12) ++ OptionPtr->Header.IAID = 0x12345678; ++ OptionPtr->T1 = 0x11111111; ++ OptionPtr->T2 = 0x22222222; ++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); ++ ++ // Set the InnerOptionLength to be less than the size of the option ++ Status = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIana, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Status, EFI_DEVICE_ERROR); ++ ++ // Now set the OptionLength to be less than the size of the option ++ OptionLength = sizeof (DHCPv6_OPTION_IA_NA) - 1; ++ Status = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIana, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Status, EFI_DEVICE_ERROR); ++} ++ ++// Test Description: ++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option is found ++TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAValidOptionExpectSuccess) { ++ // Lets add an inner option of bytes we expect to find ++ EFI_STATUS Status; ++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; ++ UINT32 OptionLength = sizeof (Option); ++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ ++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT8 *InnerOptionPtr = NULL; ++ UINT16 InnerOptionLength = 0; ++ ++ OptionPtr->Header.Code = Dhcp6OptIata; ++ OptionPtr->Header.Len = HTONS (4 + 4); // Valid length has to be more than 4 ++ OptionPtr->Header.IAID = 0x12345678; ++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); ++ ++ Status = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIata, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ASSERT_EQ (InnerOptionLength, 4); ++ ASSERT_EQ (CompareMem (InnerOptionPtr, &SearchPattern, SearchPatternLength), 0); ++} ++ ++// Test Description: ++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. ++TEST_F (Dhcp6SeekInnerOptionSafeTest, IATAInvalidSizeExpectFail) { ++ // Lets add an inner option of bytes we expect to find ++ EFI_STATUS Status; ++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; ++ UINT32 OptionLength = sizeof (Option); ++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ ++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT8 *InnerOptionPtr = NULL; ++ UINT16 InnerOptionLength = 0; ++ ++ OptionPtr->Header.Code = Dhcp6OptIata; ++ OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) ++ OptionPtr->Header.IAID = 0x12345678; ++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); ++ ++ Status = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIata, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Status, EFI_DEVICE_ERROR); ++ ++ // Now lets try modifying the OptionLength to be less than the size of the option ++ OptionLength = sizeof (DHCPv6_OPTION_IA_TA) - 1; ++ Status = Dhcp6SeekInnerOptionSafe ( ++ Dhcp6OptIata, ++ Option, ++ OptionLength, ++ &InnerOptionPtr, ++ &InnerOptionLength ++ ); ++ ASSERT_EQ (Status, EFI_DEVICE_ERROR); ++} ++ ++// Test Description: ++// This test verifies that any other Option Type fails ++TEST_F (Dhcp6SeekInnerOptionSafeTest, InvalidOption) { ++ // Lets add an inner option of bytes we expect to find ++ EFI_STATUS Result; ++ UINT8 Option[sizeof (DHCPv6_OPTION_IA_TA) + SEARCH_PATTERN_LEN] = { 0 }; ++ UINT32 OptionLength = sizeof (Option); ++ DHCPv6_OPTION_IA_TA *OptionPtr = (DHCPv6_OPTION_IA_TA *)Option; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ ++ UINTN SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT8 *InnerOptionPtr = NULL; ++ UINT16 InnerOptionLength = 0; ++ ++ OptionPtr->Header.Code = 0xC0DE; ++ OptionPtr->Header.Len = HTONS (2); // Set the length to lower than expected (4) ++ OptionPtr->Header.IAID = 0x12345678; ++ CopyMem (OptionPtr->InnerOptions, &SearchPattern, SearchPatternLength); ++ ++ Result = Dhcp6SeekInnerOptionSafe (0xC0DE, Option, OptionLength, &InnerOptionPtr, &InnerOptionLength); ++ ASSERT_EQ (Result, EFI_DEVICE_ERROR); ++} ++ ++//////////////////////////////////////////////////////////////////////// ++// Dhcp6SeekStsOption Tests ++//////////////////////////////////////////////////////////////////////// ++ ++#define PACKET_SIZE (1500) ++ ++class Dhcp6SeekStsOptionTest : public ::testing::Test { ++public: ++ DHCP6_INSTANCE Instance = { 0 }; ++ EFI_DHCP6_PACKET *Packet = NULL; ++ EFI_DHCP6_CONFIG_DATA Config = { 0 }; ++ ++protected: ++ // Add any setup code if needed ++ virtual void ++ SetUp ( ++ ) ++ { ++ // Allocate a packet ++ Packet = (EFI_DHCP6_PACKET *)AllocateZeroPool (PACKET_SIZE); ++ ASSERT_NE (Packet, nullptr); ++ ++ // Initialize the packet ++ Packet->Size = PACKET_SIZE; ++ ++ Instance.Config = &Config; ++ } ++ ++ // Add any cleanup code if needed ++ virtual void ++ TearDown ( ++ ) ++ { ++ // Clean up any resources or variables ++ FreePool (Packet); ++ } ++}; ++ ++// Test Description: ++// This test verifies that Dhcp6SeekStsOption returns EFI_DEVICE_ERROR when the option is invalid ++// This verifies that the calling function is working as expected ++TEST_F (Dhcp6SeekStsOptionTest, SeekIATAOptionExpectFail) { ++ EFI_STATUS Status; ++ UINT8 *Option = NULL; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; ++ UINT16 *Len = NULL; ++ EFI_DHCP6_IA Ia = { 0 }; ++ ++ Ia.Descriptor.Type = DHCPV6_OPTION_IA_TA; ++ Ia.IaAddressCount = 1; ++ Ia.IaAddress[0].PreferredLifetime = 0xDEADBEEF; ++ Ia.IaAddress[0].ValidLifetime = 0xDEADAAAA; ++ Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; ++ ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ ++ Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; ++ ++ // Let's append the option to the packet ++ Status = Dhcp6AppendOption ( ++ Dhcp6SeekStsOptionTest::Packet, ++ &Option, ++ Dhcp6OptStatusCode, ++ SearchPatternLength, ++ (UINT8 *)&SearchPattern ++ ); ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ // Inner option length - this will be overwritten later ++ Len = (UINT16 *)(Option + 2); ++ ++ // Fill in the inner IA option ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6SeekStsOptionTest::Packet, ++ &Option, ++ &Ia, ++ 0x12345678, ++ 0x11111111, ++ 0x22222222 ++ ); ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ // overwrite the len of inner Ia option ++ *Len = HTONS (3); ++ ++ Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_TA; ++ ++ Option = NULL; ++ Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); ++ ++ ASSERT_EQ (Status, EFI_DEVICE_ERROR); ++} ++ ++// Test Description: ++// This test verifies that Dhcp6SeekInnerOptionSafe returns EFI_SUCCESS when the IATA option size is invalid. ++TEST_F (Dhcp6SeekStsOptionTest, SeekIANAOptionExpectSuccess) { ++ EFI_STATUS Status = EFI_NOT_FOUND; ++ UINT8 *Option = NULL; ++ UINT32 SearchPattern = SEARCH_PATTERN; ++ UINT16 SearchPatternLength = SEARCH_PATTERN_LEN; ++ EFI_DHCP6_IA Ia = { 0 }; ++ ++ Ia.Descriptor.Type = DHCPV6_OPTION_IA_NA; ++ Ia.IaAddressCount = 1; ++ Ia.IaAddress[0].PreferredLifetime = 0x11111111; ++ Ia.IaAddress[0].ValidLifetime = 0x22222222; ++ Ia.IaAddress[0].IpAddress = mAllDhcpRelayAndServersAddress; ++ Packet->Length = sizeof (EFI_DHCP6_HEADER); ++ ++ Option = Dhcp6SeekStsOptionTest::Packet->Dhcp6.Option; ++ ++ Status = Dhcp6AppendOption ( ++ Dhcp6SeekStsOptionTest::Packet, ++ &Option, ++ Dhcp6OptStatusCode, ++ SearchPatternLength, ++ (UINT8 *)&SearchPattern ++ ); ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ Status = Dhcp6AppendIaOption ( ++ Dhcp6SeekStsOptionTest::Packet, ++ &Option, ++ &Ia, ++ 0x12345678, ++ 0x11111111, ++ 0x22222222 ++ ); ++ ASSERT_EQ (Status, EFI_SUCCESS); ++ ++ Dhcp6SeekStsOptionTest::Instance.Config->IaDescriptor.Type = DHCPV6_OPTION_IA_NA; ++ ++ Option = NULL; ++ Status = Dhcp6SeekStsOption (&(Dhcp6SeekStsOptionTest::Instance), Dhcp6SeekStsOptionTest::Packet, &Option); ++ ++ ASSERT_EQ (Status, EFI_SUCCESS); ++} +diff --git a/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h b/NetworkPkg/Dhcp6Dxe/GoogleTest/Dhcp6IoGoogleTest.h +new file mode 100644 +index 0000000000..aed3b89082 +--- /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 ++ ++/** ++ 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 +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0003.patch new file mode 100644 index 0000000000..bf4e8eda1f --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0003.patch @@ -0,0 +1,244 @@ +From 1c440a5eceedc64e892877eeac0f1a4938f5abbb Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Tue, 13 Feb 2024 10:46:00 -0800 +Subject: [PATCH] NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Related + Patch + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4673 +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4534 + +This was not part of the Quarkslab bugs however the same pattern +as CVE-2023-45229 exists in Dhcp6UpdateIaInfo. + +This patch replaces the code in question with the safe function +created to patch CVE-2023-45229 + +> +> if (EFI_ERROR ( +> Dhcp6SeekInnerOptionSafe ( +> Instance->Config->IaDescriptor.Type, +> Option, +> OptionLen, +> &IaInnerOpt, +> &IaInnerLen +> ) +> )) +> { +> return EFI_DEVICE_ERROR; +> } +> + +Additionally corrects incorrect usage of macro to read the status + +> - StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)DHCP6_OFFSET_OF_OPT_LEN + (Option))); +> + StsCode = NTOHS (ReadUnaligned16 ((UINT16 *) +DHCP6_OFFSET_OF_STATUS_CODE (Option)); + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar +Reviewed-by: Leif Lindholm + +CVE: CVE-2023-45229 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1c440a5eceedc64e892877eeac0f1a4938f5abbb] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Dhcp6Dxe/Dhcp6Io.c | 70 ++++++++++++++++++++++++++--------- + NetworkPkg/Dhcp6Dxe/Dhcp6Io.h | 22 +++++++++++ + 2 files changed, 75 insertions(+), 17 deletions(-) + +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +index 3b8feb4a20..a9bffae353 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +@@ -528,13 +528,23 @@ Dhcp6UpdateIaInfo ( + { + EFI_STATUS Status; + UINT8 *Option; ++ UINT32 OptionLen; + UINT8 *IaInnerOpt; + UINT16 IaInnerLen; + UINT16 StsCode; + UINT32 T1; + UINT32 T2; + ++ T1 = 0; ++ T2 = 0; ++ + ASSERT (Instance->Config != NULL); ++ ++ // 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); ++ + // + // If the reply was received in response to a solicit with rapid commit option, + // request, renew or rebind message, the client updates the information it has +@@ -549,13 +559,29 @@ Dhcp6UpdateIaInfo ( + // + Option = Dhcp6SeekIaOption ( + Packet->Dhcp6.Option, +- Packet->Length - sizeof (EFI_DHCP6_HEADER), ++ OptionLen, + &Instance->Config->IaDescriptor + ); + if (Option == NULL) { + return EFI_DEVICE_ERROR; + } + ++ // ++ // Calculate the distance from Packet->Dhcp6.Option to the IA option. ++ // ++ // 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. ++ // ++ // (*Option - Packet->Dhcp6.Option) is the number of bytes from the start of ++ // DHCP6 option area to the start of the IA option. ++ // ++ // 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 - (UINT32)(Option - Packet->Dhcp6.Option); ++ + // + // The format of the IA_NA option is: + // +@@ -591,32 +617,32 @@ Dhcp6UpdateIaInfo ( + // + + // +- // 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 (EFI_ERROR ( ++ Dhcp6SeekInnerOptionSafe ( ++ Instance->Config->IaDescriptor.Type, ++ Option, ++ OptionLen, ++ &IaInnerOpt, ++ &IaInnerLen ++ ) ++ )) ++ { ++ return EFI_DEVICE_ERROR; ++ } ++ + if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) { + 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 +- // the remainder of the message as though the server had not included the invalid IA_NA option. ++ // the remainder of the message as though the server had not included the invalid IA_NA option. + // + if ((T1 > T2) && (T2 > 0)) { + return EFI_DEVICE_ERROR; + } +- +- 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 = DHCP6_OFFSET_OF_IA_TA_INNER_OPT (Option); +- IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))) - DHCP6_SIZE_OF_IAID); + } + + // +@@ -642,7 +668,7 @@ Dhcp6UpdateIaInfo ( + Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode); + + if (Option != NULL) { +- StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_OPT_LEN (Option)))); ++ StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(DHCP6_OFFSET_OF_STATUS_CODE (Option)))); + if (StsCode != Dhcp6StsSuccess) { + return EFI_DEVICE_ERROR; + } +@@ -703,15 +729,21 @@ Dhcp6SeekInnerOptionSafe ( + } + + if (IaType == Dhcp6OptIana) { ++ // + // Verify we have a fully formed IA_NA ++ // + if (OptionLen < DHCP6_MIN_SIZE_OF_IA_NA) { + return EFI_DEVICE_ERROR; + } + ++ // ++ // Get the IA Inner Option and Length + // + 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; +@@ -719,14 +751,18 @@ Dhcp6SeekInnerOptionSafe ( + + 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; +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.h +index 051a652f2b..ab0e1ac27f 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.h ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.h +@@ -217,4 +217,26 @@ Dhcp6OnTimerTick ( + IN VOID *Context + ); + ++/** ++ 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 ++ ); ++ + #endif +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0004.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0004.patch new file mode 100644 index 0000000000..63a3f045c8 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45229-0004.patch @@ -0,0 +1,157 @@ +From 1d0b95f6457d225c5108302a9da74b4ed7aa5a38 Mon Sep 17 00:00:00 2001 +From: "Doug Flick via groups.io" +Date: Fri, 26 Jan 2024 05:54:57 +0800 +Subject: [PATCH] NetworkPkg: : Adds a SecurityFix.yaml file + +This creates / adds a security file that tracks the security fixes +found in this package and can be used to find the fixes that were +applied. + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45229 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1d0b95f6457d225c5108302a9da74b4ed7aa5a38] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/SecurityFixes.yaml | 123 ++++++++++++++++++++++++++++++++++ + 1 file changed, 123 insertions(+) + create mode 100644 NetworkPkg/SecurityFixes.yaml + +diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml +new file mode 100644 +index 0000000000..7e900483fe +--- /dev/null ++++ b/NetworkPkg/SecurityFixes.yaml +@@ -0,0 +1,123 @@ ++## @file ++# Security Fixes for SecurityPkg ++# ++# Copyright (c) Microsoft Corporation ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++CVE_2023_45229: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45229 Unit Tests" ++ cve: CVE-2023-45229 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 01 - edk2/NetworkPkg: Out-of-bounds read when processing IA_NA/IA_TA options in a DHCPv6 Advertise message" ++ note: ++ files_impacted: ++ - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c ++ - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4534 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45229 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45230: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45230 Unit Tests" ++ cve: CVE-2023-45230 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 02 - edk2/NetworkPkg: Buffer overflow in the DHCPv6 client via a long Server ID option" ++ note: ++ files_impacted: ++ - NetworkPkg\Dhcp6Dxe\Dhcp6Io.c ++ - NetworkPkg\Dhcp6Dxe\Dhcp6Impl.h ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4535 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45230 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45231: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45231 Unit Tests" ++ cve: CVE-2023-45231 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 03 - edk2/NetworkPkg: Out-of-bounds read when handling a ND Redirect message with truncated options" ++ note: ++ files_impacted: ++ - NetworkPkg/Ip6Dxe/Ip6Option.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4536 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45231 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45232: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" ++ cve: CVE-2023-45232 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 04 - edk2/NetworkPkg: Infinite loop when parsing unknown options in the Destination Options header" ++ note: ++ files_impacted: ++ - NetworkPkg/Ip6Dxe/Ip6Option.c ++ - NetworkPkg/Ip6Dxe/Ip6Option.h ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4537 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45232 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45233: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45232 Unit Tests" ++ cve: CVE-2023-45233 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 05 - edk2/NetworkPkg: Infinite loop when parsing a PadN option in the Destination Options header " ++ note: This was fixed along with CVE-2023-45233 ++ files_impacted: ++ - NetworkPkg/Ip6Dxe/Ip6Option.c ++ - NetworkPkg/Ip6Dxe/Ip6Option.h ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4538 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45233 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45234: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45234 Unit Tests" ++ cve: CVE-2023-45234 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 06 - edk2/NetworkPkg: Buffer overflow when processing DNS Servers option in a DHCPv6 Advertise message" ++ note: ++ files_impacted: ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4539 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45234 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45235: ++ commit_titles: ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Patch" ++ - "NetworkPkg: Dhcp6Dxe: SECURITY PATCH CVE-2023-45235 Unit Tests" ++ cve: CVE-2023-45235 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 07 - edk2/NetworkPkg: Buffer overflow when handling Server ID option from a DHCPv6 proxy Advertise message" ++ note: ++ files_impacted: ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4540 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45235 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index ceebb53438..6ac72772d1 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -43,6 +43,10 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45234-0002.patch \ file://CVE-2023-45235-0001.patch \ file://CVE-2023-45235-0002.patch \ + file://CVE-2023-45229-0001.patch \ + file://CVE-2023-45229-0002.patch \ + file://CVE-2023-45229-0003.patch \ + file://CVE-2023-45229-0004.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46196 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id ECBFEC3DA4B for ; Thu, 11 Jul 2024 04:56:18 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web11.4946.1720673778343572176 for ; Wed, 10 Jul 2024 21:56:18 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250809.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B1r21P008766 for ; Wed, 10 Jul 2024 21:56:18 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 4075eg48p1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:17 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:15 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 09/11] ovmf: Fix CVE-2023-45237 Date: Thu, 11 Jul 2024 04:55:39 +0000 Message-ID: <20240711045541.2155076-9-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: p3PBUf4m0jhmQfjpaS7p4DCcCojUCXmo X-Proofpoint-ORIG-GUID: p3PBUf4m0jhmQfjpaS7p4DCcCojUCXmo X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 lowpriorityscore=0 malwarescore=0 clxscore=1015 adultscore=0 bulkscore=0 mlxscore=0 spamscore=0 mlxlogscore=999 suspectscore=0 phishscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:18 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201759 From: Soumya Sambu EDK2's Network Package is susceptible to a predictable TCP Initial Sequence Number. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45237 Upstream-patches: https://github.com/tianocore/edk2/commit/4c4ceb2ceb80c42fd5545b2a4bd80321f07f4345 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45237-0001.patch | 78 + .../ovmf/ovmf/CVE-2023-45237-0002.patch | 1288 +++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 2 + 3 files changed, 1368 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0002.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0001.patch new file mode 100644 index 0000000000..d1dcb8dc44 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0001.patch @@ -0,0 +1,78 @@ +From cf07238e5fa4f8b1138ac1c9e80530b4d4e59f1c Mon Sep 17 00:00:00 2001 +From: Pierre Gondois +Date: Fri, 11 Aug 2023 16:33:06 +0200 +Subject: [PATCH] MdePkg/Rng: Add GUID to describe Arm Rndr Rng algorithms + +BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4441 + +The EFI_RNG_PROTOCOL can rely on the RngLib. The RngLib has multiple +implementations, some of them are unsafe (e.g. BaseRngLibTimerLib). +To allow the RngDxe to detect when such implementation is used, +a GetRngGuid() function is added in a following patch. + +Prepare GetRngGuid() return values and add a gEfiRngAlgorithmArmRndr +to describe a Rng algorithm accessed through Arm's RNDR instruction. +[1] states that the implementation of this algorithm should be +compliant to NIST SP900-80. The compliance is not guaranteed. + +[1] Arm Architecture Reference Manual Armv8, for A-profile architecture +sK12.1 'Properties of the generated random number' + +Signed-off-by: Pierre Gondois +Reviewed-by: Sami Mujawar +Reviewed-by: Liming Gao +Acked-by: Ard Biesheuvel +Tested-by: Kun Qin + +CVE: CVE-2023-45237 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/cf07238e5fa4f8b1138ac1c9e80530b4d4e59f1c] + +Signed-off-by: Soumya Sambu +--- + MdePkg/Include/Protocol/Rng.h | 10 ++++++++++ + MdePkg/MdePkg.dec | 1 + + 2 files changed, 11 insertions(+) + +diff --git a/MdePkg/Include/Protocol/Rng.h b/MdePkg/Include/Protocol/Rng.h +index baf425587b..38bde53240 100644 +--- a/MdePkg/Include/Protocol/Rng.h ++++ b/MdePkg/Include/Protocol/Rng.h +@@ -67,6 +67,15 @@ typedef EFI_GUID EFI_RNG_ALGORITHM; + { \ + 0xe43176d7, 0xb6e8, 0x4827, {0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 } \ + } ++/// ++/// The Arm Architecture states the RNDR that the DRBG algorithm should be compliant ++/// with NIST SP800-90A, while not mandating a particular algorithm, so as to be ++/// inclusive of different geographies. ++/// ++#define EFI_RNG_ALGORITHM_ARM_RNDR \ ++ { \ ++ 0x43d2fde3, 0x9d4e, 0x4d79, {0x02, 0x96, 0xa8, 0x9b, 0xca, 0x78, 0x08, 0x41} \ ++ } + + /** + Returns information about the random number generation implementation. +@@ -146,5 +155,6 @@ extern EFI_GUID gEfiRngAlgorithmSp80090Ctr256Guid; + extern EFI_GUID gEfiRngAlgorithmX9313DesGuid; + extern EFI_GUID gEfiRngAlgorithmX931AesGuid; + extern EFI_GUID gEfiRngAlgorithmRaw; ++extern EFI_GUID gEfiRngAlgorithmArmRndr; + + #endif +diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec +index 59b405928b..a449dbc556 100644 +--- a/MdePkg/MdePkg.dec ++++ b/MdePkg/MdePkg.dec +@@ -594,6 +594,7 @@ + gEfiRngAlgorithmX9313DesGuid = { 0x63c4785a, 0xca34, 0x4012, {0xa3, 0xc8, 0x0b, 0x6a, 0x32, 0x4f, 0x55, 0x46 }} + gEfiRngAlgorithmX931AesGuid = { 0xacd03321, 0x777e, 0x4d3d, {0xb1, 0xc8, 0x20, 0xcf, 0xd8, 0x88, 0x20, 0xc9 }} + gEfiRngAlgorithmRaw = { 0xe43176d7, 0xb6e8, 0x4827, {0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 }} ++ gEfiRngAlgorithmArmRndr = { 0x43d2fde3, 0x9d4e, 0x4d79, {0x02, 0x96, 0xa8, 0x9b, 0xca, 0x78, 0x08, 0x41 }} + + ## Include/Protocol/AdapterInformation.h + gEfiAdapterInfoMediaStateGuid = { 0xD7C74207, 0xA831, 0x4A26, {0xB1, 0xF5, 0xD1, 0x93, 0x06, 0x5C, 0xE8, 0xB6 }} +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0002.patch new file mode 100644 index 0000000000..722a6cd530 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45237-0002.patch @@ -0,0 +1,1288 @@ +From 4c4ceb2ceb80c42fd5545b2a4bd80321f07f4345 Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Wed, 8 May 2024 22:56:28 -0700 +Subject: [PATCH] NetworkPkg: SECURITY PATCH CVE-2023-45237 + +REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4542 + +Bug Overview: +PixieFail Bug #9 +CVE-2023-45237 +CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N +CWE-338 Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) + +Use of a Weak PseudoRandom Number Generator + +Change Overview: + +Updates all Instances of NET_RANDOM (NetRandomInitSeed ()) to either + +> +> EFI_STATUS +> EFIAPI +> PseudoRandomU32 ( +> OUT UINT32 *Output +> ); +> + +or (depending on the use case) + +> +> EFI_STATUS +> EFIAPI +> PseudoRandom ( +> OUT VOID *Output, +> IN UINTN OutputLength +> ); +> + +This is because the use of + +Example: + +The following code snippet PseudoRandomU32 () function is used: + +> +> UINT32 Random; +> +> Status = PseudoRandomU32 (&Random); +> if (EFI_ERROR (Status)) { +> DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", +__func__, Status)); +> return Status; +> } +> + +This also introduces a new PCD to enable/disable the use of the +secure implementation of algorithms for PseudoRandom () and +instead depend on the default implementation. This may be required for +some platforms where the UEFI Spec defined algorithms are not available. + +> +> PcdEnforceSecureRngAlgorithms +> + +If the platform does not have any one of the UEFI defined +secure RNG algorithms then the driver will assert. + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45237 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4c4ceb2ceb80c42fd5545b2a4bd80321f07f4345] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c | 10 +- + NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c | 11 +- + NetworkPkg/DnsDxe/DnsDhcp.c | 10 +- + NetworkPkg/DnsDxe/DnsImpl.c | 11 +- + NetworkPkg/HttpBootDxe/HttpBootDhcp6.c | 10 +- + NetworkPkg/IScsiDxe/IScsiCHAP.c | 19 ++- + NetworkPkg/IScsiDxe/IScsiMisc.c | 14 +-- + NetworkPkg/IScsiDxe/IScsiMisc.h | 6 +- + NetworkPkg/Include/Library/NetLib.h | 40 +++++-- + NetworkPkg/Ip4Dxe/Ip4Driver.c | 10 +- + NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c | 9 +- + NetworkPkg/Ip6Dxe/Ip6Driver.c | 17 ++- + NetworkPkg/Ip6Dxe/Ip6If.c | 12 +- + NetworkPkg/Ip6Dxe/Ip6Mld.c | 12 +- + NetworkPkg/Ip6Dxe/Ip6Nd.c | 33 +++++- + NetworkPkg/Ip6Dxe/Ip6Nd.h | 8 +- + NetworkPkg/Library/DxeNetLib/DxeNetLib.c | 130 ++++++++++++++++++--- + NetworkPkg/Library/DxeNetLib/DxeNetLib.inf | 14 ++- + NetworkPkg/NetworkPkg.dec | 7 ++ + NetworkPkg/SecurityFixes.yaml | 39 +++++++ + NetworkPkg/TcpDxe/TcpDriver.c | 15 ++- + NetworkPkg/TcpDxe/TcpDxe.inf | 3 + + NetworkPkg/Udp4Dxe/Udp4Driver.c | 10 +- + NetworkPkg/Udp6Dxe/Udp6Driver.c | 11 +- + NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c | 9 +- + NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 11 +- + NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c | 12 +- + 27 files changed, 410 insertions(+), 83 deletions(-) + +diff --git a/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c b/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c +index 8c37e93be3..892caee368 100644 +--- a/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c ++++ b/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c +@@ -1,6 +1,7 @@ + /** @file + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -189,6 +190,13 @@ Dhcp4CreateService ( + { + DHCP_SERVICE *DhcpSb; + EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + *Service = NULL; + DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE)); +@@ -203,7 +211,7 @@ Dhcp4CreateService ( + DhcpSb->Image = ImageHandle; + InitializeListHead (&DhcpSb->Children); + DhcpSb->DhcpState = Dhcp4Stopped; +- DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ()); ++ DhcpSb->Xid = Random; + CopyMem ( + &DhcpSb->ServiceBinding, + &mDhcp4ServiceBindingTemplate, +diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c +index b591a4605b..e7f2787a98 100644 +--- a/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c ++++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c +@@ -3,7 +3,7 @@ + implementation for Dhcp6 Driver. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -123,6 +123,13 @@ Dhcp6CreateService ( + { + DHCP6_SERVICE *Dhcp6Srv; + EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + *Service = NULL; + Dhcp6Srv = AllocateZeroPool (sizeof (DHCP6_SERVICE)); +@@ -147,7 +154,7 @@ Dhcp6CreateService ( + Dhcp6Srv->Signature = DHCP6_SERVICE_SIGNATURE; + Dhcp6Srv->Controller = Controller; + Dhcp6Srv->Image = ImageHandle; +- Dhcp6Srv->Xid = (0xffffff & NET_RANDOM (NetRandomInitSeed ())); ++ Dhcp6Srv->Xid = (0xffffff & Random); + + CopyMem ( + &Dhcp6Srv->ServiceBinding, +diff --git a/NetworkPkg/DnsDxe/DnsDhcp.c b/NetworkPkg/DnsDxe/DnsDhcp.c +index 933565a32d..9eb3c1d2d8 100644 +--- a/NetworkPkg/DnsDxe/DnsDhcp.c ++++ b/NetworkPkg/DnsDxe/DnsDhcp.c +@@ -2,6 +2,7 @@ + Functions implementation related with DHCPv4/v6 for DNS driver. + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -277,6 +278,7 @@ GetDns4ServerFromDhcp4 ( + EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; + BOOLEAN IsDone; + UINTN Index; ++ UINT32 Random; + + Image = Instance->Service->ImageHandle; + Controller = Instance->Service->ControllerHandle; +@@ -292,6 +294,12 @@ GetDns4ServerFromDhcp4 ( + Data = NULL; + InterfaceInfo = NULL; + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + ZeroMem ((UINT8 *)ParaList, sizeof (ParaList)); + + ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA)); +@@ -467,7 +475,7 @@ GetDns4ServerFromDhcp4 ( + + Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet); + +- Token.Packet->Dhcp4.Header.Xid = HTONL (NET_RANDOM (NetRandomInitSeed ())); ++ Token.Packet->Dhcp4.Header.Xid = Random; + + Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000); + +diff --git a/NetworkPkg/DnsDxe/DnsImpl.c b/NetworkPkg/DnsDxe/DnsImpl.c +index d311812800..c2629bb8df 100644 +--- a/NetworkPkg/DnsDxe/DnsImpl.c ++++ b/NetworkPkg/DnsDxe/DnsImpl.c +@@ -2,6 +2,7 @@ + DnsDxe support functions implementation. + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -1963,6 +1964,14 @@ ConstructDNSQuery ( + NET_FRAGMENT Frag; + DNS_HEADER *DnsHeader; + DNS_QUERY_SECTION *DnsQuery; ++ EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + // + // Messages carried by UDP are restricted to 512 bytes (not counting the IP +@@ -1977,7 +1986,7 @@ ConstructDNSQuery ( + // Fill header + // + DnsHeader = (DNS_HEADER *)Frag.Bulk; +- DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed ()); ++ DnsHeader->Identification = (UINT16)Random; + DnsHeader->Flags.Uint16 = 0x0000; + DnsHeader->Flags.Bits.RD = 1; + DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD; +diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c +index b22cef4ff5..f964515b0f 100644 +--- a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c ++++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c +@@ -2,6 +2,7 @@ + Functions implementation related with DHCPv6 for HTTP boot driver. + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -951,6 +952,7 @@ HttpBootDhcp6Sarr ( + UINT32 OptCount; + UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE]; + EFI_STATUS Status; ++ UINT32 Random; + + Dhcp6 = Private->Dhcp6; + ASSERT (Dhcp6 != NULL); +@@ -961,6 +963,12 @@ HttpBootDhcp6Sarr ( + OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer); + ASSERT (OptCount > 0); + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); + if (Retransmit == NULL) { + return EFI_OUT_OF_RESOURCES; +@@ -976,7 +984,7 @@ HttpBootDhcp6Sarr ( + Config.IaInfoEvent = NULL; + Config.RapidCommit = FALSE; + Config.ReconfigureAccept = FALSE; +- Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ()); ++ Config.IaDescriptor.IaId = Random; + Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; + Config.SolicitRetransmission = Retransmit; + Retransmit->Irt = 4; +diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.c b/NetworkPkg/IScsiDxe/IScsiCHAP.c +index b507f11cd4..bebb1ac29b 100644 +--- a/NetworkPkg/IScsiDxe/IScsiCHAP.c ++++ b/NetworkPkg/IScsiDxe/IScsiCHAP.c +@@ -3,6 +3,7 @@ + Configuration. + + Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -576,16 +577,24 @@ IScsiCHAPToSendReq ( + // + // CHAP_I= + // +- IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1); ++ Status = IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1); ++ if (EFI_ERROR (Status)) { ++ break; ++ } ++ + AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier); + IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr); + // + // CHAP_C= + // +- IScsiGenRandom ( +- (UINT8 *)AuthData->OutChallenge, +- AuthData->Hash->DigestSize +- ); ++ Status = IScsiGenRandom ( ++ (UINT8 *)AuthData->OutChallenge, ++ AuthData->Hash->DigestSize ++ ); ++ if (EFI_ERROR (Status)) { ++ break; ++ } ++ + BinToHexStatus = IScsiBinToHex ( + (UINT8 *)AuthData->OutChallenge, + AuthData->Hash->DigestSize, +diff --git a/NetworkPkg/IScsiDxe/IScsiMisc.c b/NetworkPkg/IScsiDxe/IScsiMisc.c +index b3ea90158f..cd77f1a13e 100644 +--- a/NetworkPkg/IScsiDxe/IScsiMisc.c ++++ b/NetworkPkg/IScsiDxe/IScsiMisc.c +@@ -2,6 +2,7 @@ + Miscellaneous routines for iSCSI driver. + + Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -474,20 +475,17 @@ IScsiNetNtoi ( + @param[in, out] Rand The buffer to contain random numbers. + @param[in] RandLength The length of the Rand buffer. + ++ @retval EFI_SUCCESS on success ++ @retval others on error ++ + **/ +-VOID ++EFI_STATUS + IScsiGenRandom ( + IN OUT UINT8 *Rand, + IN UINTN RandLength + ) + { +- UINT32 Random; +- +- while (RandLength > 0) { +- Random = NET_RANDOM (NetRandomInitSeed ()); +- *Rand++ = (UINT8)(Random); +- RandLength--; +- } ++ return PseudoRandom (Rand, RandLength); + } + + /** +diff --git a/NetworkPkg/IScsiDxe/IScsiMisc.h b/NetworkPkg/IScsiDxe/IScsiMisc.h +index a951eee70e..91b2cd2261 100644 +--- a/NetworkPkg/IScsiDxe/IScsiMisc.h ++++ b/NetworkPkg/IScsiDxe/IScsiMisc.h +@@ -2,6 +2,7 @@ + Miscellaneous definitions for iSCSI driver. + + Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -202,8 +203,11 @@ IScsiNetNtoi ( + @param[in, out] Rand The buffer to contain random numbers. + @param[in] RandLength The length of the Rand buffer. + ++ @retval EFI_SUCCESS on success ++ @retval others on error ++ + **/ +-VOID ++EFI_STATUS + IScsiGenRandom ( + IN OUT UINT8 *Rand, + IN UINTN RandLength +diff --git a/NetworkPkg/Include/Library/NetLib.h b/NetworkPkg/Include/Library/NetLib.h +index 8c0e62b388..e8108b79db 100644 +--- a/NetworkPkg/Include/Library/NetLib.h ++++ b/NetworkPkg/Include/Library/NetLib.h +@@ -3,6 +3,7 @@ + It provides basic functions for the UEFI network stack. + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -539,8 +540,6 @@ extern EFI_IPv4_ADDRESS mZeroIp4Addr; + #define TICKS_PER_MS 10000U + #define TICKS_PER_SECOND 10000000U + +-#define NET_RANDOM(Seed) ((UINT32) ((UINT32) (Seed) * 1103515245UL + 12345) % 4294967295UL) +- + /** + Extract a UINT32 from a byte stream. + +@@ -580,19 +579,40 @@ NetPutUint32 ( + ); + + /** +- Initialize a random seed using current time and monotonic count. ++ Generate a Random output data given a length. + +- Get current time and monotonic count first. Then initialize a random seed +- based on some basic mathematics operation on the hour, day, minute, second, +- nanosecond and year of the current time and the monotonic count value. ++ @param[out] Output - The buffer to store the generated random data. ++ @param[in] OutputLength - The length of the output buffer. + +- @return The random seed initialized with current time. ++ @retval EFI_SUCCESS On Success ++ @retval EFI_INVALID_PARAMETER Pointer is null or size is zero ++ @retval EFI_NOT_FOUND RNG protocol not found ++ @retval Others Error from RngProtocol->GetRNG() + ++ @return Status code + **/ +-UINT32 ++EFI_STATUS + EFIAPI +-NetRandomInitSeed ( +- VOID ++PseudoRandom ( ++ OUT VOID *Output, ++ IN UINTN OutputLength ++ ); ++ ++/** ++ Generate a 32-bit pseudo-random number. ++ ++ @param[out] Output - The buffer to store the generated random number. ++ ++ @retval EFI_SUCCESS On Success ++ @retval EFI_NOT_FOUND RNG protocol not found ++ @retval Others Error from RngProtocol->GetRNG() ++ ++ @return Status code ++**/ ++EFI_STATUS ++EFIAPI ++PseudoRandomU32 ( ++ OUT UINT32 *Output + ); + + #define NET_LIST_USER_STRUCT(Entry, Type, Field) \ +diff --git a/NetworkPkg/Ip4Dxe/Ip4Driver.c b/NetworkPkg/Ip4Dxe/Ip4Driver.c +index ec483ff01f..683423f38d 100644 +--- a/NetworkPkg/Ip4Dxe/Ip4Driver.c ++++ b/NetworkPkg/Ip4Dxe/Ip4Driver.c +@@ -2,6 +2,7 @@ + The driver binding and service binding protocol for IP4 driver. + + Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +@@ -549,11 +550,18 @@ Ip4DriverBindingStart ( + EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2; + UINTN Index; + IP4_CONFIG2_DATA_ITEM *DataItem; ++ UINT32 Random; + + IpSb = NULL; + Ip4Cfg2 = NULL; + DataItem = NULL; + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + // + // Test for the Ip4 service binding protocol + // +@@ -653,7 +661,7 @@ Ip4DriverBindingStart ( + // + // Initialize the IP4 ID + // +- mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ()); ++ mIp4Id = (UINT16)Random; + + return Status; + +diff --git a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c +index 70e232ce6c..4c1354d26c 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c ++++ b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c +@@ -2276,6 +2276,13 @@ Ip6ConfigInitInstance ( + UINTN Index; + UINT16 IfIndex; + IP6_CONFIG_DATA_ITEM *DataItem; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance); + +@@ -2381,7 +2388,7 @@ Ip6ConfigInitInstance ( + // The NV variable is not set, so generate a random IAID, and write down the + // fresh new configuration as the NV variable now. + // +- Instance->IaId = NET_RANDOM (NetRandomInitSeed ()); ++ Instance->IaId = Random; + + for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) { + Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31)); +diff --git a/NetworkPkg/Ip6Dxe/Ip6Driver.c b/NetworkPkg/Ip6Dxe/Ip6Driver.c +index b483a7d136..cbe011dad4 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Driver.c ++++ b/NetworkPkg/Ip6Dxe/Ip6Driver.c +@@ -3,7 +3,7 @@ + + Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -316,7 +316,11 @@ Ip6CreateService ( + IpSb->CurHopLimit = IP6_HOP_LIMIT; + IpSb->LinkMTU = IP6_MIN_LINK_MTU; + IpSb->BaseReachableTime = IP6_REACHABLE_TIME; +- Ip6UpdateReachableTime (IpSb); ++ Status = Ip6UpdateReachableTime (IpSb); ++ if (EFI_ERROR (Status)) { ++ goto ON_ERROR; ++ } ++ + // + // RFC4861 RETRANS_TIMER: 1,000 milliseconds + // +@@ -516,11 +520,18 @@ Ip6DriverBindingStart ( + EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + IP6_CONFIG_DATA_ITEM *DataItem; ++ UINT32 Random; + + IpSb = NULL; + Ip6Cfg = NULL; + DataItem = NULL; + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + // + // Test for the Ip6 service binding protocol + // +@@ -656,7 +667,7 @@ Ip6DriverBindingStart ( + // + // Initialize the IP6 ID + // +- mIp6Id = NET_RANDOM (NetRandomInitSeed ()); ++ mIp6Id = Random; + + return EFI_SUCCESS; + +diff --git a/NetworkPkg/Ip6Dxe/Ip6If.c b/NetworkPkg/Ip6Dxe/Ip6If.c +index 4629c05f25..f3d11c4d21 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6If.c ++++ b/NetworkPkg/Ip6Dxe/Ip6If.c +@@ -2,7 +2,7 @@ + Implement IP6 pseudo interface. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -89,6 +89,14 @@ Ip6SetAddress ( + IP6_PREFIX_LIST_ENTRY *PrefixEntry; + UINT64 Delay; + IP6_DELAY_JOIN_LIST *DelayNode; ++ EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE); + +@@ -164,7 +172,7 @@ Ip6SetAddress ( + // Thus queue the address to be processed in Duplicate Address Detection module + // after the delay time (in milliseconds). + // +- Delay = (UINT64)NET_RANDOM (NetRandomInitSeed ()); ++ Delay = (UINT64)Random; + Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS); + Delay = RShiftU64 (Delay, 32); + +diff --git a/NetworkPkg/Ip6Dxe/Ip6Mld.c b/NetworkPkg/Ip6Dxe/Ip6Mld.c +index e6b2b653e2..498a118543 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Mld.c ++++ b/NetworkPkg/Ip6Dxe/Ip6Mld.c +@@ -696,7 +696,15 @@ Ip6UpdateDelayTimer ( + IN OUT IP6_MLD_GROUP *Group + ) + { +- UINT32 Delay; ++ UINT32 Delay; ++ EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + // + // If the Query packet specifies a Maximum Response Delay of zero, perform timer +@@ -715,7 +723,7 @@ Ip6UpdateDelayTimer ( + // is less than the remaining value of the running timer. + // + if ((Group->DelayTimer == 0) || (Delay < Group->DelayTimer)) { +- Group->DelayTimer = Delay / 4294967295UL * NET_RANDOM (NetRandomInitSeed ()); ++ Group->DelayTimer = Delay / 4294967295UL * Random; + } + + return EFI_SUCCESS; +diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.c b/NetworkPkg/Ip6Dxe/Ip6Nd.c +index c10c7017f8..72aa45c10f 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Nd.c ++++ b/NetworkPkg/Ip6Dxe/Ip6Nd.c +@@ -2,7 +2,7 @@ + Implementation of Neighbor Discovery support routines. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -16,17 +16,28 @@ EFI_MAC_ADDRESS mZeroMacAddress; + + @param[in, out] IpSb Points to the IP6_SERVICE. + ++ @retval EFI_SUCCESS ReachableTime Updated ++ @retval others Failed to update ReachableTime + **/ +-VOID ++EFI_STATUS + Ip6UpdateReachableTime ( + IN OUT IP6_SERVICE *IpSb + ) + { +- UINT32 Random; ++ UINT32 Random; ++ EFI_STATUS Status; + +- Random = (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE; ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ ++ Random = (Random / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE; + Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED; + IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE; ++ ++ return EFI_SUCCESS; + } + + /** +@@ -972,10 +983,17 @@ Ip6InitDADProcess ( + IP6_SERVICE *IpSb; + EFI_STATUS Status; + UINT32 MaxDelayTick; ++ UINT32 Random; + + NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE); + ASSERT (AddressInfo != NULL); + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + // + // Do nothing if we have already started DAD on the address. + // +@@ -1014,7 +1032,7 @@ Ip6InitDADProcess ( + Entry->Transmit = 0; + Entry->Receive = 0; + MaxDelayTick = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS; +- Entry->RetransTick = (MaxDelayTick * ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5; ++ Entry->RetransTick = (MaxDelayTick * ((Random % 5) + 1)) / 5; + Entry->AddressInfo = AddressInfo; + Entry->Callback = Callback; + Entry->Context = Context; +@@ -2078,7 +2096,10 @@ Ip6ProcessRouterAdvertise ( + // in BaseReachableTime and recompute a ReachableTime. + // + IpSb->BaseReachableTime = ReachableTime; +- Ip6UpdateReachableTime (IpSb); ++ Status = Ip6UpdateReachableTime (IpSb); ++ if (EFI_ERROR (Status)) { ++ goto Exit; ++ } + } + + if (RetransTimer != 0) { +diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.h b/NetworkPkg/Ip6Dxe/Ip6Nd.h +index bf64e9114e..5795e23c7d 100644 +--- a/NetworkPkg/Ip6Dxe/Ip6Nd.h ++++ b/NetworkPkg/Ip6Dxe/Ip6Nd.h +@@ -2,7 +2,7 @@ + Definition of Neighbor Discovery support routines. + + Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -780,10 +780,10 @@ Ip6OnArpResolved ( + /** + Update the ReachableTime in IP6 service binding instance data, in milliseconds. + +- @param[in, out] IpSb Points to the IP6_SERVICE. +- ++ @retval EFI_SUCCESS ReachableTime Updated ++ @retval others Failed to update ReachableTime + **/ +-VOID ++EFI_STATUS + Ip6UpdateReachableTime ( + IN OUT IP6_SERVICE *IpSb + ); +diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c +index fd4a9e15a8..01c13c08d2 100644 +--- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c ++++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c +@@ -3,6 +3,7 @@ + + Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + +@@ -31,6 +32,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + #include ++#include + + #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE) + #define DEFAULT_ZERO_START ((UINTN) ~0) +@@ -127,6 +129,25 @@ GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = { + 0 + }; + ++// ++// These represent UEFI SPEC defined algorithms that should be supported by ++// the RNG protocol and are generally considered secure. ++// ++// The order of the algorithms in this array is important. This order is the order ++// in which the algorithms will be tried by the RNG protocol. ++// If your platform needs to use a specific algorithm for the random number generator, ++// then you should place that algorithm first in the array. ++// ++GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID *mSecureHashAlgorithms[] = { ++ &gEfiRngAlgorithmSp80090Ctr256Guid, // SP800-90A DRBG CTR using AES-256 ++ &gEfiRngAlgorithmSp80090Hmac256Guid, // SP800-90A DRBG HMAC using SHA-256 ++ &gEfiRngAlgorithmSp80090Hash256Guid, // SP800-90A DRBG Hash using SHA-256 ++ &gEfiRngAlgorithmArmRndr, // unspecified SP800-90A DRBG via ARM RNDR register ++ &gEfiRngAlgorithmRaw, // Raw data from NRBG (or TRNG) ++}; ++ ++#define SECURE_HASH_ALGORITHMS_SIZE (sizeof (mSecureHashAlgorithms) / sizeof (EFI_GUID *)) ++ + /** + Locate the handles that support SNP, then open one of them + to send the syslog packets. The caller isn't required to close +@@ -884,34 +905,107 @@ Ip6Swap128 ( + } + + /** +- Initialize a random seed using current time and monotonic count. ++ Generate a Random output data given a length. + +- Get current time and monotonic count first. Then initialize a random seed +- based on some basic mathematics operation on the hour, day, minute, second, +- nanosecond and year of the current time and the monotonic count value. ++ @param[out] Output - The buffer to store the generated random data. ++ @param[in] OutputLength - The length of the output buffer. + +- @return The random seed initialized with current time. ++ @retval EFI_SUCCESS On Success ++ @retval EFI_INVALID_PARAMETER Pointer is null or size is zero ++ @retval EFI_NOT_FOUND RNG protocol not found ++ @retval Others Error from RngProtocol->GetRNG() + ++ @return Status code + **/ +-UINT32 ++EFI_STATUS + EFIAPI +-NetRandomInitSeed ( +- VOID ++PseudoRandom ( ++ OUT VOID *Output, ++ IN UINTN OutputLength + ) + { +- EFI_TIME Time; +- UINT32 Seed; +- UINT64 MonotonicCount; ++ EFI_RNG_PROTOCOL *RngProtocol; ++ EFI_STATUS Status; ++ UINTN AlgorithmIndex; ++ ++ if ((Output == NULL) || (OutputLength == 0)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&RngProtocol); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Failed to locate EFI_RNG_PROTOCOL: %r\n", Status)); ++ ASSERT_EFI_ERROR (Status); ++ return Status; ++ } ++ ++ if (PcdGetBool (PcdEnforceSecureRngAlgorithms)) { ++ for (AlgorithmIndex = 0; AlgorithmIndex < SECURE_HASH_ALGORITHMS_SIZE; AlgorithmIndex++) { ++ Status = RngProtocol->GetRNG (RngProtocol, mSecureHashAlgorithms[AlgorithmIndex], OutputLength, (UINT8 *)Output); ++ if (!EFI_ERROR (Status)) { ++ // ++ // Secure Algorithm was supported on this platform ++ // ++ return EFI_SUCCESS; ++ } else if (Status == EFI_UNSUPPORTED) { ++ // ++ // Secure Algorithm was not supported on this platform ++ // ++ DEBUG ((DEBUG_ERROR, "Failed to generate random data using secure algorithm %d: %r\n", AlgorithmIndex, Status)); ++ ++ // ++ // Try the next secure algorithm ++ // ++ continue; ++ } else { ++ // ++ // Some other error occurred ++ // ++ DEBUG ((DEBUG_ERROR, "Failed to generate random data using secure algorithm %d: %r\n", AlgorithmIndex, Status)); ++ ASSERT_EFI_ERROR (Status); ++ return Status; ++ } ++ } ++ ++ // ++ // If we get here, we failed to generate random data using any secure algorithm ++ // Platform owner should ensure that at least one secure algorithm is supported ++ // ++ ASSERT_EFI_ERROR (Status); ++ return Status; ++ } ++ ++ // ++ // Lets try using the default algorithm (which may not be secure) ++ // ++ Status = RngProtocol->GetRNG (RngProtocol, NULL, OutputLength, (UINT8 *)Output); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random data: %r\n", __func__, Status)); ++ ASSERT_EFI_ERROR (Status); ++ return Status; ++ } + +- gRT->GetTime (&Time, NULL); +- Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second); +- Seed ^= Time.Nanosecond; +- Seed ^= Time.Year << 7; ++ return EFI_SUCCESS; ++} ++ ++/** ++ Generate a 32-bit pseudo-random number. + +- gBS->GetNextMonotonicCount (&MonotonicCount); +- Seed += (UINT32)MonotonicCount; ++ @param[out] Output - The buffer to store the generated random number. + +- return Seed; ++ @retval EFI_SUCCESS On Success ++ @retval EFI_NOT_FOUND RNG protocol not found ++ @retval Others Error from RngProtocol->GetRNG() ++ ++ @return Status code ++**/ ++EFI_STATUS ++EFIAPI ++PseudoRandomU32 ( ++ OUT UINT32 *Output ++ ) ++{ ++ return PseudoRandom (Output, sizeof (*Output)); + } + + /** +diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf +index 8145d256ec..a8f534a293 100644 +--- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf ++++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf +@@ -3,6 +3,7 @@ + # + # Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ # (C) Copyright 2015 Hewlett Packard Enterprise Development LP
++# Copyright (c) Microsoft Corporation + # SPDX-License-Identifier: BSD-2-Clause-Patent + # + ## +@@ -49,7 +50,11 @@ + gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable + gEfiAdapterInfoMediaStateGuid ## SOMETIMES_CONSUMES +- ++ gEfiRngAlgorithmRaw ## CONSUMES ++ gEfiRngAlgorithmSp80090Ctr256Guid ## CONSUMES ++ gEfiRngAlgorithmSp80090Hmac256Guid ## CONSUMES ++ gEfiRngAlgorithmSp80090Hash256Guid ## CONSUMES ++ gEfiRngAlgorithmArmRndr ## CONSUMES + + [Protocols] + gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES +@@ -59,3 +64,10 @@ + gEfiComponentNameProtocolGuid ## SOMETIMES_CONSUMES + gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiAdapterInformationProtocolGuid ## SOMETIMES_CONSUMES ++ gEfiRngProtocolGuid ## CONSUMES ++ ++[FixedPcd] ++ gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms ## CONSUMES ++ ++[Depex] ++ gEfiRngProtocolGuid +diff --git a/NetworkPkg/NetworkPkg.dec b/NetworkPkg/NetworkPkg.dec +index 928e84fec4..ff335e957c 100644 +--- a/NetworkPkg/NetworkPkg.dec ++++ b/NetworkPkg/NetworkPkg.dec +@@ -5,6 +5,7 @@ + # + # Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.
+ # (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP
++# Copyright (c) Microsoft Corporation + # + # SPDX-License-Identifier: BSD-2-Clause-Patent + # +@@ -127,6 +128,12 @@ + # @Prompt Indicates whether SnpDxe creates event for ExitBootServices() call. + gEfiNetworkPkgTokenSpaceGuid.PcdSnpCreateExitBootServicesEvent|TRUE|BOOLEAN|0x1000000C + ++ ## Enforces the use of Secure UEFI spec defined RNG algorithms for all network connections. ++ # TRUE - Enforce the use of Secure UEFI spec defined RNG algorithms. ++ # FALSE - Do not enforce and depend on the default implementation of RNG algorithm from the provider. ++ # @Prompt Enforce the use of Secure UEFI spec defined RNG algorithms. ++ gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms|TRUE|BOOLEAN|0x1000000D ++ + [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] + ## IPv6 DHCP Unique Identifier (DUID) Type configuration (From RFCs 3315 and 6355). + # 01 = DUID Based on Link-layer Address Plus Time [DUID-LLT] +diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml +index 7e900483fe..2b2c794697 100644 +--- a/NetworkPkg/SecurityFixes.yaml ++++ b/NetworkPkg/SecurityFixes.yaml +@@ -121,3 +121,42 @@ CVE_2023_45235: + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45237: ++ commit_titles: ++ - "NetworkPkg:: SECURITY PATCH CVE 2023-45237" ++ cve: CVE-2023-45237 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 09 - Use of a Weak PseudoRandom Number Generator" ++ note: ++ files_impacted: ++ - NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c ++ - NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c ++ - NetworkPkg/DnsDxe/DnsDhcp.c ++ - NetworkPkg/DnsDxe/DnsImpl.c ++ - NetworkPkg/HttpBootDxe/HttpBootDhcp6.c ++ - NetworkPkg/IScsiDxe/IScsiCHAP.c ++ - NetworkPkg/IScsiDxe/IScsiMisc.c ++ - NetworkPkg/IScsiDxe/IScsiMisc.h ++ - NetworkPkg/Include/Library/NetLib.h ++ - NetworkPkg/Ip4Dxe/Ip4Driver.c ++ - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c ++ - NetworkPkg/Ip6Dxe/Ip6Driver.c ++ - NetworkPkg/Ip6Dxe/Ip6If.c ++ - NetworkPkg/Ip6Dxe/Ip6Mld.c ++ - NetworkPkg/Ip6Dxe/Ip6Nd.c ++ - NetworkPkg/Ip6Dxe/Ip6Nd.h ++ - NetworkPkg/Library/DxeNetLib/DxeNetLib.c ++ - NetworkPkg/Library/DxeNetLib/DxeNetLib.inf ++ - NetworkPkg/NetworkPkg.dec ++ - NetworkPkg/TcpDxe/TcpDriver.c ++ - NetworkPkg/Udp4Dxe/Udp4Driver.c ++ - NetworkPkg/Udp6Dxe/Udp6Driver.c ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++ - NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4542 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45237 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +diff --git a/NetworkPkg/TcpDxe/TcpDriver.c b/NetworkPkg/TcpDxe/TcpDriver.c +index 98a90e0210..8fe6badd68 100644 +--- a/NetworkPkg/TcpDxe/TcpDriver.c ++++ b/NetworkPkg/TcpDxe/TcpDriver.c +@@ -2,7 +2,7 @@ + The driver binding and service binding protocol for the TCP driver. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -163,7 +163,13 @@ TcpDriverEntryPoint ( + ) + { + EFI_STATUS Status; +- UINT32 Seed; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a Failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + // + // Install the TCP Driver Binding Protocol +@@ -203,9 +209,8 @@ TcpDriverEntryPoint ( + // + // Initialize ISS and random port. + // +- Seed = NetRandomInitSeed (); +- mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss; +- mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN)); ++ mTcpGlobalIss = Random % mTcpGlobalIss; ++ mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (Random % TCP_PORT_KNOWN)); + mTcp6RandomPort = mTcp4RandomPort; + + return EFI_SUCCESS; +diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf +index c0acbdca57..cf5423f4c5 100644 +--- a/NetworkPkg/TcpDxe/TcpDxe.inf ++++ b/NetworkPkg/TcpDxe/TcpDxe.inf +@@ -82,5 +82,8 @@ + gEfiTcp6ProtocolGuid ## BY_START + gEfiTcp6ServiceBindingProtocolGuid ## BY_START + ++[Depex] ++ gEfiHash2ServiceBindingProtocolGuid ++ + [UserExtensions.TianoCore."ExtraFiles"] + TcpDxeExtra.uni +diff --git a/NetworkPkg/Udp4Dxe/Udp4Driver.c b/NetworkPkg/Udp4Dxe/Udp4Driver.c +index cb917fcfc9..c7ea16f4cd 100644 +--- a/NetworkPkg/Udp4Dxe/Udp4Driver.c ++++ b/NetworkPkg/Udp4Dxe/Udp4Driver.c +@@ -1,6 +1,7 @@ + /** @file + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
++Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -555,6 +556,13 @@ Udp4DriverEntryPoint ( + ) + { + EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + // + // Install the Udp4DriverBinding and Udp4ComponentName protocols. +@@ -571,7 +579,7 @@ Udp4DriverEntryPoint ( + // + // Initialize the UDP random port. + // +- mUdp4RandomPort = (UINT16)(((UINT16)NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); ++ mUdp4RandomPort = (UINT16)(((UINT16)Random) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); + } + + return Status; +diff --git a/NetworkPkg/Udp6Dxe/Udp6Driver.c b/NetworkPkg/Udp6Dxe/Udp6Driver.c +index ae96fb9966..edb758d57c 100644 +--- a/NetworkPkg/Udp6Dxe/Udp6Driver.c ++++ b/NetworkPkg/Udp6Dxe/Udp6Driver.c +@@ -2,7 +2,7 @@ + Driver Binding functions and Service Binding functions for the Network driver module. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -596,6 +596,13 @@ Udp6DriverEntryPoint ( + ) + { + EFI_STATUS Status; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } + + // + // Install the Udp6DriverBinding and Udp6ComponentName protocols. +@@ -614,7 +621,7 @@ Udp6DriverEntryPoint ( + // Initialize the UDP random port. + // + mUdp6RandomPort = (UINT16)( +- ((UINT16)NetRandomInitSeed ()) % ++ ((UINT16)Random) % + UDP6_PORT_KNOWN + + UDP6_PORT_KNOWN + ); +diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c +index 91146b78cb..452038c219 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c +@@ -2,7 +2,7 @@ + Functions implementation related with DHCPv4 for UefiPxeBc Driver. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -1381,6 +1381,12 @@ PxeBcDhcp4Discover ( + UINT8 VendorOptLen; + UINT32 Xid; + ++ Status = PseudoRandomU32 (&Xid); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + Mode = Private->PxeBc.Mode; + Dhcp4 = Private->Dhcp4; + Status = EFI_SUCCESS; +@@ -1471,7 +1477,6 @@ PxeBcDhcp4Discover ( + // + // Set fields of the token for the request packet. + // +- Xid = NET_RANDOM (NetRandomInitSeed ()); + Token.Packet->Dhcp4.Header.Xid = HTONL (Xid); + Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)((IsBCast) ? 0x8000 : 0x0)); + CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); +diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +index 7fd1281c11..bcabbd2219 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +@@ -2180,7 +2180,7 @@ PxeBcDhcp6Discover ( + UINTN ReadSize; + UINT16 OpCode; + UINT16 OpLen; +- UINT32 Xid; ++ UINT32 Random; + EFI_STATUS Status; + UINTN DiscoverLenNeeded; + +@@ -2198,6 +2198,12 @@ PxeBcDhcp6Discover ( + return EFI_DEVICE_ERROR; + } + ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ + DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); + Discover = AllocateZeroPool (DiscoverLenNeeded); + if (Discover == NULL) { +@@ -2207,8 +2213,7 @@ PxeBcDhcp6Discover ( + // + // Build the discover packet by the cached request packet before. + // +- Xid = NET_RANDOM (NetRandomInitSeed ()); +- Discover->TransactionId = HTONL (Xid); ++ Discover->TransactionId = HTONL (Random); + Discover->MessageType = Request->Dhcp6.Header.MessageType; + RequestOpt = Request->Dhcp6.Option; + DiscoverOpt = Discover->DhcpOptions; +diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c +index d84aca7e85..4cd915b411 100644 +--- a/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c ++++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c +@@ -3,6 +3,7 @@ + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
++ Copyright (c) Microsoft Corporation + + SPDX-License-Identifier: BSD-2-Clause-Patent + +@@ -892,6 +893,13 @@ PxeBcCreateIp6Children ( + PXEBC_PRIVATE_PROTOCOL *Id; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + UINTN Index; ++ UINT32 Random; ++ ++ Status = PseudoRandomU32 (&Random); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Failed to generate random number using EFI_RNG_PROTOCOL: %r\n", Status)); ++ return Status; ++ } + + if (Private->Ip6Nic != NULL) { + // +@@ -935,9 +943,9 @@ PxeBcCreateIp6Children ( + } + + // +- // Generate a random IAID for the Dhcp6 assigned address. ++ // Set a random IAID for the Dhcp6 assigned address. + // +- Private->IaId = NET_RANDOM (NetRandomInitSeed ()); ++ Private->IaId = Random; + if (Private->Snp != NULL) { + for (Index = 0; Index < Private->Snp->Mode->HwAddressSize; Index++) { + Private->IaId |= (Private->Snp->Mode->CurrentAddress.Addr[Index] << ((Index << 3) & 31)); +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 6ac72772d1..47ed2c7cd3 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -47,6 +47,8 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45229-0002.patch \ file://CVE-2023-45229-0003.patch \ file://CVE-2023-45229-0004.patch \ + file://CVE-2023-45237-0001.patch \ + file://CVE-2023-45237-0002.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46199 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB11BC41513 for ; Thu, 11 Jul 2024 04:56:28 +0000 (UTC) Received: from mx0b-0064b401.pphosted.com (mx0b-0064b401.pphosted.com [205.220.178.238]) by mx.groups.io with SMTP id smtpd.web10.4977.1720673781058523919 for ; Wed, 10 Jul 2024 21:56:21 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.178.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250812.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4rAxC016520 for ; Thu, 11 Jul 2024 04:56:20 GMT Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 406vw64gkn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Jul 2024 04:56:20 +0000 (GMT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:17 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 10/11] ovmf: Fix CVE-2023-45236 Date: Thu, 11 Jul 2024 04:55:40 +0000 Message-ID: <20240711045541.2155076-10-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-ORIG-GUID: 13rXVhPzDlknD2fl5fbuAAqsGpALW16F X-Proofpoint-GUID: 13rXVhPzDlknD2fl5fbuAAqsGpALW16F X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 spamscore=0 lowpriorityscore=0 bulkscore=0 priorityscore=1501 phishscore=0 malwarescore=0 clxscore=1015 adultscore=0 impostorscore=0 mlxlogscore=999 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:28 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201760 From: Soumya Sambu EDK2's Network Package is susceptible to a predictable TCP Initial Sequence Number. This vulnerability can be exploited by an attacker to gain unauthorized access and potentially lead to a loss of Confidentiality. References: https://nvd.nist.gov/vuln/detail/CVE-2023-45236 Upstream-patches: https://github.com/tianocore/edk2/commit/1904a64bcc18199738e5be183d28887ac5d837d7 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2023-45236.patch | 829 ++++++++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 1 + 2 files changed, 830 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2023-45236.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2023-45236.patch b/meta/recipes-core/ovmf/ovmf/CVE-2023-45236.patch new file mode 100644 index 0000000000..ac43392ce6 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2023-45236.patch @@ -0,0 +1,829 @@ +From 1904a64bcc18199738e5be183d28887ac5d837d7 Mon Sep 17 00:00:00 2001 +From: Doug Flick +Date: Wed, 8 May 2024 22:56:29 -0700 +Subject: [PATCH] NetworkPkg TcpDxe: SECURITY PATCH CVE-2023-45236 + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4541 +REF: https://www.rfc-editor.org/rfc/rfc1948.txt +REF: https://www.rfc-editor.org/rfc/rfc6528.txt +REF: https://www.rfc-editor.org/rfc/rfc9293.txt + +Bug Overview: +PixieFail Bug #8 +CVE-2023-45236 +CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N +CWE-200 Exposure of Sensitive Information to an Unauthorized Actor + +Updates TCP ISN generation to use a cryptographic hash of the +connection's identifying parameters and a secret key. +This prevents an attacker from guessing the ISN used for some other +connection. + +This is follows the guidance in RFC 1948, RFC 6528, and RFC 9293. + +RFC: 9293 Section 3.4.1. Initial Sequence Number Selection + + A TCP implementation MUST use the above type of "clock" for clock- + driven selection of initial sequence numbers (MUST-8), and SHOULD + generate its initial sequence numbers with the expression: + + ISN = M + F(localip, localport, remoteip, remoteport, secretkey) + + where M is the 4 microsecond timer, and F() is a pseudorandom + function (PRF) of the connection's identifying parameters ("localip, + localport, remoteip, remoteport") and a secret key ("secretkey") + (SHLD-1). F() MUST NOT be computable from the outside (MUST-9), or + an attacker could still guess at sequence numbers from the ISN used + for some other connection. The PRF could be implemented as a + cryptographic hash of the concatenation of the TCP connection + parameters and some secret data. For discussion of the selection of + a specific hash algorithm and management of the secret key data, + please see Section 3 of [42]. + + For each connection there is a send sequence number and a receive + sequence number. The initial send sequence number (ISS) is chosen by + the data sending TCP peer, and the initial receive sequence number + (IRS) is learned during the connection-establishing procedure. + + For a connection to be established or initialized, the two TCP peers + must synchronize on each other's initial sequence numbers. This is + done in an exchange of connection-establishing segments carrying a + control bit called "SYN" (for synchronize) and the initial sequence + numbers. As a shorthand, segments carrying the SYN bit are also + called "SYNs". Hence, the solution requires a suitable mechanism for + picking an initial sequence number and a slightly involved handshake + to exchange the ISNs. + +Cc: Saloni Kasbekar +Cc: Zachary Clark-williams + +Signed-off-by: Doug Flick [MSFT] +Reviewed-by: Saloni Kasbekar + +CVE: CVE-2023-45236 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1904a64bcc18199738e5be183d28887ac5d837d7] + +Signed-off-by: Soumya Sambu +--- + NetworkPkg/SecurityFixes.yaml | 22 +++ + NetworkPkg/TcpDxe/TcpDriver.c | 92 ++++++++++++- + NetworkPkg/TcpDxe/TcpDxe.inf | 8 +- + NetworkPkg/TcpDxe/TcpFunc.h | 23 ++-- + NetworkPkg/TcpDxe/TcpInput.c | 13 +- + NetworkPkg/TcpDxe/TcpMain.h | 59 ++++++-- + NetworkPkg/TcpDxe/TcpMisc.c | 244 ++++++++++++++++++++++++++++++++-- + NetworkPkg/TcpDxe/TcpTimer.c | 3 +- + 8 files changed, 415 insertions(+), 49 deletions(-) + +diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml +index 2b2c794697..ab355419cc 100644 +--- a/NetworkPkg/SecurityFixes.yaml ++++ b/NetworkPkg/SecurityFixes.yaml +@@ -121,6 +121,28 @@ CVE_2023_45235: + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html ++CVE_2023_45236: ++ commit_titles: ++ - "NetworkPkg: TcpDxe: SECURITY PATCH CVE-2023-45236 Patch" ++ cve: CVE-2023-45236 ++ date_reported: 2023-08-28 13:56 UTC ++ description: "Bug 08 - edk2/NetworkPkg: Predictable TCP Initial Sequence Numbers" ++ note: ++ files_impacted: ++ - NetworkPkg/Include/Library/NetLib.h ++ - NetworkPkg/TcpDxe/TcpDriver.c ++ - NetworkPkg/TcpDxe/TcpDxe.inf ++ - NetworkPkg/TcpDxe/TcpFunc.h ++ - NetworkPkg/TcpDxe/TcpInput.c ++ - NetworkPkg/TcpDxe/TcpMain.h ++ - NetworkPkg/TcpDxe/TcpMisc.c ++ - NetworkPkg/TcpDxe/TcpTimer.c ++ links: ++ - https://bugzilla.tianocore.org/show_bug.cgi?id=4541 ++ - https://nvd.nist.gov/vuln/detail/CVE-2023-45236 ++ - http://www.openwall.com/lists/oss-security/2024/01/16/2 ++ - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html ++ - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html + CVE_2023_45237: + commit_titles: + - "NetworkPkg:: SECURITY PATCH CVE 2023-45237" +diff --git a/NetworkPkg/TcpDxe/TcpDriver.c b/NetworkPkg/TcpDxe/TcpDriver.c +index 8fe6badd68..40bba4080c 100644 +--- a/NetworkPkg/TcpDxe/TcpDriver.c ++++ b/NetworkPkg/TcpDxe/TcpDriver.c +@@ -83,6 +83,12 @@ EFI_SERVICE_BINDING_PROTOCOL gTcpServiceBinding = { + TcpServiceBindingDestroyChild + }; + ++// ++// This is the handle for the Hash2ServiceBinding Protocol instance this driver produces ++// if the platform does not provide one. ++// ++EFI_HANDLE mHash2ServiceHandle = NULL; ++ + /** + Create and start the heartbeat timer for the TCP driver. + +@@ -165,6 +171,23 @@ TcpDriverEntryPoint ( + EFI_STATUS Status; + UINT32 Random; + ++ // ++ // Initialize the Secret used for hashing TCP sequence numbers ++ // ++ // Normally this should be regenerated periodically, but since ++ // this is only used for UEFI networking and not a general purpose ++ // operating system, it is not necessary to regenerate it. ++ // ++ Status = PseudoRandomU32 (&mTcpGlobalSecret); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); ++ return Status; ++ } ++ ++ // ++ // Get a random number used to generate a random port number ++ // Intentionally not linking this to mTcpGlobalSecret to avoid leaking information about the secret ++ // + Status = PseudoRandomU32 (&Random); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a Failed to generate random number: %r\n", __func__, Status)); +@@ -207,9 +230,8 @@ TcpDriverEntryPoint ( + } + + // +- // Initialize ISS and random port. ++ // Initialize the random port. + // +- mTcpGlobalIss = Random % mTcpGlobalIss; + mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (Random % TCP_PORT_KNOWN)); + mTcp6RandomPort = mTcp4RandomPort; + +@@ -224,6 +246,8 @@ TcpDriverEntryPoint ( + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources. ++ @retval EFI_UNSUPPORTED Service Binding Protocols are unavailable. ++ @retval EFI_ALREADY_STARTED The TCP driver is already started on the controller. + @retval EFI_SUCCESS A new IP6 service binding private was created. + + **/ +@@ -234,11 +258,13 @@ TcpCreateService ( + IN UINT8 IpVersion + ) + { +- EFI_STATUS Status; +- EFI_GUID *IpServiceBindingGuid; +- EFI_GUID *TcpServiceBindingGuid; +- TCP_SERVICE_DATA *TcpServiceData; +- IP_IO_OPEN_DATA OpenData; ++ EFI_STATUS Status; ++ EFI_GUID *IpServiceBindingGuid; ++ EFI_GUID *TcpServiceBindingGuid; ++ TCP_SERVICE_DATA *TcpServiceData; ++ IP_IO_OPEN_DATA OpenData; ++ EFI_SERVICE_BINDING_PROTOCOL *Hash2ServiceBinding; ++ EFI_HASH2_PROTOCOL *Hash2Protocol; + + if (IpVersion == IP_VERSION_4) { + IpServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid; +@@ -272,6 +298,33 @@ TcpCreateService ( + return EFI_UNSUPPORTED; + } + ++ Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol); ++ if (EFI_ERROR (Status)) { ++ // ++ // If we can't find the Hashing protocol, then we need to create one. ++ // ++ ++ // ++ // Platform is expected to publish the hash service binding protocol to support TCP. ++ // ++ Status = gBS->LocateProtocol ( ++ &gEfiHash2ServiceBindingProtocolGuid, ++ NULL, ++ (VOID **)&Hash2ServiceBinding ++ ); ++ if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->CreateChild == NULL)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // ++ // Create an instance of the hash protocol for this controller. ++ // ++ Status = Hash2ServiceBinding->CreateChild (Hash2ServiceBinding, &mHash2ServiceHandle); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } ++ } ++ + // + // Create the TCP service data. + // +@@ -423,6 +476,7 @@ TcpDestroyService ( + EFI_STATUS Status; + LIST_ENTRY *List; + TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; ++ EFI_SERVICE_BINDING_PROTOCOL *Hash2ServiceBinding; + + ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); + +@@ -439,6 +493,30 @@ TcpDestroyService ( + return EFI_SUCCESS; + } + ++ // ++ // Destroy the Hash2ServiceBinding instance if it is created by Tcp driver. ++ // ++ if (mHash2ServiceHandle != NULL) { ++ Status = gBS->LocateProtocol ( ++ &gEfiHash2ServiceBindingProtocolGuid, ++ NULL, ++ (VOID **)&Hash2ServiceBinding ++ ); ++ if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->DestroyChild == NULL)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // ++ // Destroy the instance of the hashing protocol for this controller. ++ // ++ Status = Hash2ServiceBinding->DestroyChild (Hash2ServiceBinding, &mHash2ServiceHandle); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ mHash2ServiceHandle = NULL; ++ } ++ + Status = gBS->OpenProtocol ( + NicHandle, + ServiceBindingGuid, +diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf +index cf5423f4c5..76de4cf9ec 100644 +--- a/NetworkPkg/TcpDxe/TcpDxe.inf ++++ b/NetworkPkg/TcpDxe/TcpDxe.inf +@@ -6,6 +6,7 @@ + # stack has been loaded in system. This driver supports both IPv4 and IPv6 network stack. + # + # Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
++# Copyright (c) Microsoft Corporation + # + # SPDX-License-Identifier: BSD-2-Clause-Patent + # +@@ -68,7 +69,6 @@ + NetLib + IpIoLib + +- + [Protocols] + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES +@@ -81,6 +81,12 @@ + gEfiIp6ServiceBindingProtocolGuid ## TO_START + gEfiTcp6ProtocolGuid ## BY_START + gEfiTcp6ServiceBindingProtocolGuid ## BY_START ++ gEfiHash2ProtocolGuid ## BY_START ++ gEfiHash2ServiceBindingProtocolGuid ## BY_START ++ ++[Guids] ++ gEfiHashAlgorithmMD5Guid ## CONSUMES ++ gEfiHashAlgorithmSha256Guid ## CONSUMES + + [Depex] + gEfiHash2ServiceBindingProtocolGuid +diff --git a/NetworkPkg/TcpDxe/TcpFunc.h b/NetworkPkg/TcpDxe/TcpFunc.h +index a7af01fff2..c707bee3e5 100644 +--- a/NetworkPkg/TcpDxe/TcpFunc.h ++++ b/NetworkPkg/TcpDxe/TcpFunc.h +@@ -2,7 +2,7 @@ + Declaration of external functions shared in TCP driver. + + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -36,8 +36,11 @@ VOID + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + ++ @retval EFI_SUCCESS The operation completed successfully ++ @retval others The underlying functions failed and could not complete the operation ++ + **/ +-VOID ++EFI_STATUS + TcpInitTcbLocal ( + IN OUT TCP_CB *Tcb + ); +@@ -128,17 +131,6 @@ TcpCloneTcb ( + IN TCP_CB *Tcb + ); + +-/** +- Compute an ISS to be used by a new connection. +- +- @return The result ISS. +- +-**/ +-TCP_SEQNO +-TcpGetIss ( +- VOID +- ); +- + /** + Get the local mss. + +@@ -202,8 +194,11 @@ TcpFormatNetbuf ( + @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a + connection. + ++ @retval EFI_SUCCESS The operation completed successfully ++ @retval others The underlying functions failed and could not complete the operation ++ + **/ +-VOID ++EFI_STATUS + TcpOnAppConnect ( + IN OUT TCP_CB *Tcb + ); +diff --git a/NetworkPkg/TcpDxe/TcpInput.c b/NetworkPkg/TcpDxe/TcpInput.c +index fb1aa827f8..0477a15d0c 100644 +--- a/NetworkPkg/TcpDxe/TcpInput.c ++++ b/NetworkPkg/TcpDxe/TcpInput.c +@@ -724,6 +724,7 @@ TcpInput ( + TCP_SEQNO Urg; + UINT16 Checksum; + INT32 Usable; ++ EFI_STATUS Status; + + ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6)); + +@@ -872,7 +873,17 @@ TcpInput ( + Tcb->LocalEnd.Port = Head->DstPort; + Tcb->RemoteEnd.Port = Head->SrcPort; + +- TcpInitTcbLocal (Tcb); ++ Status = TcpInitTcbLocal (Tcb); ++ if (EFI_ERROR (Status)) { ++ DEBUG ( ++ (DEBUG_ERROR, ++ "TcpInput: discard a segment because failed to init local end for TCB %p\n", ++ Tcb) ++ ); ++ ++ goto DISCARD; ++ } ++ + TcpInitTcbPeer (Tcb, Seg, &Option); + + TcpSetState (Tcb, TCP_SYN_RCVD); +diff --git a/NetworkPkg/TcpDxe/TcpMain.h b/NetworkPkg/TcpDxe/TcpMain.h +index c0c9b7f46e..4d5566ab93 100644 +--- a/NetworkPkg/TcpDxe/TcpMain.h ++++ b/NetworkPkg/TcpDxe/TcpMain.h +@@ -3,7 +3,7 @@ + It is the common head file for all Tcp*.c in TCP driver. + + Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -31,7 +32,7 @@ extern EFI_UNICODE_STRING_TABLE *gTcpControllerNameTable; + + extern LIST_ENTRY mTcpRunQue; + extern LIST_ENTRY mTcpListenQue; +-extern TCP_SEQNO mTcpGlobalIss; ++extern TCP_SEQNO mTcpGlobalSecret; + extern UINT32 mTcpTick; + + /// +@@ -45,14 +46,6 @@ extern UINT32 mTcpTick; + + #define TCP_EXPIRE_TIME 65535 + +-/// +-/// The implementation selects the initial send sequence number and the unit to +-/// be added when it is increased. +-/// +-#define TCP_BASE_ISS 0x4d7e980b +-#define TCP_ISS_INCREMENT_1 2048 +-#define TCP_ISS_INCREMENT_2 100 +- + typedef union { + EFI_TCP4_CONFIG_DATA Tcp4CfgData; + EFI_TCP6_CONFIG_DATA Tcp6CfgData; +@@ -774,4 +767,50 @@ Tcp6Poll ( + IN EFI_TCP6_PROTOCOL *This + ); + ++/** ++ Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local ++ and remote IP addresses and ports. ++ ++ This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1 ++ Where the ISN is computed as follows: ++ ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret) ++ ++ Otherwise: ++ ISN = M + F(localip, localport, remoteip, remoteport, secretkey) ++ ++ "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the ++ connection's identifying parameters ("localip, localport, remoteip, remoteport") ++ and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the ++ outside (MUST-9), or an attacker could still guess at sequence numbers from the ++ ISN used for some other connection. The PRF could be implemented as a ++ cryptographic hash of the concatenation of the TCP connection parameters and some ++ secret data. For discussion of the selection of a specific hash algorithm and ++ management of the secret key data." ++ ++ @param[in] LocalIp A pointer to the local IP address of the TCP connection. ++ @param[in] LocalIpSize The size, in bytes, of the LocalIp buffer. ++ @param[in] LocalPort The local port number of the TCP connection. ++ @param[in] RemoteIp A pointer to the remote IP address of the TCP connection. ++ @param[in] RemoteIpSize The size, in bytes, of the RemoteIp buffer. ++ @param[in] RemotePort The remote port number of the TCP connection. ++ @param[out] Isn A pointer to the variable that will receive the Initial ++ Sequence Number (ISN). ++ ++ @retval EFI_SUCCESS The operation completed successfully, and the ISN was ++ retrieved. ++ @retval EFI_INVALID_PARAMETER One or more of the input parameters are invalid. ++ @retval EFI_UNSUPPORTED The operation is not supported. ++ ++**/ ++EFI_STATUS ++TcpGetIsn ( ++ IN UINT8 *LocalIp, ++ IN UINTN LocalIpSize, ++ IN UINT16 LocalPort, ++ IN UINT8 *RemoteIp, ++ IN UINTN RemoteIpSize, ++ IN UINT16 RemotePort, ++ OUT TCP_SEQNO *Isn ++ ); ++ + #endif +diff --git a/NetworkPkg/TcpDxe/TcpMisc.c b/NetworkPkg/TcpDxe/TcpMisc.c +index c93212d47d..3310306f63 100644 +--- a/NetworkPkg/TcpDxe/TcpMisc.c ++++ b/NetworkPkg/TcpDxe/TcpMisc.c +@@ -3,7 +3,7 @@ + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -20,7 +20,34 @@ LIST_ENTRY mTcpListenQue = { + &mTcpListenQue + }; + +-TCP_SEQNO mTcpGlobalIss = TCP_BASE_ISS; ++// ++// The Session secret ++// This must be initialized to a random value at boot time ++// ++TCP_SEQNO mTcpGlobalSecret; ++ ++// ++// Union to hold either an IPv4 or IPv6 address ++// This is used to simplify the ISN hash computation ++// ++typedef union { ++ UINT8 IPv4[4]; ++ UINT8 IPv6[16]; ++} NETWORK_ADDRESS; ++ ++// ++// The ISN is computed by hashing this structure ++// It is initialized with the local and remote IP addresses and ports ++// and the secret ++// ++// ++typedef struct { ++ UINT16 LocalPort; ++ UINT16 RemotePort; ++ NETWORK_ADDRESS LocalAddress; ++ NETWORK_ADDRESS RemoteAddress; ++ TCP_SEQNO Secret; ++} ISN_HASH_CTX; + + CHAR16 *mTcpStateName[] = { + L"TCP_CLOSED", +@@ -41,12 +68,18 @@ CHAR16 *mTcpStateName[] = { + + @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + ++ @retval EFI_SUCCESS The operation completed successfully ++ @retval others The underlying functions failed and could not complete the operation ++ + **/ +-VOID ++EFI_STATUS + TcpInitTcbLocal ( + IN OUT TCP_CB *Tcb + ) + { ++ TCP_SEQNO Isn; ++ EFI_STATUS Status; ++ + // + // Compute the checksum of the fixed parts of pseudo header + // +@@ -57,6 +90,16 @@ TcpInitTcbLocal ( + 0x06, + 0 + ); ++ ++ Status = TcpGetIsn ( ++ Tcb->LocalEnd.Ip.v4.Addr, ++ sizeof (IPv4_ADDRESS), ++ Tcb->LocalEnd.Port, ++ Tcb->RemoteEnd.Ip.v4.Addr, ++ sizeof (IPv4_ADDRESS), ++ Tcb->RemoteEnd.Port, ++ &Isn ++ ); + } else { + Tcb->HeadSum = NetIp6PseudoHeadChecksum ( + &Tcb->LocalEnd.Ip.v6, +@@ -64,9 +107,25 @@ TcpInitTcbLocal ( + 0x06, + 0 + ); ++ ++ Status = TcpGetIsn ( ++ Tcb->LocalEnd.Ip.v6.Addr, ++ sizeof (IPv6_ADDRESS), ++ Tcb->LocalEnd.Port, ++ Tcb->RemoteEnd.Ip.v6.Addr, ++ sizeof (IPv6_ADDRESS), ++ Tcb->RemoteEnd.Port, ++ &Isn ++ ); ++ } ++ ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "TcpInitTcbLocal: failed to get isn\n")); ++ ASSERT (FALSE); ++ return Status; + } + +- Tcb->Iss = TcpGetIss (); ++ Tcb->Iss = Isn; + Tcb->SndUna = Tcb->Iss; + Tcb->SndNxt = Tcb->Iss; + +@@ -82,6 +141,8 @@ TcpInitTcbLocal ( + Tcb->RetxmitSeqMax = 0; + + Tcb->ProbeTimerOn = FALSE; ++ ++ return EFI_SUCCESS; + } + + /** +@@ -506,18 +567,162 @@ TcpCloneTcb ( + } + + /** +- Compute an ISS to be used by a new connection. +- +- @return The resulting ISS. ++ Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local ++ and remote IP addresses and ports. ++ ++ This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1 ++ Where the ISN is computed as follows: ++ ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret) ++ ++ Otherwise: ++ ISN = M + F(localip, localport, remoteip, remoteport, secretkey) ++ ++ "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the ++ connection's identifying parameters ("localip, localport, remoteip, remoteport") ++ and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the ++ outside (MUST-9), or an attacker could still guess at sequence numbers from the ++ ISN used for some other connection. The PRF could be implemented as a ++ cryptographic hash of the concatenation of the TCP connection parameters and some ++ secret data. For discussion of the selection of a specific hash algorithm and ++ management of the secret key data." ++ ++ @param[in] LocalIp A pointer to the local IP address of the TCP connection. ++ @param[in] LocalIpSize The size, in bytes, of the LocalIp buffer. ++ @param[in] LocalPort The local port number of the TCP connection. ++ @param[in] RemoteIp A pointer to the remote IP address of the TCP connection. ++ @param[in] RemoteIpSize The size, in bytes, of the RemoteIp buffer. ++ @param[in] RemotePort The remote port number of the TCP connection. ++ @param[out] Isn A pointer to the variable that will receive the Initial ++ Sequence Number (ISN). ++ ++ @retval EFI_SUCCESS The operation completed successfully, and the ISN was ++ retrieved. ++ @retval EFI_INVALID_PARAMETER One or more of the input parameters are invalid. ++ @retval EFI_UNSUPPORTED The operation is not supported. + + **/ +-TCP_SEQNO +-TcpGetIss ( +- VOID ++EFI_STATUS ++TcpGetIsn ( ++ IN UINT8 *LocalIp, ++ IN UINTN LocalIpSize, ++ IN UINT16 LocalPort, ++ IN UINT8 *RemoteIp, ++ IN UINTN RemoteIpSize, ++ IN UINT16 RemotePort, ++ OUT TCP_SEQNO *Isn + ) + { +- mTcpGlobalIss += TCP_ISS_INCREMENT_1; +- return mTcpGlobalIss; ++ EFI_STATUS Status; ++ EFI_HASH2_PROTOCOL *Hash2Protocol; ++ EFI_HASH2_OUTPUT HashResult; ++ ISN_HASH_CTX IsnHashCtx; ++ EFI_TIME TimeStamp; ++ ++ // ++ // Check that the ISN pointer is valid ++ // ++ if (Isn == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // The local ip may be a v4 or v6 address and may not be NULL ++ // ++ if ((LocalIp == NULL) || (LocalIpSize == 0) || (RemoteIp == NULL) || (RemoteIpSize == 0)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // the local ip may be a v4 or v6 address ++ // ++ if ((LocalIpSize != sizeof (EFI_IPv4_ADDRESS)) && (LocalIpSize != sizeof (EFI_IPv6_ADDRESS))) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Locate the Hash Protocol ++ // ++ Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_NET, "Failed to locate Hash Protocol: %r\n", Status)); ++ ++ // ++ // TcpCreateService(..) is expected to be called prior to this function ++ // ++ ASSERT_EFI_ERROR (Status); ++ return Status; ++ } ++ ++ // ++ // Initialize the hash algorithm ++ // ++ Status = Hash2Protocol->HashInit (Hash2Protocol, &gEfiHashAlgorithmSha256Guid); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_NET, "Failed to initialize sha256 hash algorithm: %r\n", Status)); ++ return Status; ++ } ++ ++ IsnHashCtx.LocalPort = LocalPort; ++ IsnHashCtx.RemotePort = RemotePort; ++ IsnHashCtx.Secret = mTcpGlobalSecret; ++ ++ // ++ // Check the IP address family and copy accordingly ++ // ++ if (LocalIpSize == sizeof (EFI_IPv4_ADDRESS)) { ++ CopyMem (&IsnHashCtx.LocalAddress.IPv4, LocalIp, LocalIpSize); ++ } else if (LocalIpSize == sizeof (EFI_IPv6_ADDRESS)) { ++ CopyMem (&IsnHashCtx.LocalAddress.IPv6, LocalIp, LocalIpSize); ++ } else { ++ return EFI_INVALID_PARAMETER; // Unsupported address size ++ } ++ ++ // ++ // Repeat the process for the remote IP address ++ // ++ if (RemoteIpSize == sizeof (EFI_IPv4_ADDRESS)) { ++ CopyMem (&IsnHashCtx.RemoteAddress.IPv4, RemoteIp, RemoteIpSize); ++ } else if (RemoteIpSize == sizeof (EFI_IPv6_ADDRESS)) { ++ CopyMem (&IsnHashCtx.RemoteAddress.IPv6, RemoteIp, RemoteIpSize); ++ } else { ++ return EFI_INVALID_PARAMETER; // Unsupported address size ++ } ++ ++ // ++ // Compute the hash ++ // Update the hash with the data ++ // ++ Status = Hash2Protocol->HashUpdate (Hash2Protocol, (UINT8 *)&IsnHashCtx, sizeof (IsnHashCtx)); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_NET, "Failed to update hash: %r\n", Status)); ++ return Status; ++ } ++ ++ // ++ // Finalize the hash and retrieve the result ++ // ++ Status = Hash2Protocol->HashFinal (Hash2Protocol, &HashResult); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_NET, "Failed to finalize hash: %r\n", Status)); ++ return Status; ++ } ++ ++ Status = gRT->GetTime (&TimeStamp, NULL); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // ++ // copy the first 4 bytes of the hash result into the ISN ++ // ++ CopyMem (Isn, HashResult.Md5Hash, sizeof (*Isn)); ++ ++ // ++ // now add the timestamp to the ISN as 4 microseconds units (1000 / 4 = 250) ++ // ++ *Isn += (TCP_SEQNO)TimeStamp.Nanosecond * 250; ++ ++ return Status; + } + + /** +@@ -721,17 +926,28 @@ TcpFormatNetbuf ( + @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a + connection. + ++ @retval EFI_SUCCESS The operation completed successfully ++ @retval others The underlying functions failed and could not complete the operation ++ + **/ +-VOID ++EFI_STATUS + TcpOnAppConnect ( + IN OUT TCP_CB *Tcb + ) + { +- TcpInitTcbLocal (Tcb); ++ EFI_STATUS Status; ++ ++ Status = TcpInitTcbLocal (Tcb); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ + TcpSetState (Tcb, TCP_SYN_SENT); + + TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout); + TcpToSendData (Tcb, 1); ++ ++ return EFI_SUCCESS; + } + + /** +diff --git a/NetworkPkg/TcpDxe/TcpTimer.c b/NetworkPkg/TcpDxe/TcpTimer.c +index 5d2e124977..065b1bdf5f 100644 +--- a/NetworkPkg/TcpDxe/TcpTimer.c ++++ b/NetworkPkg/TcpDxe/TcpTimer.c +@@ -2,7 +2,7 @@ + TCP timer related functions. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+- ++ Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +@@ -483,7 +483,6 @@ TcpTickingDpc ( + INT16 Index; + + mTcpTick++; +- mTcpGlobalIss += TCP_ISS_INCREMENT_2; + + // + // Don't use LIST_FOR_EACH, which isn't delete safe. +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index 47ed2c7cd3..dbfed086e4 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -49,6 +49,7 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45229-0004.patch \ file://CVE-2023-45237-0001.patch \ file://CVE-2023-45237-0002.patch \ + file://CVE-2023-45236.patch \ " PV = "edk2-stable202202" From patchwork Thu Jul 11 04:55:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ssambu X-Patchwork-Id: 46198 X-Patchwork-Delegate: steve@sakoman.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB0EBC3271E for ; Thu, 11 Jul 2024 04:56:28 +0000 (UTC) Received: from mx0a-0064b401.pphosted.com (mx0a-0064b401.pphosted.com [205.220.166.238]) by mx.groups.io with SMTP id smtpd.web11.4948.1720673781624517688 for ; Wed, 10 Jul 2024 21:56:21 -0700 Authentication-Results: mx.groups.io; dkim=none (message not signed); spf=permerror, err=parse error for token &{10 18 %{ir}.%{v}.%{d}.spf.has.pphosted.com}: invalid domain name (domain: windriver.com, ip: 205.220.166.238, mailfrom: prvs=79227d51f5=soumya.sambu@windriver.com) Received: from pps.filterd (m0250810.ppops.net [127.0.0.1]) by mx0a-0064b401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 46B4j20J016647 for ; Wed, 10 Jul 2024 21:56:21 -0700 Received: from ala-exchng01.corp.ad.wrs.com (ala-exchng01.wrs.com [147.11.82.252]) by mx0a-0064b401.pphosted.com (PPS) with ESMTPS id 407170mcjv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 10 Jul 2024 21:56:21 -0700 (PDT) Received: from blr-linux-engg1.wrs.com (147.11.136.210) by ala-exchng01.corp.ad.wrs.com (147.11.82.252) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Wed, 10 Jul 2024 21:56:19 -0700 From: ssambu To: Subject: [OE-core][kirkstone][PATCH 11/11] ovmf: Fix CVE-2022-36765 Date: Thu, 11 Jul 2024 04:55:41 +0000 Message-ID: <20240711045541.2155076-11-soumya.sambu@windriver.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20240711045541.2155076-1-soumya.sambu@windriver.com> References: <20240711045541.2155076-1-soumya.sambu@windriver.com> MIME-Version: 1.0 X-Originating-IP: [147.11.136.210] X-ClientProxiedBy: ALA-EXCHNG02.corp.ad.wrs.com (147.11.82.254) To ala-exchng01.corp.ad.wrs.com (147.11.82.252) X-Proofpoint-GUID: A0tqwPJKsAKPkdBqa613LhpjihCqpA0E X-Proofpoint-ORIG-GUID: A0tqwPJKsAKPkdBqa613LhpjihCqpA0E X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.28.16 definitions=2024-07-11_01,2024-07-10_01,2024-05-17_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 impostorscore=0 malwarescore=0 phishscore=0 adultscore=0 lowpriorityscore=0 spamscore=0 suspectscore=0 bulkscore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.21.0-2406140001 definitions=main-2407110031 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 11 Jul 2024 04:56:28 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/201761 From: Soumya Sambu EDK2 is susceptible to a vulnerability in the CreateHob() function, allowing a user to trigger a integer overflow to buffer overflow via a local network. Successful exploitation of this vulnerability may result in a compromise of confidentiality, integrity, and/or availability. References: https://nvd.nist.gov/vuln/detail/CVE-2022-36765 Upstream-patches: https://github.com/tianocore/edk2/commit/59f024c76ee57c2bec84794536302fc770cd6ec2 https://github.com/tianocore/edk2/commit/aeaee8944f0eaacbf4cdf39279785b9ba4836bb6 https://github.com/tianocore/edk2/commit/9a75b030cf27d2530444e9a2f9f11867f79bf679 Signed-off-by: Soumya Sambu --- .../ovmf/ovmf/CVE-2022-36765-0001.patch | 179 ++++++++++++++++++ .../ovmf/ovmf/CVE-2022-36765-0002.patch | 157 +++++++++++++++ .../ovmf/ovmf/CVE-2022-36765-0003.patch | 135 +++++++++++++ meta/recipes-core/ovmf/ovmf_git.bb | 3 + 4 files changed, 474 insertions(+) create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0001.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0002.patch create mode 100644 meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0003.patch diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0001.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0001.patch new file mode 100644 index 0000000000..120cf66f6a --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0001.patch @@ -0,0 +1,179 @@ +From 59f024c76ee57c2bec84794536302fc770cd6ec2 Mon Sep 17 00:00:00 2001 +From: Gua Guo +Date: Thu, 11 Jan 2024 13:01:19 +0800 +Subject: [PATCH] UefiPayloadPkg/Hob: Integer Overflow in CreateHob() + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4166 + +Fix integer overflow in various CreateHob instances. +Fixes: CVE-2022-36765 + +The CreateHob() function aligns the requested size to 8 +performing the following operation: +``` +HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); +``` + +No checks are performed to ensure this value doesn't +overflow, and could lead to CreateHob() returning a smaller +HOB than requested, which could lead to OOB HOB accesses. + +Reported-by: Marc Beatove +Cc: Guo Dong +Cc: Sean Rhodes +Cc: James Lu +Reviewed-by: Gua Guo +Cc: John Mathew +Authored-by: Gerd Hoffmann +Signed-off-by: Gua Guo + +CVE: CVE-2022-36765 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/59f024c76ee57c2bec84794536302fc770cd6ec2] + +Signed-off-by: Soumya Sambu +--- + .../Library/PayloadEntryHobLib/Hob.c | 43 +++++++++++++++++++ + .../UefiPayloadEntry/UniversalPayloadEntry.c | 8 ++-- + 2 files changed, 48 insertions(+), 3 deletions(-) + +diff --git a/UefiPayloadPkg/Library/PayloadEntryHobLib/Hob.c b/UefiPayloadPkg/Library/PayloadEntryHobLib/Hob.c +index 2c3acbbc19..51c2e28d7d 100644 +--- a/UefiPayloadPkg/Library/PayloadEntryHobLib/Hob.c ++++ b/UefiPayloadPkg/Library/PayloadEntryHobLib/Hob.c +@@ -110,6 +110,13 @@ CreateHob ( + + HandOffHob = GetHobList (); + ++ // ++ // Check Length to avoid data overflow. ++ // ++ if (HobLength > MAX_UINT16 - 0x7) { ++ return NULL; ++ } ++ + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; +@@ -160,6 +167,9 @@ BuildResourceDescriptorHob ( + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; +@@ -330,6 +340,10 @@ BuildModuleHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; +@@ -378,6 +392,11 @@ BuildGuidHob ( + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + DataLength)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return NULL; ++ } ++ + CopyGuid (&Hob->Name, Guid); + return Hob + 1; + } +@@ -441,6 +460,10 @@ BuildFvHob ( + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -472,6 +495,10 @@ BuildFv2Hob ( + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -513,6 +540,10 @@ BuildFv3Hob ( + EFI_HOB_FIRMWARE_VOLUME3 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV3, sizeof (EFI_HOB_FIRMWARE_VOLUME3)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -546,6 +577,10 @@ BuildCpuHob ( + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; +@@ -583,6 +618,10 @@ BuildStackHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; +@@ -664,6 +703,10 @@ BuildMemoryAllocationHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; +diff --git a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c +index edb3c20471..abfe75bd7b 100644 +--- a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c ++++ b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c +@@ -111,10 +111,12 @@ AddNewHob ( + } + + NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength); +- +- if (NewHob.Header != NULL) { +- CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER)); ++ ASSERT (NewHob.Header != NULL); ++ if (NewHob.Header == NULL) { ++ return; + } ++ ++ CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER)); + } + + /** +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0002.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0002.patch new file mode 100644 index 0000000000..1209be27b5 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0002.patch @@ -0,0 +1,157 @@ +From aeaee8944f0eaacbf4cdf39279785b9ba4836bb6 Mon Sep 17 00:00:00 2001 +From: Gua Guo +Date: Thu, 11 Jan 2024 13:07:50 +0800 +Subject: [PATCH] EmbeddedPkg/Hob: Integer Overflow in CreateHob() + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4166 + +Fix integer overflow in various CreateHob instances. +Fixes: CVE-2022-36765 + +The CreateHob() function aligns the requested size to 8 +performing the following operation: +``` +HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); +``` + +No checks are performed to ensure this value doesn't +overflow, and could lead to CreateHob() returning a smaller +HOB than requested, which could lead to OOB HOB accesses. + +Reported-by: Marc Beatove +Cc: Leif Lindholm +Reviewed-by: Ard Biesheuvel +Cc: Abner Chang +Cc: John Mathew +Authored-by: Gerd Hoffmann +Signed-off-by: Gua Guo + +CVE: CVE-2022-36765 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/aeaee8944f0eaacbf4cdf39279785b9ba4836bb6] + +Signed-off-by: Soumya Sambu +--- + EmbeddedPkg/Library/PrePiHobLib/Hob.c | 43 +++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/EmbeddedPkg/Library/PrePiHobLib/Hob.c b/EmbeddedPkg/Library/PrePiHobLib/Hob.c +index 8eb175aa96..cbc35152cc 100644 +--- a/EmbeddedPkg/Library/PrePiHobLib/Hob.c ++++ b/EmbeddedPkg/Library/PrePiHobLib/Hob.c +@@ -110,6 +110,13 @@ CreateHob ( + + HandOffHob = GetHobList (); + ++ // ++ // Check Length to avoid data overflow. ++ // ++ if (HobLength > MAX_UINT16 - 0x7) { ++ return NULL; ++ } ++ + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; +@@ -160,6 +167,9 @@ BuildResourceDescriptorHob ( + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; +@@ -401,6 +411,10 @@ BuildModuleHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; +@@ -449,6 +463,11 @@ BuildGuidHob ( + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + DataLength)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return NULL; ++ } ++ + CopyGuid (&Hob->Name, Guid); + return Hob + 1; + } +@@ -512,6 +531,10 @@ BuildFvHob ( + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -543,6 +566,10 @@ BuildFv2Hob ( + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -584,6 +611,10 @@ BuildFv3Hob ( + EFI_HOB_FIRMWARE_VOLUME3 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV3, sizeof (EFI_HOB_FIRMWARE_VOLUME3)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -639,6 +670,10 @@ BuildCpuHob ( + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; +@@ -676,6 +711,10 @@ BuildStackHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; +@@ -756,6 +795,10 @@ BuildMemoryAllocationHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0003.patch b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0003.patch new file mode 100644 index 0000000000..9579205e09 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2022-36765-0003.patch @@ -0,0 +1,135 @@ +From 9a75b030cf27d2530444e9a2f9f11867f79bf679 Mon Sep 17 00:00:00 2001 +From: Gua Guo +Date: Thu, 11 Jan 2024 13:03:26 +0800 +Subject: [PATCH] StandaloneMmPkg/Hob: Integer Overflow in CreateHob() + +REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4166 + +Fix integer overflow in various CreateHob instances. +Fixes: CVE-2022-36765 + +The CreateHob() function aligns the requested size to 8 +performing the following operation: +``` +HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); +``` + +No checks are performed to ensure this value doesn't +overflow, and could lead to CreateHob() returning a smaller +HOB than requested, which could lead to OOB HOB accesses. + +Reported-by: Marc Beatove +Reviewed-by: Ard Biesheuvel +Cc: Sami Mujawar +Reviewed-by: Ray Ni +Cc: John Mathew +Authored-by: Gerd Hoffmann +Signed-off-by: Gua Guo + +CVE: CVE-2022-36765 + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/9a75b030cf27d2530444e9a2f9f11867f79bf679] + +Signed-off-by: Soumya Sambu +--- + .../Arm/StandaloneMmCoreHobLib.c | 35 +++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Arm/StandaloneMmCoreHobLib.c b/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Arm/StandaloneMmCoreHobLib.c +index 1550e1babc..59473e28fe 100644 +--- a/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Arm/StandaloneMmCoreHobLib.c ++++ b/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Arm/StandaloneMmCoreHobLib.c +@@ -34,6 +34,13 @@ CreateHob ( + + HandOffHob = GetHobList (); + ++ // ++ // Check Length to avoid data overflow. ++ // ++ if (HobLength > MAX_UINT16 - 0x7) { ++ return NULL; ++ } ++ + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; +@@ -89,6 +96,10 @@ BuildModuleHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; +@@ -129,6 +140,9 @@ BuildResourceDescriptorHob ( + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; +@@ -167,6 +181,11 @@ BuildGuidHob ( + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + DataLength)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return NULL; ++ } ++ + CopyGuid (&Hob->Name, Guid); + return Hob + 1; + } +@@ -226,6 +245,10 @@ BuildFvHob ( + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -255,6 +278,10 @@ BuildFv2Hob ( + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +@@ -282,6 +309,10 @@ BuildCpuHob ( + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; +@@ -319,6 +350,10 @@ BuildMemoryAllocationHob ( + ); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); ++ ASSERT (Hob != NULL); ++ if (Hob == NULL) { ++ return; ++ } + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; +-- +2.40.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index dbfed086e4..1dba709824 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -50,6 +50,9 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://CVE-2023-45237-0001.patch \ file://CVE-2023-45237-0002.patch \ file://CVE-2023-45236.patch \ + file://CVE-2022-36765-0001.patch \ + file://CVE-2022-36765-0002.patch \ + file://CVE-2022-36765-0003.patch \ " PV = "edk2-stable202202"