diff --git a/SPECS/edk2/CVE-2025-2296.patch b/SPECS/edk2/CVE-2025-2296.patch new file mode 100644 index 00000000000..4d4f944ed72 --- /dev/null +++ b/SPECS/edk2/CVE-2025-2296.patch @@ -0,0 +1,1218 @@ +From b8e7f492faace8ec5fc184280d74ee5977525921 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 +Upstream Patch Reference: https://patch-diff.githubusercontent.com/raw/tianocore/edk2/pull/10628.patch +--- + .../BlobVerifierSevHashes.c | 4 +- + OvmfPkg/Include/Library/BlobVerifierLib.h | 4 +- + .../BlobVerifierLibNull/BlobVerifierNull.c | 4 +- + .../GenericQemuLoadImageLib.c | 56 ++- + .../X86QemuLoadImageLib/X86QemuLoadImageLib.c | 104 ++++- + .../X86QemuLoadImageLib.inf | 1 + + .../QemuKernelLoaderFsDxe.c | 433 ++++++++++++------ + .../QemuKernelLoaderFsDxe.inf | 1 + + 8 files changed, 448 insertions(+), 159 deletions(-) + +diff --git a/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c b/OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c +index 65f040f..6123c8a 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,7 +91,8 @@ EFIAPI + VerifyBlob ( + IN CONST CHAR16 *BlobName, + IN CONST VOID *Buf, +- IN UINT32 BufSize ++ IN UINT32 BufSize, ++ IN EFI_STATUS FetchStatus + ) + { + CONST GUID *Guid; +diff --git a/OvmfPkg/Include/Library/BlobVerifierLib.h b/OvmfPkg/Include/Library/BlobVerifierLib.h +index 7e1af27..286b564 100644 +--- a/OvmfPkg/Include/Library/BlobVerifierLib.h ++++ b/OvmfPkg/Include/Library/BlobVerifierLib.h +@@ -22,6 +22,7 @@ + @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 +@@ -32,7 +33,8 @@ 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 e817c3c..2b80348 100644 +--- a/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c ++++ b/OvmfPkg/Library/BlobVerifierLibNull/BlobVerifierNull.c +@@ -16,6 +16,7 @@ + @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 +@@ -26,7 +27,8 @@ EFIAPI + VerifyBlob ( + IN CONST CHAR16 *BlobName, + IN CONST VOID *Buf, +- IN UINT32 BufSize ++ IN UINT32 BufSize, ++ IN EFI_STATUS FetchStatus + ) + { + return EFI_SUCCESS; +diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c +index c751b10..86de79e 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" + ); +diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c +index 248a03e..ca9c877 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 +@@ -57,6 +59,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 +360,7 @@ QemuLoadKernelImage ( + UINTN CommandLineSize; + CHAR8 *CommandLine; + UINTN InitrdSize; ++ BOOLEAN Shim; + + // + // Redundant assignment to work around GCC48/GCC49 limitations. +@@ -351,11 +373,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; +@@ -377,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 +@@ -465,6 +543,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 +570,8 @@ QemuLoadKernelImage ( + UnicodeSPrintAsciiFormat ( + KernelLoadedImage->LoadOptions, + KernelLoadedImage->LoadOptionsSize, +- "%a%a", ++ "%a%a%a", ++ (Shim == FALSE) ? "" : "kernel ", + (CommandLineSize == 0) ? "" : CommandLine, + (InitrdSize == 0) ? "" : " initrd=initrd" + ); +diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf +index c7ec041..09babd3 100644 +--- a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf ++++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf +@@ -33,6 +33,7 @@ + LoadLinuxLib + PrintLib + QemuFwCfgLib ++ QemuFwCfgSimpleParserLib + ReportStatusCodeLib + UefiBootServicesTableLib + +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +index f007f8a..cb6fe8a 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -32,25 +33,24 @@ + // + // 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]; ++ CHAR16 Name[48]; + struct { +- FIRMWARE_CONFIG_ITEM CONST SizeKey; +- FIRMWARE_CONFIG_ITEM CONST DataKey; +- UINT32 Size; +- } FwCfgItem[2]; +- UINT32 Size; +- UINT8 *Data; +-} KERNEL_BLOB; +- +-STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = { ++ FIRMWARE_CONFIG_ITEM SizeKey; ++ FIRMWARE_CONFIG_ITEM DataKey; ++ UINT32 Size; ++ } FwCfgItem[2]; ++} KERNEL_BLOB_ITEMS; ++ ++typedef struct KERNEL_BLOB KERNEL_BLOB; ++struct KERNEL_BLOB { ++ CHAR16 Name[48]; ++ UINT32 Size; ++ UINT8 *Data; ++ KERNEL_BLOB *Next; ++}; ++ ++STATIC KERNEL_BLOB_ITEMS mKernelBlobItems[] = { + { + L"kernel", + { +@@ -70,7 +70,10 @@ STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = { + } + }; + +-STATIC UINT64 mTotalBlobBytes; ++STATIC KERNEL_BLOB *mKernelBlobs; ++STATIC UINT64 mKernelBlobCount; ++STATIC UINT64 mKernelNamedBlobCount; ++STATIC UINT64 mTotalBlobBytes; + + // + // Device path for the handle that incorporates our "EFI stub filesystem". +@@ -118,7 +121,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; +@@ -178,7 +181,7 @@ typedef struct { + STATIC + EFI_STATUS + EFIAPI +-StubFileOpen ( ++QemuKernelStubFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, +@@ -197,7 +200,7 @@ StubFileOpen ( + STATIC + EFI_STATUS + EFIAPI +-StubFileClose ( ++QemuKernelStubFileClose ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -220,7 +223,7 @@ StubFileClose ( + STATIC + EFI_STATUS + EFIAPI +-StubFileDelete ( ++QemuKernelStubFileDelete ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -230,18 +233,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, +@@ -258,10 +260,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; +@@ -273,17 +275,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; +@@ -291,7 +292,6 @@ ConvertKernelBlobTypeToFileInfo ( + + NameSize = (StrLen (Name) + 1) * 2; + FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize; +- ASSERT (FileInfoSize >= sizeof *FileInfo); + + OriginalBufferSize = *BufferSize; + *BufferSize = FileInfoSize; +@@ -313,6 +313,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. + +@@ -350,25 +367,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. + // +@@ -376,8 +393,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 + ); +@@ -392,7 +417,7 @@ StubFileRead ( + // + // Reading a file. + // +- Blob = &mKernelBlob[StubFile->BlobType]; ++ Blob = StubFile->Blob; + if (StubFile->Position > Blob->Size) { + return EFI_DEVICE_ERROR; + } +@@ -403,6 +428,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); + } + +@@ -436,7 +462,7 @@ StubFileRead ( + STATIC + EFI_STATUS + EFIAPI +-StubFileWrite ( ++QemuKernelStubFileWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer +@@ -445,7 +471,7 @@ StubFileWrite ( + STUB_FILE *StubFile; + + StubFile = STUB_FILE_FROM_FILE (This); +- return (StubFile->BlobType == KernelBlobTypeMax) ? ++ return (StubFile->Blob == NULL) ? + EFI_UNSUPPORTED : + EFI_WRITE_PROTECTED; + } +@@ -467,7 +493,7 @@ StubFileWrite ( + STATIC + EFI_STATUS + EFIAPI +-StubFileGetPosition ( ++QemuKernelStubFileGetPosition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +@@ -475,7 +501,7 @@ StubFileGetPosition ( + STUB_FILE *StubFile; + + StubFile = STUB_FILE_FROM_FILE (This); +- if (StubFile->BlobType == KernelBlobTypeMax) { ++ if (StubFile->Blob == NULL) { + return EFI_UNSUPPORTED; + } + +@@ -502,7 +528,7 @@ StubFileGetPosition ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSetPosition ( ++QemuKernelStubFileSetPosition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +@@ -512,7 +538,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 +@@ -527,7 +553,7 @@ StubFileSetPosition ( + // + // regular file seek + // +- Blob = &mKernelBlob[StubFile->BlobType]; ++ Blob = StubFile->Blob; + if (Position == MAX_UINT64) { + // + // seek to end +@@ -584,7 +610,7 @@ StubFileSetPosition ( + STATIC + EFI_STATUS + EFIAPI +-StubFileGetInfo ( ++QemuKernelStubFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, +@@ -597,8 +623,8 @@ StubFileGetInfo ( + StubFile = STUB_FILE_FROM_FILE (This); + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { +- return ConvertKernelBlobTypeToFileInfo ( +- StubFile->BlobType, ++ return QemuKernelBlobTypeToFileInfo ( ++ StubFile->Blob, + BufferSize, + Buffer + ); +@@ -686,7 +712,7 @@ StubFileGetInfo ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSetInfo ( ++QemuKernelStubFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, +@@ -713,7 +739,7 @@ StubFileSetInfo ( + STATIC + EFI_STATUS + EFIAPI +-StubFileFlush ( ++QemuKernelStubFileFlush ( + IN EFI_FILE_PROTOCOL *This + ) + { +@@ -725,16 +751,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 +@@ -744,7 +770,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, +@@ -753,7 +779,7 @@ StubFileOpen ( + ) + { + CONST STUB_FILE *StubFile; +- UINTN BlobType; ++ KERNEL_BLOB *Blob; + STUB_FILE *NewStubFile; + + // +@@ -775,21 +801,25 @@ 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; +- } ++ if (FileName[0] == '\\') { ++ // also accept absolute paths, i.e. '\kernel' for 'kernel' ++ FileName++; + } + +- if (BlobType == KernelBlobTypeMax) { ++ Blob = FindKernelBlob (FileName); ++ ++ 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)); + } + + // +@@ -801,7 +831,7 @@ StubFileOpen ( + } + + NewStubFile->Signature = STUB_FILE_SIG; +- NewStubFile->BlobType = (KERNEL_BLOB_TYPE)BlobType; ++ NewStubFile->Blob = Blob; + NewStubFile->Position = 0; + CopyMem ( + &NewStubFile->File, +@@ -843,7 +873,7 @@ StubFileOpen ( + STATIC + EFI_STATUS + EFIAPI +-StubFileSystemOpenVolume ( ++QemuKernelStubFileSystemOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ) +@@ -856,7 +886,7 @@ StubFileSystemOpenVolume ( + } + + StubFile->Signature = STUB_FILE_SIG; +- StubFile->BlobType = KernelBlobTypeMax; ++ StubFile->Blob = NULL; + StubFile->Position = 0; + CopyMem ( + &StubFile->File, +@@ -870,13 +900,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, +@@ -884,8 +914,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) { +@@ -914,17 +947,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 +@@ -935,35 +984,54 @@ 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. ++ // Size != 0 -> use size as-is ++ // SizeKey != 0 -> read size from fw_cfg ++ // both are 0 -> unused entry + // +- 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) && ++ (BlobItems->FwCfgItem[Idx].Size == 0)) ++ { + break; + } + +- QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey); +- Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 (); +- Blob->Size += Blob->FwCfgItem[Idx].Size; ++ if (BlobItems->FwCfgItem[Idx].SizeKey) { ++ 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 (( +@@ -973,6 +1041,7 @@ FetchBlob ( + (INT64)Blob->Size, + Blob->Name + )); ++ FreePool (Blob); + return EFI_OUT_OF_RESOURCES; + } + +@@ -985,33 +1054,98 @@ 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", +- __FUNCTION__, +- (INT64)Left, +- Blob->Name, +- (INT32)Idx +- )); ++STATIC ++EFI_STATUS ++QemuKernelVerifyBlob ( ++ CHAR16 *FileName, ++ EFI_STATUS FetchStatus ++ ) ++{ ++ KERNEL_BLOB *Blob; ++ EFI_STATUS Status; ++ ++ if ((StrCmp (FileName, L"kernel") != 0) && ++ (StrCmp (FileName, L"initrd") != 0) && ++ (StrCmp (FileName, L"cmdline") != 0)) ++ { ++ return EFI_SUCCESS; ++ } ++ ++ Blob = FindKernelBlob (FileName); ++ Status = VerifyBlob ( ++ FileName, ++ Blob ? Blob->Data : NULL, ++ Blob ? Blob->Size : 0, ++ FetchStatus ++ ); ++ 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; + } + +- ChunkData += Blob->FwCfgItem[Idx].Size; ++ mKernelNamedBlobCount++; + } + ++ FreePool (DirEntry); + return EFI_SUCCESS; + } + +@@ -1039,12 +1173,13 @@ QemuKernelLoaderFsDxeEntrypoint ( + IN EFI_SYSTEM_TABLE *SystemTable + ) + { +- UINTN BlobType; +- KERNEL_BLOB *CurrentBlob; +- KERNEL_BLOB *KernelBlob; +- EFI_STATUS Status; +- 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; +@@ -1057,30 +1192,38 @@ QemuKernelLoaderFsDxeEntrypoint ( + } + + // +- // Fetch all blobs. ++ // Fetch named blobs. + // +- for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) { +- CurrentBlob = &mKernelBlob[BlobType]; +- Status = FetchBlob (CurrentBlob); +- if (EFI_ERROR (Status)) { +- goto FreeBlobs; ++ 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]; ++ if (FindKernelBlob (BlobItems->Name)) { ++ continue; + } + +- Status = VerifyBlob ( +- CurrentBlob->Name, +- CurrentBlob->Data, +- CurrentBlob->Size ++ 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) && (mKernelNamedBlobCount == 0)) { ++ DEBUG ((DEBUG_INFO, "%a: no kernel and no named blobs present -> quit\n", __func__)); + Status = EFI_NOT_FOUND; + #if defined (MDE_CPU_AARCH64) + // +@@ -1125,7 +1268,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, +@@ -1160,13 +1305,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; +diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf +index e0331c6..4445407 100644 +--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf ++++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf +@@ -31,6 +31,7 @@ + DebugPrintErrorLevelLib + DevicePathLib + MemoryAllocationLib ++ PrintLib + QemuFwCfgLib + UefiBootServicesTableLib + UefiDriverEntryPoint +-- +2.45.4 + diff --git a/SPECS/edk2/edk2.spec b/SPECS/edk2/edk2.spec index 50855621dde..53edaf004b3 100644 --- a/SPECS/edk2/edk2.spec +++ b/SPECS/edk2/edk2.spec @@ -45,7 +45,7 @@ ExclusiveArch: x86_64 Name: edk2 Version: %{GITDATE}git%{GITCOMMIT} -Release: 43%{?dist} +Release: 44%{?dist} Summary: UEFI firmware for 64-bit virtual machines License: BSD-2-Clause-Patent and OpenSSL and MIT URL: http://www.tianocore.org @@ -123,6 +123,7 @@ Patch0027: CVE-2023-45236.patch Patch0028: CVE-2024-38796.patch Patch0029: CVE-2023-45231.patch Patch0030: CVE-2023-45229.patch +Patch0031: CVE-2025-2296.patch # Patches for the vendored OpenSSL are in the range from 1000 to 1999 (inclusive). Patch1000: CVE-2023-0464.patch @@ -716,6 +717,9 @@ $tests_ok %changelog +* Tue Nov 19 2025 Jyoti kanase - 20230301gitf80f052277c8-44 +- Patch for CVE-2025-2296 + * Mon Aug 11 2025 Azure Linux Security Servicing Account - 20230301gitf80f052277c8-43 - Patch for CVE-2025-3770