diff --git a/meta/recipes-core/ovmf/ovmf/0001-AmdSev-Halt-on-failed-blob-allocation.patch b/meta/recipes-core/ovmf/ovmf/0001-AmdSev-Halt-on-failed-blob-allocation.patch new file mode 100644 index 0000000000..181ff3376a --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/0001-AmdSev-Halt-on-failed-blob-allocation.patch @@ -0,0 +1,159 @@ +From dbec8dc5ba6341d816ffd495fcd7eeece1716bb4 Mon Sep 17 00:00:00 2001 +From: Tobin Feldman-Fitzthum +Date: Mon, 29 Apr 2024 20:07:19 +0000 +Subject: [PATCH] AmdSev: Halt on failed blob allocation + +A malicious host may be able to undermine the fw_cfg +interface such that loading a blob fails. + +In this case rather than continuing to the next boot +option, the blob verifier should halt. + +For non-confidential guests, the error should be non-fatal. + +Signed-off-by: Tobin Feldman-Fitzthum + +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/10b4bb8d6d0c515ed9663691aea3684be8f7b0fc] +Signed-off-by: Hongxu Jia +--- + .../BlobVerifierSevHashes.c | 17 ++++++++++++++++- + OvmfPkg/Include/Library/BlobVerifierLib.h | 11 +++++++---- + .../BlobVerifierLibNull/BlobVerifierNull.c | 13 ++++++++----- + .../QemuKernelLoaderFsDxe.c | 9 ++++----- + 4 files changed, 35 insertions(+), 15 deletions(-) + +diff --git a/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c b/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c +index 2e58794c3c..6477c5c3d3 100644 +--- a/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c ++++ b/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c +@@ -80,6 +80,7 @@ FindBlobEntryGuid ( + @param[in] BlobName The name of the blob + @param[in] Buf The data of the blob + @param[in] BufSize The size of the blob in bytes ++ @param[in] FetchStatus The status of the previous blob fetch + + @retval EFI_SUCCESS The blob was verified successfully. + @retval EFI_ACCESS_DENIED The blob could not be verified, and therefore +@@ -90,13 +91,27 @@ EFIAPI + VerifyBlob ( + IN CONST CHAR16 *BlobName, + IN CONST VOID *Buf, +- IN UINT32 BufSize ++ IN UINT32 BufSize, ++ IN EFI_STATUS FetchStatus + ) + { + CONST GUID *Guid; + INT32 Remaining; + HASH_TABLE *Entry; + ++ // Enter a dead loop if the fetching of this blob ++ // failed. This prevents a malicious host from ++ // circumventing the following checks. ++ if (EFI_ERROR (FetchStatus)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "%a: Fetching blob failed.\n", ++ __func__ ++ )); ++ ++ CpuDeadLoop (); ++ } ++ + if ((mHashesTable == NULL) || (mHashesTableSize == 0)) { + DEBUG (( + DEBUG_ERROR, +diff --git a/OvmfPkg/Include/Library/BlobVerifierLib.h b/OvmfPkg/Include/Library/BlobVerifierLib.h +index 7e1af27574..09af1b77de 100644 +--- a/OvmfPkg/Include/Library/BlobVerifierLib.h ++++ b/OvmfPkg/Include/Library/BlobVerifierLib.h +@@ -22,17 +22,20 @@ + @param[in] BlobName The name of the blob + @param[in] Buf The data of the blob + @param[in] BufSize The size of the blob in bytes ++ @param[in] FetchStatus The status of fetching this blob + +- @retval EFI_SUCCESS The blob was verified successfully. +- @retval EFI_ACCESS_DENIED The blob could not be verified, and therefore +- should be considered non-secure. ++ @retval EFI_SUCCESS The blob was verified successfully or was not ++ found in the hash table. ++ @retval EFI_ACCESS_DENIED Kernel hashes not supported but the boot can ++ continue safely. + **/ + EFI_STATUS + EFIAPI + VerifyBlob ( + IN CONST CHAR16 *BlobName, + IN CONST VOID *Buf, +- IN UINT32 BufSize ++ IN UINT32 BufSize, ++ IN EFI_STATUS FetchStatus + ); + + #endif +diff --git a/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c b/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c +index e817c3cc95..db5320571c 100644 +--- a/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c ++++ b/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c +@@ -16,18 +16,21 @@ + @param[in] BlobName The name of the blob + @param[in] Buf The data of the blob + @param[in] BufSize The size of the blob in bytes ++ @param[in] FetchStatus The status of the fetch of this blob + +- @retval EFI_SUCCESS The blob was verified successfully. +- @retval EFI_ACCESS_DENIED The blob could not be verified, and therefore +- should be considered non-secure. ++ @retval EFI_SUCCESS The blob was verified successfully or was not ++ found in the hash table. ++ @retval EFI_ACCESS_DENIED Kernel hashes not supported but the boot can ++ continue safely. + **/ + EFI_STATUS + EFIAPI + VerifyBlob ( + IN CONST CHAR16 *BlobName, + IN CONST VOID *Buf, +- IN UINT32 BufSize ++ IN UINT32 BufSize, ++ IN EFI_STATUS FetchStatus + ) + { +- return EFI_SUCCESS; ++ return FetchStatus; + } +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 3c12085f6c..cf58c97cd2 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -1042,6 +1042,7 @@ QemuKernelLoaderFsDxeEntrypoint ( + KERNEL_BLOB *CurrentBlob; + KERNEL_BLOB *KernelBlob; + EFI_STATUS Status; ++ EFI_STATUS FetchStatus; + EFI_HANDLE FileSystemHandle; + EFI_HANDLE InitrdLoadFile2Handle; + +@@ -1060,15 +1061,13 @@ QemuKernelLoaderFsDxeEntrypoint ( + // + for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) { + CurrentBlob = &mKernelBlob[BlobType]; +- Status = FetchBlob (CurrentBlob); +- if (EFI_ERROR (Status)) { +- goto FreeBlobs; +- } ++ FetchStatus = FetchBlob (CurrentBlob); + + Status = VerifyBlob ( + CurrentBlob->Name, + CurrentBlob->Data, +- CurrentBlob->Size ++ CurrentBlob->Size, ++ FetchStatus + ); + if (EFI_ERROR (Status)) { + goto FreeBlobs; +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-1.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-1.patch new file mode 100644 index 0000000000..5cdbb12f19 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-1.patch @@ -0,0 +1,762 @@ +From 459f5ffa24ae8574657c4105af0ff7dc30ac428d Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 14 Jan 2025 17:36:39 +0100 +Subject: [PATCH 01/10] OvmfPkg/QemuKernelLoaderFsDxe: rework direct kernel + boot filesystem + +Split KERNEL_BLOB struct into two: + + * One (KERNEL_BLOB_ITEMS) static array describing how to load (unnamed) + blobs from fw_cfg. + * And one (KERNEL_BLOB) dynamically allocated linked list carrying the + data blobs for the pseudo filesystem. + +Also add some debug logging. Prefix most functions with 'QemuKernel' +for consistency and easier log file grepping. Add some small helper +functions. + +This refactoring prepares for loading blobs in other ways. +No (intentional) change in filesystem protocol behavior. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/459f5ffa24ae8574657c4105af0ff7dc30ac428d] +Signed-off-by: Hongxu Jia +--- + .../QemuKernelLoaderFsDxe.c | 345 +++++++++++------- + 1 file changed, 205 insertions(+), 140 deletions(-) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index cf58c97cd2..7ad1b3828f 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -31,13 +31,6 @@ + // + // Static data that hosts the fw_cfg blobs and serves file requests. + // +-typedef enum { +- KernelBlobTypeKernel, +- KernelBlobTypeInitrd, +- KernelBlobTypeCommandLine, +- KernelBlobTypeMax +-} KERNEL_BLOB_TYPE; +- + typedef struct { + CONST CHAR16 Name[8]; + struct { +@@ -45,11 +38,17 @@ typedef struct { + FIRMWARE_CONFIG_ITEM CONST DataKey; + UINT32 Size; + } FwCfgItem[2]; +- UINT32 Size; +- UINT8 *Data; +-} KERNEL_BLOB; ++} KERNEL_BLOB_ITEMS; ++ ++typedef struct KERNEL_BLOB KERNEL_BLOB; ++struct KERNEL_BLOB { ++ CHAR16 Name[8]; ++ UINT32 Size; ++ UINT8 *Data; ++ KERNEL_BLOB *Next; ++}; + +-STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = { ++STATIC KERNEL_BLOB_ITEMS mKernelBlobItems[] = { + { + L"kernel", + { +@@ -69,7 +68,9 @@ STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = { + } + }; + +-STATIC UINT64 mTotalBlobBytes; ++STATIC KERNEL_BLOB *mKernelBlobs; ++STATIC UINT64 mKernelBlobCount; ++STATIC UINT64 mTotalBlobBytes; + + // + // Device path for the handle that incorporates our "EFI stub filesystem". +@@ -117,7 +118,7 @@ STATIC EFI_TIME mInitTime; + typedef struct { + UINT64 Signature; // Carries STUB_FILE_SIG. + +- KERNEL_BLOB_TYPE BlobType; // Index into mKernelBlob. KernelBlobTypeMax ++ KERNEL_BLOB *Blob; // Index into mKernelBlob. KernelBlobTypeMax + // denotes the root directory of the filesystem. + + UINT64 Position; // Byte position for regular files; +@@ -177,7 +178,7 @@ typedef struct { + STATIC + EFI_STATUS + EFIAPI +-StubFileOpen ( ++QemuKernelStubFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, +@@ -196,7 +197,7 @@ StubFileOpen ( + STATIC + EFI_STATUS + EFIAPI +-StubFileClose ( ++QemuKernelStubFileClose ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -219,7 +220,7 @@ StubFileClose ( + STATIC + EFI_STATUS + EFIAPI +-StubFileDelete ( ++QemuKernelStubFileDelete ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -229,18 +230,17 @@ StubFileDelete ( + + /** + Helper function that formats an EFI_FILE_INFO structure into the +- user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including +- KernelBlobTypeMax, which stands for the root directory). ++ user-allocated buffer, for any valid KERNEL_BLOB (including NULL, ++ which stands for the root directory). + + The interface follows the EFI_FILE_GET_INFO -- and for directories, the + EFI_FILE_READ -- interfaces. + +- @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg ++ @param[in] Blob The KERNEL_BLOB identifying the fw_cfg + blob backing the STUB_FILE that information is +- being requested about. If BlobType equals +- KernelBlobTypeMax, then information will be +- provided about the root directory of the +- filesystem. ++ being requested about. If Blob is NULL, ++ then information will be provided about the root ++ directory of the filesystem. + + @param[in,out] BufferSize On input, the size of Buffer. On output, the + amount of data returned in Buffer. In both cases, +@@ -257,10 +257,10 @@ StubFileDelete ( + **/ + STATIC + EFI_STATUS +-ConvertKernelBlobTypeToFileInfo ( +- IN KERNEL_BLOB_TYPE BlobType, +- IN OUT UINTN *BufferSize, +- OUT VOID *Buffer ++QemuKernelBlobTypeToFileInfo ( ++ IN KERNEL_BLOB *Blob, ++ IN OUT UINTN *BufferSize, ++ OUT VOID *Buffer + ) + { + CONST CHAR16 *Name; +@@ -272,17 +272,16 @@ ConvertKernelBlobTypeToFileInfo ( + EFI_FILE_INFO *FileInfo; + UINTN OriginalBufferSize; + +- if (BlobType == KernelBlobTypeMax) { ++ if (Blob == NULL) { + // + // getting file info about the root directory + // ++ DEBUG ((DEBUG_INFO, "%a: file info: directory\n", __func__)); + Name = L"\\"; +- FileSize = KernelBlobTypeMax; ++ FileSize = mKernelBlobCount; + Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY; + } else { +- CONST KERNEL_BLOB *Blob; +- +- Blob = &mKernelBlob[BlobType]; ++ DEBUG ((DEBUG_INFO, "%a: file info: \"%s\"\n", __func__, Blob->Name)); + Name = Blob->Name; + FileSize = Blob->Size; + Attribute = EFI_FILE_READ_ONLY; +@@ -312,6 +311,23 @@ ConvertKernelBlobTypeToFileInfo ( + return EFI_SUCCESS; + } + ++STATIC ++KERNEL_BLOB * ++FindKernelBlob ( ++ CHAR16 *FileName ++ ) ++{ ++ KERNEL_BLOB *Blob; ++ ++ for (Blob = mKernelBlobs; Blob != NULL; Blob = Blob->Next) { ++ if (StrCmp (FileName, Blob->Name) == 0) { ++ return Blob; ++ } ++ } ++ ++ return NULL; ++} ++ + /** + Reads data from a file, or continues scanning a directory. + +@@ -349,25 +365,25 @@ ConvertKernelBlobTypeToFileInfo ( + STATIC + EFI_STATUS + EFIAPI +-StubFileRead ( ++QemuKernelStubFileRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) + { +- STUB_FILE *StubFile; +- CONST KERNEL_BLOB *Blob; +- UINT64 Left; ++ STUB_FILE *StubFile; ++ KERNEL_BLOB *Blob; ++ UINT64 Left, Pos; + + StubFile = STUB_FILE_FROM_FILE (This); + + // + // Scanning the root directory? + // +- if (StubFile->BlobType == KernelBlobTypeMax) { ++ if (StubFile->Blob == NULL) { + EFI_STATUS Status; + +- if (StubFile->Position == KernelBlobTypeMax) { ++ if (StubFile->Position == mKernelBlobCount) { + // + // Scanning complete. + // +@@ -375,8 +391,16 @@ StubFileRead ( + return EFI_SUCCESS; + } + +- Status = ConvertKernelBlobTypeToFileInfo ( +- (KERNEL_BLOB_TYPE)StubFile->Position, ++ for (Pos = 0, Blob = mKernelBlobs; ++ Pos < StubFile->Position; ++ Pos++, Blob = Blob->Next) ++ { ++ } ++ ++ DEBUG ((DEBUG_INFO, "%a: file list: #%d \"%s\"\n", __func__, Pos, Blob->Name)); ++ ++ Status = QemuKernelBlobTypeToFileInfo ( ++ Blob, + BufferSize, + Buffer + ); +@@ -391,7 +415,7 @@ StubFileRead ( + // + // Reading a file. + // +- Blob = &mKernelBlob[StubFile->BlobType]; ++ Blob = StubFile->Blob; + if (StubFile->Position > Blob->Size) { + return EFI_DEVICE_ERROR; + } +@@ -402,6 +426,7 @@ StubFileRead ( + } + + if (Blob->Data != NULL) { ++ DEBUG ((DEBUG_INFO, "%a: file read: \"%s\", %d bytes\n", __func__, Blob->Name, *BufferSize)); + CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize); + } + +@@ -435,7 +460,7 @@ StubFileRead ( + STATIC + EFI_STATUS + EFIAPI +-StubFileWrite ( ++QemuKernelStubFileWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer +@@ -444,7 +469,7 @@ StubFileWrite ( + STUB_FILE *StubFile; + + StubFile = STUB_FILE_FROM_FILE (This); +- return (StubFile->BlobType == KernelBlobTypeMax) ? ++ return (StubFile->Blob == NULL) ? + EFI_UNSUPPORTED : + EFI_WRITE_PROTECTED; + } +@@ -466,7 +491,7 @@ StubFileWrite ( + STATIC + EFI_STATUS + EFIAPI +-StubFileGetPosition ( ++QemuKernelStubFileGetPosition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +@@ -474,7 +499,7 @@ StubFileGetPosition ( + STUB_FILE *StubFile; + + StubFile = STUB_FILE_FROM_FILE (This); +- if (StubFile->BlobType == KernelBlobTypeMax) { ++ if (StubFile->Blob == NULL) { + return EFI_UNSUPPORTED; + } + +@@ -501,7 +526,7 @@ StubFileGetPosition ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSetPosition ( ++QemuKernelStubFileSetPosition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +@@ -511,7 +536,7 @@ StubFileSetPosition ( + + StubFile = STUB_FILE_FROM_FILE (This); + +- if (StubFile->BlobType == KernelBlobTypeMax) { ++ if (StubFile->Blob == NULL) { + if (Position == 0) { + // + // rewinding a directory scan is allowed +@@ -526,7 +551,7 @@ StubFileSetPosition ( + // + // regular file seek + // +- Blob = &mKernelBlob[StubFile->BlobType]; ++ Blob = StubFile->Blob; + if (Position == MAX_UINT64) { + // + // seek to end +@@ -583,7 +608,7 @@ StubFileSetPosition ( + STATIC + EFI_STATUS + EFIAPI +-StubFileGetInfo ( ++QemuKernelStubFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, +@@ -596,8 +621,8 @@ StubFileGetInfo ( + StubFile = STUB_FILE_FROM_FILE (This); + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { +- return ConvertKernelBlobTypeToFileInfo ( +- StubFile->BlobType, ++ return QemuKernelBlobTypeToFileInfo ( ++ StubFile->Blob, + BufferSize, + Buffer + ); +@@ -685,7 +710,7 @@ StubFileGetInfo ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSetInfo ( ++QemuKernelStubFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, +@@ -712,7 +737,7 @@ StubFileSetInfo ( + STATIC + EFI_STATUS + EFIAPI +-StubFileFlush ( ++QemuKernelStubFileFlush ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -724,16 +749,16 @@ StubFileFlush ( + // + STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = { + EFI_FILE_PROTOCOL_REVISION, // revision 1 +- StubFileOpen, +- StubFileClose, +- StubFileDelete, +- StubFileRead, +- StubFileWrite, +- StubFileGetPosition, +- StubFileSetPosition, +- StubFileGetInfo, +- StubFileSetInfo, +- StubFileFlush, ++ QemuKernelStubFileOpen, ++ QemuKernelStubFileClose, ++ QemuKernelStubFileDelete, ++ QemuKernelStubFileRead, ++ QemuKernelStubFileWrite, ++ QemuKernelStubFileGetPosition, ++ QemuKernelStubFileSetPosition, ++ QemuKernelStubFileGetInfo, ++ QemuKernelStubFileSetInfo, ++ QemuKernelStubFileFlush, + NULL, // OpenEx, revision 2 + NULL, // ReadEx, revision 2 + NULL, // WriteEx, revision 2 +@@ -743,7 +768,7 @@ STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = { + STATIC + EFI_STATUS + EFIAPI +-StubFileOpen ( ++QemuKernelStubFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, +@@ -752,7 +777,7 @@ StubFileOpen ( + ) + { + CONST STUB_FILE *StubFile; +- UINTN BlobType; ++ KERNEL_BLOB *Blob; + STUB_FILE *NewStubFile; + + // +@@ -774,21 +799,20 @@ StubFileOpen ( + // Only the root directory supports opening files in it. + // + StubFile = STUB_FILE_FROM_FILE (This); +- if (StubFile->BlobType != KernelBlobTypeMax) { ++ if (StubFile->Blob != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Locate the file. + // +- for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) { +- if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) { +- break; +- } +- } ++ Blob = FindKernelBlob (FileName); + +- if (BlobType == KernelBlobTypeMax) { ++ if (Blob == NULL) { ++ DEBUG ((DEBUG_INFO, "%a: file not found: \"%s\"\n", __func__, FileName)); + return EFI_NOT_FOUND; ++ } else { ++ DEBUG ((DEBUG_INFO, "%a: file opened: \"%s\"\n", __func__, FileName)); + } + + // +@@ -800,7 +824,7 @@ StubFileOpen ( + } + + NewStubFile->Signature = STUB_FILE_SIG; +- NewStubFile->BlobType = (KERNEL_BLOB_TYPE)BlobType; ++ NewStubFile->Blob = Blob; + NewStubFile->Position = 0; + CopyMem ( + &NewStubFile->File, +@@ -842,7 +866,7 @@ StubFileOpen ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSystemOpenVolume ( ++QemuKernelStubFileSystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ) +@@ -855,7 +879,7 @@ StubFileSystemOpenVolume ( + } + + StubFile->Signature = STUB_FILE_SIG; +- StubFile->BlobType = KernelBlobTypeMax; ++ StubFile->Blob = NULL; + StubFile->Position = 0; + CopyMem ( + &StubFile->File, +@@ -869,13 +893,13 @@ StubFileSystemOpenVolume ( + + STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, +- StubFileSystemOpenVolume ++ QemuKernelStubFileSystemOpenVolume + }; + + STATIC + EFI_STATUS + EFIAPI +-InitrdLoadFile2 ( ++QemuKernelInitrdLoadFile2 ( + IN EFI_LOAD_FILE2_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, +@@ -883,8 +907,11 @@ InitrdLoadFile2 ( + OUT VOID *Buffer OPTIONAL + ) + { +- CONST KERNEL_BLOB *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd]; ++ KERNEL_BLOB *InitrdBlob; + ++ DEBUG ((DEBUG_INFO, "%a: initrd read\n", __func__)); ++ InitrdBlob = FindKernelBlob (L"initrd"); ++ ASSERT (InitrdBlob != NULL); + ASSERT (InitrdBlob->Size > 0); + + if (BootPolicy) { +@@ -913,17 +940,33 @@ InitrdLoadFile2 ( + } + + STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = { +- InitrdLoadFile2, ++ QemuKernelInitrdLoadFile2, + }; + + // + // Utility functions. + // + ++STATIC VOID ++QemuKernelChunkedRead ( ++ UINT8 *Dest, ++ UINT32 Bytes ++ ) ++{ ++ UINT32 Chunk; ++ ++ while (Bytes > 0) { ++ Chunk = (Bytes < SIZE_1MB) ? Bytes : SIZE_1MB; ++ QemuFwCfgReadBytes (Chunk, Dest); ++ Bytes -= Chunk; ++ Dest += Chunk; ++ } ++} ++ + /** + Populate a blob in mKernelBlob. + +- param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is ++ param[in,out] Blob Pointer to the KERNEL_BLOB_ITEMS that is + to be filled from fw_cfg. + + @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a +@@ -934,35 +977,46 @@ STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = { + **/ + STATIC + EFI_STATUS +-FetchBlob ( +- IN OUT KERNEL_BLOB *Blob ++QemuKernelFetchBlob ( ++ IN KERNEL_BLOB_ITEMS *BlobItems + ) + { +- UINT32 Left; +- UINTN Idx; +- UINT8 *ChunkData; ++ UINT32 Size; ++ UINTN Idx; ++ UINT8 *ChunkData; ++ KERNEL_BLOB *Blob; ++ EFI_STATUS Status; + + // + // Read blob size. + // +- Blob->Size = 0; +- for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) { +- if (Blob->FwCfgItem[Idx].SizeKey == 0) { ++ for (Size = 0, Idx = 0; Idx < ARRAY_SIZE (BlobItems->FwCfgItem); Idx++) { ++ if (BlobItems->FwCfgItem[Idx].SizeKey == 0) { + break; + } + +- QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey); +- Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 (); +- Blob->Size += Blob->FwCfgItem[Idx].Size; ++ QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].SizeKey); ++ BlobItems->FwCfgItem[Idx].Size = QemuFwCfgRead32 (); ++ Size += BlobItems->FwCfgItem[Idx].Size; + } + +- if (Blob->Size == 0) { ++ if (Size == 0) { + return EFI_SUCCESS; + } + ++ Blob = AllocatePool (sizeof (*Blob)); ++ if (Blob->Data == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ ZeroMem (Blob, sizeof (*Blob)); ++ + // + // Read blob. + // ++ Status = StrCpyS (Blob->Name, sizeof (Blob->Name), BlobItems->Name); ++ ASSERT (!EFI_ERROR (Status)); ++ Blob->Size = Size; + Blob->Data = AllocatePool (Blob->Size); + if (Blob->Data == NULL) { + DEBUG (( +@@ -972,6 +1026,7 @@ FetchBlob ( + (INT64)Blob->Size, + Blob->Name + )); ++ FreePool (Blob); + return EFI_OUT_OF_RESOURCES; + } + +@@ -984,34 +1039,48 @@ FetchBlob ( + )); + + ChunkData = Blob->Data; +- for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) { +- if (Blob->FwCfgItem[Idx].DataKey == 0) { ++ for (Idx = 0; Idx < ARRAY_SIZE (BlobItems->FwCfgItem); Idx++) { ++ if (BlobItems->FwCfgItem[Idx].DataKey == 0) { + break; + } + +- QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey); ++ QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].DataKey); ++ QemuKernelChunkedRead (ChunkData, BlobItems->FwCfgItem[Idx].Size); ++ ChunkData += BlobItems->FwCfgItem[Idx].Size; ++ } + +- Left = Blob->FwCfgItem[Idx].Size; +- while (Left > 0) { +- UINT32 Chunk; ++ Blob->Next = mKernelBlobs; ++ mKernelBlobs = Blob; ++ mKernelBlobCount++; ++ mTotalBlobBytes += Blob->Size; ++ return EFI_SUCCESS; ++} + +- Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB; +- QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left); +- Left -= Chunk; +- DEBUG (( +- DEBUG_VERBOSE, +- "%a: %Ld bytes remaining for \"%s\" (%d)\n", +- __func__, +- (INT64)Left, +- Blob->Name, +- (INT32)Idx +- )); +- } ++STATIC ++EFI_STATUS ++QemuKernelVerifyBlob ( ++ CHAR16 *FileName, ++ EFI_STATUS FetchStatus ++ ) ++{ ++ KERNEL_BLOB *Blob; ++ EFI_STATUS Status; + +- ChunkData += Blob->FwCfgItem[Idx].Size; ++ if ((StrCmp (FileName, L"kernel") != 0) && ++ (StrCmp (FileName, L"initrd") != 0) && ++ (StrCmp (FileName, L"cmdline") != 0)) ++ { ++ return EFI_SUCCESS; + } + +- return EFI_SUCCESS; ++ Blob = FindKernelBlob (FileName); ++ Status = VerifyBlob ( ++ FileName, ++ Blob ? Blob->Data : NULL, ++ Blob ? Blob->Size : 0, ++ FetchStatus ++ ); ++ return Status; + } + + // +@@ -1038,13 +1107,13 @@ QemuKernelLoaderFsDxeEntrypoint ( + IN EFI_SYSTEM_TABLE *SystemTable + ) + { +- UINTN BlobType; +- KERNEL_BLOB *CurrentBlob; +- KERNEL_BLOB *KernelBlob; +- EFI_STATUS Status; +- EFI_STATUS FetchStatus; +- EFI_HANDLE FileSystemHandle; +- EFI_HANDLE InitrdLoadFile2Handle; ++ UINTN BlobIdx; ++ KERNEL_BLOB_ITEMS *BlobItems; ++ KERNEL_BLOB *Blob; ++ EFI_STATUS Status; ++ EFI_STATUS FetchStatus; ++ EFI_HANDLE FileSystemHandle; ++ EFI_HANDLE InitrdLoadFile2Handle; + + if (!QemuFwCfgIsAvailable ()) { + return EFI_NOT_FOUND; +@@ -1059,26 +1128,22 @@ QemuKernelLoaderFsDxeEntrypoint ( + // + // Fetch all blobs. + // +- for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) { +- CurrentBlob = &mKernelBlob[BlobType]; +- FetchStatus = FetchBlob (CurrentBlob); +- +- Status = VerifyBlob ( +- CurrentBlob->Name, +- CurrentBlob->Data, +- CurrentBlob->Size, ++ for (BlobIdx = 0; BlobIdx < ARRAY_SIZE (mKernelBlobItems); ++BlobIdx) { ++ BlobItems = &mKernelBlobItems[BlobIdx]; ++ FetchStatus = QemuKernelFetchBlob (BlobItems); ++ ++ Status = QemuKernelVerifyBlob ( ++ (CHAR16 *)BlobItems->Name, + FetchStatus + ); + if (EFI_ERROR (Status)) { + goto FreeBlobs; + } +- +- mTotalBlobBytes += CurrentBlob->Size; + } + +- KernelBlob = &mKernelBlob[KernelBlobTypeKernel]; +- +- if (KernelBlob->Data == NULL) { ++ Blob = FindKernelBlob (L"kernel"); ++ if (Blob == NULL) { ++ DEBUG ((DEBUG_INFO, "%a: no kernel present -> quit\n", __func__)); + Status = EFI_NOT_FOUND; + goto FreeBlobs; + } +@@ -1106,7 +1171,9 @@ QemuKernelLoaderFsDxeEntrypoint ( + goto FreeBlobs; + } + +- if (KernelBlob[KernelBlobTypeInitrd].Size > 0) { ++ Blob = FindKernelBlob (L"initrd"); ++ if (Blob != NULL) { ++ DEBUG ((DEBUG_INFO, "%a: initrd setup\n", __func__)); + InitrdLoadFile2Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &InitrdLoadFile2Handle, +@@ -1141,13 +1208,11 @@ UninstallFileSystemHandle: + ASSERT_EFI_ERROR (Status); + + FreeBlobs: +- while (BlobType > 0) { +- CurrentBlob = &mKernelBlob[--BlobType]; +- if (CurrentBlob->Data != NULL) { +- FreePool (CurrentBlob->Data); +- CurrentBlob->Size = 0; +- CurrentBlob->Data = NULL; +- } ++ while (mKernelBlobs != NULL) { ++ Blob = mKernelBlobs; ++ mKernelBlobs = Blob->Next; ++ FreePool (Blob->Data); ++ FreePool (Blob); + } + + return Status; +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-2.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-2.patch new file mode 100644 index 0000000000..964ee306bf --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-2.patch @@ -0,0 +1,175 @@ +From 20df7c42bd446fe725bfc78cdb40577456c421d8 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 15 Jan 2025 00:29:52 +0100 +Subject: [PATCH 02/10] OvmfPkg/QemuKernelLoaderFsDxe: add support for named + blobs + +Load all named fw_cfg blobs with "etc/boot/" prefix into the pseudo +filesystem. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/20df7c42bd446fe725bfc78cdb40577456c421d8] +Signed-off-by: Hongxu Jia +--- + .../QemuKernelLoaderFsDxe.c | 94 ++++++++++++++++--- + .../QemuKernelLoaderFsDxe.inf | 1 + + 2 files changed, 84 insertions(+), 11 deletions(-) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 7ad1b3828f..1f63adda0b 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,12 +33,12 @@ + // Static data that hosts the fw_cfg blobs and serves file requests. + // + typedef struct { +- CONST CHAR16 Name[8]; ++ CHAR16 Name[8]; + struct { +- FIRMWARE_CONFIG_ITEM CONST SizeKey; +- FIRMWARE_CONFIG_ITEM CONST DataKey; +- UINT32 Size; +- } FwCfgItem[2]; ++ FIRMWARE_CONFIG_ITEM SizeKey; ++ FIRMWARE_CONFIG_ITEM DataKey; ++ UINT32 Size; ++ } FwCfgItem[2]; + } KERNEL_BLOB_ITEMS; + + typedef struct KERNEL_BLOB KERNEL_BLOB; +@@ -989,15 +990,23 @@ QemuKernelFetchBlob ( + + // + // Read blob size. ++ // Size != 0 -> use size as-is ++ // SizeKey != 0 -> read size from fw_cfg ++ // both are 0 -> unused entry + // + for (Size = 0, Idx = 0; Idx < ARRAY_SIZE (BlobItems->FwCfgItem); Idx++) { +- if (BlobItems->FwCfgItem[Idx].SizeKey == 0) { ++ if ((BlobItems->FwCfgItem[Idx].SizeKey == 0) && ++ (BlobItems->FwCfgItem[Idx].Size == 0)) ++ { + break; + } + +- QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].SizeKey); +- BlobItems->FwCfgItem[Idx].Size = QemuFwCfgRead32 (); +- Size += BlobItems->FwCfgItem[Idx].Size; ++ if (BlobItems->FwCfgItem[Idx].SizeKey) { ++ QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].SizeKey); ++ BlobItems->FwCfgItem[Idx].Size = QemuFwCfgRead32 (); ++ } ++ ++ Size += BlobItems->FwCfgItem[Idx].Size; + } + + if (Size == 0) { +@@ -1083,6 +1092,55 @@ QemuKernelVerifyBlob ( + return Status; + } + ++STATIC ++EFI_STATUS ++QemuKernelFetchNamedBlobs ( ++ VOID ++ ) ++{ ++ struct { ++ UINT32 FileSize; ++ UINT16 FileSelect; ++ UINT16 Reserved; ++ CHAR8 FileName[QEMU_FW_CFG_FNAME_SIZE]; ++ } *DirEntry; ++ KERNEL_BLOB_ITEMS Items; ++ EFI_STATUS Status; ++ EFI_STATUS FetchStatus; ++ UINT32 Count; ++ UINT32 Idx; ++ ++ QemuFwCfgSelectItem (QemuFwCfgItemFileDir); ++ Count = SwapBytes32 (QemuFwCfgRead32 ()); ++ ++ DirEntry = AllocatePool (sizeof (*DirEntry) * Count); ++ QemuFwCfgReadBytes (sizeof (*DirEntry) * Count, DirEntry); ++ ++ for (Idx = 0; Idx < Count; ++Idx) { ++ if (AsciiStrnCmp (DirEntry[Idx].FileName, "etc/boot/", 9) != 0) { ++ continue; ++ } ++ ++ ZeroMem (&Items, sizeof (Items)); ++ UnicodeSPrint (Items.Name, sizeof (Items.Name), L"%a", DirEntry[Idx].FileName + 9); ++ Items.FwCfgItem[0].DataKey = SwapBytes16 (DirEntry[Idx].FileSelect); ++ Items.FwCfgItem[0].Size = SwapBytes32 (DirEntry[Idx].FileSize); ++ ++ FetchStatus = QemuKernelFetchBlob (&Items); ++ Status = QemuKernelVerifyBlob ( ++ (CHAR16 *)Items.Name, ++ FetchStatus ++ ); ++ if (EFI_ERROR (Status)) { ++ FreePool (DirEntry); ++ return Status; ++ } ++ } ++ ++ FreePool (DirEntry); ++ return EFI_SUCCESS; ++} ++ + // + // The entry point of the feature. + // +@@ -1126,10 +1184,24 @@ QemuKernelLoaderFsDxeEntrypoint ( + } + + // +- // Fetch all blobs. ++ // Fetch named blobs. + // ++ DEBUG ((DEBUG_INFO, "%a: named blobs (etc/boot/*)\n", __func__)); ++ Status = QemuKernelFetchNamedBlobs (); ++ if (EFI_ERROR (Status)) { ++ goto FreeBlobs; ++ } ++ ++ // ++ // Fetch traditional blobs. ++ // ++ DEBUG ((DEBUG_INFO, "%a: traditional blobs\n", __func__)); + for (BlobIdx = 0; BlobIdx < ARRAY_SIZE (mKernelBlobItems); ++BlobIdx) { +- BlobItems = &mKernelBlobItems[BlobIdx]; ++ BlobItems = &mKernelBlobItems[BlobIdx]; ++ if (FindKernelBlob (BlobItems->Name)) { ++ continue; ++ } ++ + FetchStatus = QemuKernelFetchBlob (BlobItems); + + Status = QemuKernelVerifyBlob ( +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf +index 7b35adb8e0..a2f44bbca1 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf +@@ -30,6 +30,7 @@ + DebugLib + DevicePathLib + MemoryAllocationLib ++ PrintLib + QemuFwCfgLib + UefiBootServicesTableLib + UefiDriverEntryPoint +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-3.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-3.patch new file mode 100644 index 0000000000..0ea2a70bf5 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-3.patch @@ -0,0 +1,42 @@ +From adf385ecab69631952bdc8b774ebd77e82b94a00 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 16 Jan 2025 15:42:13 +0100 +Subject: [PATCH 03/10] OvmfPkg/QemuKernelLoaderFsDxe: allow longer file names + +QEMU_FW_CFG_FNAME_SIZE is 56. 'etc/boot/' prefix is minus 9. Add one +for the terminating '\0'. Effective max size is 48. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/adf385ecab69631952bdc8b774ebd77e82b94a00] +Signed-off-by: Hongxu Jia +--- + OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 1f63adda0b..0947b6bf2d 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -33,7 +33,7 @@ + // Static data that hosts the fw_cfg blobs and serves file requests. + // + typedef struct { +- CHAR16 Name[8]; ++ CHAR16 Name[48]; + struct { + FIRMWARE_CONFIG_ITEM SizeKey; + FIRMWARE_CONFIG_ITEM DataKey; +@@ -43,7 +43,7 @@ typedef struct { + + typedef struct KERNEL_BLOB KERNEL_BLOB; + struct KERNEL_BLOB { +- CHAR16 Name[8]; ++ CHAR16 Name[48]; + UINT32 Size; + UINT8 *Data; + KERNEL_BLOB *Next; +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-4.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-4.patch new file mode 100644 index 0000000000..bba3b51c78 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-4.patch @@ -0,0 +1,34 @@ +From 1111e9fe7078eed9e5c50e1808776ee40a629e16 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 16 Jan 2025 15:52:54 +0100 +Subject: [PATCH 04/10] OvmfPkg/QemuKernelLoaderFsDxe: drop bogus assert + +Triggers when trying to get root directory info. +Reproducer: + * Use qemu -kernel with something edk2 can not load. + * When dropped into the efi shell try inspect the file system. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1111e9fe7078eed9e5c50e1808776ee40a629e16] +Signed-off-by: Hongxu Jia +--- + OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 0947b6bf2d..3e1a876bf0 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -290,7 +290,6 @@ QemuKernelBlobTypeToFileInfo ( + + NameSize = (StrLen (Name) + 1) * 2; + FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize; +- ASSERT (FileInfoSize >= sizeof *FileInfo); + + OriginalBufferSize = *BufferSize; + *BufferSize = FileInfoSize; +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-5.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-5.patch new file mode 100644 index 0000000000..e3a8292356 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-5.patch @@ -0,0 +1,36 @@ +From 46ae4e4b9574530e5081e98af0495d6f6d28379f Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 16 Jan 2025 16:03:01 +0100 +Subject: [PATCH 05/10] OvmfPkg/QemuKernelLoaderFsDxe: accept absolute paths + +EFI shell looks for "\startup.nsh". +Try "-fw_cfg name=etc/boot/startup.nsh,string='echo hello'" ;) + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/46ae4e4b9574530e5081e98af0495d6f6d28379f] +Signed-off-by: Hongxu Jia +--- + OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 3e1a876bf0..5b90420dad 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -806,6 +806,11 @@ QemuKernelStubFileOpen ( + // + // Locate the file. + // ++ if (FileName[0] == '\\') { ++ // also accept absolute paths, i.e. '\kernel' for 'kernel' ++ FileName++; ++ } ++ + Blob = FindKernelBlob (FileName); + + if (Blob == NULL) { +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-6.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-6.patch new file mode 100644 index 0000000000..3515efe008 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-6.patch @@ -0,0 +1,54 @@ +From c45051450efbdae4a38f07998b3e7b77abe7173a Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 20 Jan 2025 11:28:37 +0100 +Subject: [PATCH 06/10] OvmfPkg/QemuKernelLoaderFsDxe: don't quit when named + blobs are present + +Allows to use the qemu kernel loader pseudo file system for other +purposes than loading a linux kernel (or efi binary). Passing +startup.nsh for EFI shell is one example. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/c45051450efbdae4a38f07998b3e7b77abe7173a] +Signed-off-by: Hongxu Jia +--- + OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index 5b90420dad..add914daa8 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -71,6 +71,7 @@ STATIC KERNEL_BLOB_ITEMS mKernelBlobItems[] = { + + STATIC KERNEL_BLOB *mKernelBlobs; + STATIC UINT64 mKernelBlobCount; ++STATIC UINT64 mKernelNamedBlobCount; + STATIC UINT64 mTotalBlobBytes; + + // +@@ -1139,6 +1140,8 @@ QemuKernelFetchNamedBlobs ( + FreePool (DirEntry); + return Status; + } ++ ++ mKernelNamedBlobCount++; + } + + FreePool (DirEntry); +@@ -1218,8 +1221,8 @@ QemuKernelLoaderFsDxeEntrypoint ( + } + + Blob = FindKernelBlob (L"kernel"); +- if (Blob == NULL) { +- DEBUG ((DEBUG_INFO, "%a: no kernel present -> quit\n", __func__)); ++ if ((Blob == NULL) && (mKernelNamedBlobCount == 0)) { ++ DEBUG ((DEBUG_INFO, "%a: no kernel and no named blobs present -> quit\n", __func__)); + Status = EFI_NOT_FOUND; + goto FreeBlobs; + } +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-7.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-7.patch new file mode 100644 index 0000000000..a9d9922695 --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-7.patch @@ -0,0 +1,124 @@ +From 3da39f2cb681eb69f4eef54acd4b25d25cd7103d Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 10 Apr 2024 17:25:03 +0200 +Subject: [PATCH 07/10] OvmfPkg/X86QemuLoadImageLib: support booting via shim + +Try load shim first. In case that succeeded update the command line to +list 'kernel' first so shim will fetch the kernel from the kernel loader +file system. + +This allows to use direct kernel boot with distro kernels and secure +boot enabled. Usually distro kernels can only be verified by distro +shim using the distro keys compiled into the shim binary. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/3da39f2cb681eb69f4eef54acd4b25d25cd7103d] +Signed-off-by: Hongxu Jia +--- + .../X86QemuLoadImageLib/X86QemuLoadImageLib.c | 56 ++++++++++++++++++- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c +index a7ab43ca74..e4dbc2dc7e 100644 +--- a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c ++++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c +@@ -57,6 +57,25 @@ STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = { + } + }; + ++STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mShimDevicePath = { ++ { ++ { ++ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, ++ { sizeof (VENDOR_DEVICE_PATH) } ++ }, ++ QEMU_KERNEL_LOADER_FS_MEDIA_GUID ++ }, { ++ { ++ MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, ++ { sizeof (KERNEL_FILE_DEVPATH) } ++ }, ++ L"shim", ++ }, { ++ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, ++ { sizeof (EFI_DEVICE_PATH_PROTOCOL) } ++ } ++}; ++ + STATIC + VOID + FreeLegacyImage ( +@@ -339,6 +358,7 @@ QemuLoadKernelImage ( + UINTN CommandLineSize; + CHAR8 *CommandLine; + UINTN InitrdSize; ++ BOOLEAN Shim; + + // + // Redundant assignment to work around GCC48/GCC49 limitations. +@@ -351,11 +371,35 @@ QemuLoadKernelImage ( + Status = gBS->LoadImage ( + FALSE, // BootPolicy: exact match required + gImageHandle, // ParentImageHandle +- (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath, ++ (EFI_DEVICE_PATH_PROTOCOL *)&mShimDevicePath, + NULL, // SourceBuffer + 0, // SourceSize + &KernelImageHandle + ); ++ if (Status == EFI_SUCCESS) { ++ Shim = TRUE; ++ DEBUG ((DEBUG_INFO, "%a: booting via shim\n", __func__)); ++ } else { ++ Shim = FALSE; ++ if (Status == EFI_SECURITY_VIOLATION) { ++ gBS->UnloadImage (KernelImageHandle); ++ } ++ ++ if (Status != EFI_NOT_FOUND) { ++ DEBUG ((DEBUG_INFO, "%a: LoadImage(shim): %r\n", __func__, Status)); ++ return Status; ++ } ++ ++ Status = gBS->LoadImage ( ++ FALSE, // BootPolicy: exact match required ++ gImageHandle, // ParentImageHandle ++ (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath, ++ NULL, // SourceBuffer ++ 0, // SourceSize ++ &KernelImageHandle ++ ); ++ } ++ + switch (Status) { + case EFI_SUCCESS: + break; +@@ -465,6 +509,13 @@ QemuLoadKernelImage ( + KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2; + } + ++ if (Shim) { ++ // ++ // Prefix 'kernel ' in UTF-16. ++ // ++ KernelLoadedImage->LoadOptionsSize += sizeof (L"kernel ") - 2; ++ } ++ + if (KernelLoadedImage->LoadOptionsSize == 0) { + KernelLoadedImage->LoadOptions = NULL; + } else { +@@ -485,7 +536,8 @@ QemuLoadKernelImage ( + UnicodeSPrintAsciiFormat ( + KernelLoadedImage->LoadOptions, + KernelLoadedImage->LoadOptionsSize, +- "%a%a", ++ "%a%a%a", ++ (Shim == FALSE) ? "" : "kernel ", + (CommandLineSize == 0) ? "" : CommandLine, + (InitrdSize == 0) ? "" : " initrd=initrd" + ); +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-8.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-8.patch new file mode 100644 index 0000000000..97d77883fd --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-8.patch @@ -0,0 +1,125 @@ +From 4b507b49664514d7f09e6b7a9ca2da25a5e440fd Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 11 Apr 2024 08:15:22 +0200 +Subject: [PATCH 08/10] OvmfPkg/GenericQemuLoadImageLib: support booting via + shim + +Try load shim first. In case that succeeded update the command line to +list 'kernel' first so shim will fetch the kernel from the kernel loader +file system. + +This allows to use direct kernel boot with distro kernels and secure +boot enabled. Usually distro kernels can only be verified by distro +shim using the distro keys compiled into the shim binary. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4b507b49664514d7f09e6b7a9ca2da25a5e440fd] +Signed-off-by: Hongxu Jia +--- + .../GenericQemuLoadImageLib.c | 56 ++++++++++++++++++- + 1 file changed, 54 insertions(+), 2 deletions(-) + +diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c +index b99fb350aa..9d0ba77755 100644 +--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c ++++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c +@@ -57,6 +57,25 @@ STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = { + } + }; + ++STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mShimDevicePath = { ++ { ++ { ++ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, ++ { sizeof (VENDOR_DEVICE_PATH) } ++ }, ++ QEMU_KERNEL_LOADER_FS_MEDIA_GUID ++ }, { ++ { ++ MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, ++ { sizeof (KERNEL_FILE_DEVPATH) } ++ }, ++ L"shim", ++ }, { ++ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, ++ { sizeof (EFI_DEVICE_PATH_PROTOCOL) } ++ } ++}; ++ + STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mQemuKernelLoaderFsDevicePath = { + { + { +@@ -174,6 +193,7 @@ QemuLoadKernelImage ( + UINTN CommandLineSize; + CHAR8 *CommandLine; + UINTN InitrdSize; ++ BOOLEAN Shim; + + // + // Load the image. This should call back into the QEMU EFI loader file system. +@@ -181,11 +201,35 @@ QemuLoadKernelImage ( + Status = gBS->LoadImage ( + FALSE, // BootPolicy: exact match required + gImageHandle, // ParentImageHandle +- (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath, ++ (EFI_DEVICE_PATH_PROTOCOL *)&mShimDevicePath, + NULL, // SourceBuffer + 0, // SourceSize + &KernelImageHandle + ); ++ if (Status == EFI_SUCCESS) { ++ Shim = TRUE; ++ DEBUG ((DEBUG_INFO, "%a: booting via shim\n", __func__)); ++ } else { ++ Shim = FALSE; ++ if (Status == EFI_SECURITY_VIOLATION) { ++ gBS->UnloadImage (KernelImageHandle); ++ } ++ ++ if (Status != EFI_NOT_FOUND) { ++ DEBUG ((DEBUG_INFO, "%a: LoadImage(shim): %r\n", __func__, Status)); ++ return Status; ++ } ++ ++ Status = gBS->LoadImage ( ++ FALSE, // BootPolicy: exact match required ++ gImageHandle, // ParentImageHandle ++ (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath, ++ NULL, // SourceBuffer ++ 0, // SourceSize ++ &KernelImageHandle ++ ); ++ } ++ + switch (Status) { + case EFI_SUCCESS: + break; +@@ -303,6 +347,13 @@ QemuLoadKernelImage ( + KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2; + } + ++ if (Shim) { ++ // ++ // Prefix 'kernel ' in UTF-16. ++ // ++ KernelLoadedImage->LoadOptionsSize += sizeof (L"kernel ") - 2; ++ } ++ + if (KernelLoadedImage->LoadOptionsSize == 0) { + KernelLoadedImage->LoadOptions = NULL; + } else { +@@ -323,7 +374,8 @@ QemuLoadKernelImage ( + UnicodeSPrintAsciiFormat ( + KernelLoadedImage->LoadOptions, + KernelLoadedImage->LoadOptionsSize, +- "%a%a", ++ "%a%a%a", ++ (Shim == FALSE) ? "" : "kernel ", + (CommandLineSize == 0) ? "" : CommandLine, + (InitrdSize == 0) ? "" : " initrd=initrd" + ); +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-9.patch b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-9.patch new file mode 100644 index 0000000000..8f0535cc4b --- /dev/null +++ b/meta/recipes-core/ovmf/ovmf/CVE-2025-2296-9.patch @@ -0,0 +1,108 @@ +From 1549bf11cc94b135b6ad8fa5ebc34bdf7c18ba9c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 17 Dec 2024 09:59:21 +0100 +Subject: [PATCH 09/10] OvmfPkg/X86QemuLoadImageLib: make legacy loader + configurable. + +Add the 'opt/org.tianocore/EnableLegacyLoader' FwCfg option to +enable/disable the insecure legacy linux kernel loader. + +For now this is enabled by default. Probably the default will be +flipped to disabled at some point in the future. + +Also print a warning to the screen in case the linux kernel secure +boot verification has failed. + +Signed-off-by: Gerd Hoffmann + +CVE: CVE-2025-2296 +Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1549bf11cc94b135b6ad8fa5ebc34bdf7c18ba9c] +Signed-off-by: Hongxu Jia +--- + .../X86QemuLoadImageLib/X86QemuLoadImageLib.c | 48 ++++++++++++++++--- + .../X86QemuLoadImageLib.inf | 1 + + 2 files changed, 42 insertions(+), 7 deletions(-) + +diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c +index e4dbc2dc7e..2d610f6bd3 100644 +--- a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c ++++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c +@@ -19,8 +19,10 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include +@@ -421,13 +423,45 @@ QemuLoadKernelImage ( + // Fall through + // + case EFI_ACCESS_DENIED: +- // +- // We are running with UEFI secure boot enabled, and the image failed to +- // authenticate. For compatibility reasons, we fall back to the legacy +- // loader in this case. +- // +- // Fall through +- // ++ // ++ // We are running with UEFI secure boot enabled, and the image failed to ++ // authenticate. For compatibility reasons, we fall back to the legacy ++ // loader in this case (unless disabled via fw_cfg). ++ // ++ { ++ EFI_STATUS RetStatus; ++ BOOLEAN Enabled = TRUE; ++ ++ AsciiPrint ( ++ "OVMF: Secure boot image verification failed. Consider using the '-shim'\n" ++ "OVMF: command line switch for qemu (available in version 10.0 + newer).\n" ++ "\n" ++ ); ++ ++ RetStatus = QemuFwCfgParseBool ( ++ "opt/org.tianocore/EnableLegacyLoader", ++ &Enabled ++ ); ++ if (EFI_ERROR (RetStatus)) { ++ Enabled = TRUE; ++ } ++ ++ if (!Enabled) { ++ AsciiPrint ( ++ "OVMF: Fallback to insecure legacy linux kernel loader is disabled.\n" ++ "\n" ++ ); ++ return EFI_ACCESS_DENIED; ++ } else { ++ AsciiPrint ( ++ "OVMF: Using legacy linux kernel loader (insecure and deprecated).\n" ++ "\n" ++ ); ++ // ++ // Fall through ++ // ++ } ++ } + case EFI_UNSUPPORTED: + // + // The image is not natively supported or cross-type supported. Let's try +diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf +index c7ec041cb7..09babd3be8 100644 +--- a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf ++++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf +@@ -33,6 +33,7 @@ + LoadLinuxLib + PrintLib + QemuFwCfgLib ++ QemuFwCfgSimpleParserLib + ReportStatusCodeLib + UefiBootServicesTableLib + +-- +2.49.0 + diff --git a/meta/recipes-core/ovmf/ovmf_git.bb b/meta/recipes-core/ovmf/ovmf_git.bb index badde30d97..fd5ff25dc9 100644 --- a/meta/recipes-core/ovmf/ovmf_git.bb +++ b/meta/recipes-core/ovmf/ovmf_git.bb @@ -29,6 +29,16 @@ SRC_URI = "gitsm://github.com/tianocore/edk2.git;branch=master;protocol=https \ file://0006-BaseTools-StringFuncs-fix-gcc-16-warning.patch \ file://0007-BaseTools-EfiRom-fix-compiler-warning.patch \ file://0008-BaseTools-Pccts-set-C-standard.patch \ + file://0001-AmdSev-Halt-on-failed-blob-allocation.patch \ + file://CVE-2025-2296-1.patch \ + file://CVE-2025-2296-2.patch \ + file://CVE-2025-2296-3.patch \ + file://CVE-2025-2296-4.patch \ + file://CVE-2025-2296-5.patch \ + file://CVE-2025-2296-6.patch \ + file://CVE-2025-2296-7.patch \ + file://CVE-2025-2296-8.patch \ + file://CVE-2025-2296-9.patch \ " PV = "edk2-stable202402"