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

