In order to measure kernel images to a PCR of our choice, we need to
load ourselves the selected image from the specified device to memory.
We may then call LoadImage() with our memory buffer instead of our
device path (this will cause the loaded image to be relocated and
ready for StartImage()).

Signed-off-by: Cedric Hombourger <[email protected]>
---
 Makefile.am      |   3 +-
 include/loader.h |  21 +++++++
 loader.c         | 146 +++++++++++++++++++++++++++++++++++++++++++++++
 main.c           |  15 ++++-
 4 files changed, 181 insertions(+), 4 deletions(-)
 create mode 100644 include/loader.h
 create mode 100644 loader.c

diff --git a/Makefile.am b/Makefile.am
index 8fb8652..fb907ff 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -135,7 +135,8 @@ efi_sources = \
        env/fatvars.c \
        utils.c \
        bootguard.c \
-       main.c
+       main.c \
+       loader.c
 
 efi_cppflags = \
        -I$(top_builddir) -include config.h \
diff --git a/include/loader.h b/include/loader.h
new file mode 100644
index 0000000..5cf639e
--- /dev/null
+++ b/include/loader.h
@@ -0,0 +1,21 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (C) 2021 Mentor Graphics, A Siemens business
+ *
+ * Authors:
+ *  Cedric Hombourger <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#pragma once
+
+#include <efi.h>
+#include <efilib.h>
+
+EFI_STATUS
+load_from_device_path (IN OUT EFI_DEVICE_PATH **device_path, OUT VOID **data, 
OUT UINTN *size);
diff --git a/loader.c b/loader.c
new file mode 100644
index 0000000..6029781
--- /dev/null
+++ b/loader.c
@@ -0,0 +1,146 @@
+/*
+ * EFI Boot Guard
+ *
+ * Copyright (C) 2021 Mentor Graphics, A Siemens business
+ *
+ * Authors:
+ *  Cedric Hombourger <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include <efi.h>
+#include <efilib.h>
+#include "loader.h"
+
+static EFI_STATUS
+opened_file_size (EFI_FILE_HANDLE file_handle, UINT64 *size) {
+       UINT64 position;
+       EFI_STATUS status;
+
+       /* Get current position so we can restore it (on success only) */
+       status = uefi_call_wrapper(file_handle->GetPosition, 2, file_handle, 
&position);
+       if (EFI_ERROR(status)) {
+               return status;
+       }
+
+       /* Seek to the end of the file */
+       status = uefi_call_wrapper(file_handle->SetPosition, 2, file_handle, 
-1);
+       if (EFI_ERROR(status)) {
+               return status;
+       }
+
+       /* Get position at end of file */
+       status = uefi_call_wrapper(file_handle->GetPosition, 2, file_handle, 
size);
+       if (EFI_ERROR(status)) {
+               return status;
+       }
+
+       /* Restore original position */
+       status = uefi_call_wrapper(file_handle->SetPosition, 2, file_handle, 
position);
+       return status;
+}
+
+EFI_STATUS
+load_from_device_path (IN OUT EFI_DEVICE_PATH **device_path, OUT VOID **data, 
OUT UINTN *size)
+{
+       EFI_DEVICE_PATH *file_path;
+       MEMMAP_DEVICE_PATH *memory_path = NULL;
+       FILEPATH_DEVICE_PATH *node;
+        EFI_HANDLE device_handle;
+       EFI_FILE_HANDLE file_handle = NULL, last_handle;
+       UINT64 file_size;
+       void *file_data = NULL;
+       EFI_STATUS status;
+
+       file_path = *device_path;
+       status = uefi_call_wrapper(BS->LocateDevicePath, 3, 
&FileSystemProtocol, &file_path, &device_handle);
+       if (EFI_ERROR(status)) {
+               goto exit;
+       }
+
+       file_handle = LibOpenRoot (device_handle);
+       if (file_handle == NULL) {
+               /* Unable to open root device */
+               status = EFI_UNSUPPORTED;
+               goto exit;
+       }
+
+       /* Open each node from the device path until we get to the leaf node: 
our file */
+       node = (FILEPATH_DEVICE_PATH *)file_path;
+       while (!IsDevicePathEnd(&node->Header)) {
+               if (DevicePathType(&node->Header) != MEDIA_DEVICE_PATH || 
DevicePathSubType(&node->Header) != MEDIA_FILEPATH_DP) {
+                       status = EFI_UNSUPPORTED;
+                       goto close_file;
+               }
+
+               last_handle = file_handle;
+               file_handle = NULL;
+
+               status = uefi_call_wrapper(last_handle->Open, 5, last_handle, 
&file_handle, node->PathName, EFI_FILE_MODE_READ, 0);
+               if (EFI_ERROR(status)) {
+                       goto exit;
+               }
+               uefi_call_wrapper(last_handle->Close, 1, last_handle);
+               node = (FILEPATH_DEVICE_PATH *) 
NextDevicePathNode(&node->Header);
+       }
+
+       /* Get size of the file to be loaded */
+       status = opened_file_size(file_handle, &file_size);
+       if (EFI_ERROR(status)) {
+               goto close_file;
+       }
+
+       /* Allocate memory to hold it in memory */
+       file_data = AllocatePool(file_size);
+       if (file_data == NULL) {
+               status = EFI_OUT_OF_RESOURCES;
+               goto close_file;
+       }
+
+       /* And now load it entirely */
+       status = uefi_call_wrapper(file_handle->Read, 3, file_handle, 
&file_size, file_data);
+       if (EFI_ERROR(status)) {
+               goto free_data;
+       }
+
+       memory_path = AllocatePool (2 * sizeof (MEMMAP_DEVICE_PATH));
+       if (memory_path == NULL) {
+               status = EFI_OUT_OF_RESOURCES;
+               goto free_data;
+       }
+
+       /* Make a memory map device path */
+       SetDevicePathNodeLength(&memory_path[0].Header, sizeof(*memory_path));
+       memory_path[0].Header.Type = HARDWARE_DEVICE_PATH;
+       memory_path[0].Header.SubType = HW_MEMMAP_DP;
+       memory_path[0].MemoryType = EfiLoaderData;
+       memory_path[0].StartingAddress = (EFI_PHYSICAL_ADDRESS) file_data;
+       memory_path[0].EndingAddress = memory_path[0].StartingAddress + 
file_size;
+
+       /* End list of device path elements with an "end" node */
+       SetDevicePathEndNode(&memory_path[1].Header);
+
+       /* Provide the address and size of the loaded file */
+       *data = file_data;
+       *size = (UINTN) file_size;
+
+       /* Provide new device path to caller */
+       FreePool(*device_path);
+       *device_path = (EFI_DEVICE_PATH *)memory_path;
+       goto close_file;
+
+free_data:
+       if (file_data != NULL) {
+               FreePool(file_data);
+       }
+close_file:
+       if (file_handle != NULL) {
+               uefi_call_wrapper(file_handle->Close, 1, file_handle);
+       }
+exit:
+    return status;
+}
diff --git a/main.c b/main.c
index 7949218..c47af74 100644
--- a/main.c
+++ b/main.c
@@ -20,6 +20,7 @@
 #include <pci/header.h>
 #include <bootguard.h>
 #include <configuration.h>
+#include "loader.h"
 #include "version.h"
 #include "utils.h"
 
@@ -102,6 +103,8 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, 
EFI_SYSTEM_TABLE *system_table)
        EFI_DEVICE_PATH *payload_dev_path;
        EFI_LOADED_IMAGE *loaded_image;
        EFI_HANDLE payload_handle;
+       VOID *payload_data;
+       UINTN payload_size;
        EFI_STATUS status;
        BG_STATUS bg_status;
        BG_LOADER_PARAMS bg_loader_params;
@@ -169,11 +172,17 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, 
EFI_SYSTEM_TABLE *system_table)
                }
        }
 
+       /* Load specified kernel image to memory */
+       status = load_from_device_path (&payload_dev_path, &payload_data, 
&payload_size);
+       if (EFI_ERROR(status)) {
+               error_exit(L"Cannot load specified kernel image to memory", 
status);
+       }
+
        /* Load and start image */
-       status = uefi_call_wrapper(BS->LoadImage, 6, TRUE, this_image,
-                                  payload_dev_path, NULL, 0, &payload_handle);
+       status = uefi_call_wrapper(BS->LoadImage, 6, FALSE, this_image,
+                                  payload_dev_path, payload_data, 
payload_size, &payload_handle);
        if (EFI_ERROR(status)) {
-               error_exit(L"Cannot load specified kernel image", status);
+               error_exit(L"Cannot load specified kernel image from memory", 
status);
        }
 
        FreePool(payload_dev_path);
-- 
2.30.2

-- 
You received this message because you are subscribed to the Google Groups "EFI 
Boot Guard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/efibootguard-dev/20210704180009.383-2-Cedric_Hombourger%40mentor.com.

Reply via email to