new file mode 100644
@@ -0,0 +1,159 @@
+From dbec8dc5ba6341d816ffd495fcd7eeece1716bb4 Mon Sep 17 00:00:00 2001
+From: Tobin Feldman-Fitzthum <tobin@linux.ibm.com>
+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 <tobin@linux.ibm.com>
+
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/10b4bb8d6d0c515ed9663691aea3684be8f7b0fc]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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
+
new file mode 100644
@@ -0,0 +1,762 @@
+From 459f5ffa24ae8574657c4105af0ff7dc30ac428d Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/459f5ffa24ae8574657c4105af0ff7dc30ac428d]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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
+
new file mode 100644
@@ -0,0 +1,175 @@
+From 20df7c42bd446fe725bfc78cdb40577456c421d8 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/20df7c42bd446fe725bfc78cdb40577456c421d8]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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 <Library/DebugLib.h>
+ #include <Library/DevicePathLib.h>
+ #include <Library/MemoryAllocationLib.h>
++#include <Library/PrintLib.h>
+ #include <Library/QemuFwCfgLib.h>
+ #include <Library/UefiBootServicesTableLib.h>
+ #include <Library/UefiRuntimeServicesTableLib.h>
+@@ -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
+
new file mode 100644
@@ -0,0 +1,42 @@
+From adf385ecab69631952bdc8b774ebd77e82b94a00 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/adf385ecab69631952bdc8b774ebd77e82b94a00]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ 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
+
new file mode 100644
@@ -0,0 +1,34 @@
+From 1111e9fe7078eed9e5c50e1808776ee40a629e16 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1111e9fe7078eed9e5c50e1808776ee40a629e16]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ 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
+
new file mode 100644
@@ -0,0 +1,36 @@
+From 46ae4e4b9574530e5081e98af0495d6f6d28379f Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/46ae4e4b9574530e5081e98af0495d6f6d28379f]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ 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
+
new file mode 100644
@@ -0,0 +1,54 @@
+From c45051450efbdae4a38f07998b3e7b77abe7173a Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/c45051450efbdae4a38f07998b3e7b77abe7173a]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ 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
+
new file mode 100644
@@ -0,0 +1,124 @@
+From 3da39f2cb681eb69f4eef54acd4b25d25cd7103d Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/3da39f2cb681eb69f4eef54acd4b25d25cd7103d]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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
+
new file mode 100644
@@ -0,0 +1,125 @@
+From 4b507b49664514d7f09e6b7a9ca2da25a5e440fd Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/4b507b49664514d7f09e6b7a9ca2da25a5e440fd]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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
+
new file mode 100644
@@ -0,0 +1,108 @@
+From 1549bf11cc94b135b6ad8fa5ebc34bdf7c18ba9c Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel@redhat.com>
+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 <kraxel@redhat.com>
+
+CVE: CVE-2025-2296
+Upstream-Status: Backport [https://github.com/tianocore/edk2/commit/1549bf11cc94b135b6ad8fa5ebc34bdf7c18ba9c]
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ .../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 <Library/MemoryAllocationLib.h>
+ #include <Library/PrintLib.h>
+ #include <Library/QemuFwCfgLib.h>
++#include <Library/QemuFwCfgSimpleParserLib.h>
+ #include <Library/QemuLoadImageLib.h>
+ #include <Library/UefiBootServicesTableLib.h>
++#include <Library/UefiLib.h>
+ #include <Protocol/DevicePath.h>
+ #include <Protocol/LoadedImage.h>
+ #include <Protocol/OvmfLoadedX86LinuxKernel.h>
+@@ -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
+
@@ -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"