efi: zboot: create MemoryMapped() device path for the parent if needed

LoadImage() is supposed to install an instance of the protocol
EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL onto the loaded image's handle so
that the program can figure out where it was loaded from. The reference
implementation even does this (with a NULL protocol pointer) if the call
to LoadImage() used the source buffer and size arguments, and passed
NULL for the image device path. Hand rolled implementations of LoadImage
may behave differently, though, and so it is better to tolerate
situations where the protocol is missing. And actually, concatenating an
Offset() node to a NULL device path (as we do currently) is not great
either.

So in cases where the protocol is absent, or when it points to NULL,
construct a MemoryMapped() device node as the base node that describes
the parent image's footprint in memory.

Cc: Daan De Meyer <daandemeyer@fb.com>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2022-09-22 12:03:52 +02:00
parent 04419e8a7b
commit 3c6edd9034
2 changed files with 23 additions and 4 deletions

View File

@ -162,6 +162,11 @@ static void append_end_node(efi_device_path_protocol_t **dp)
asmlinkage efi_status_t __efiapi asmlinkage efi_status_t __efiapi
efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
{ {
struct efi_mem_mapped_dev_path mmdp = {
.header.type = EFI_DEV_HW,
.header.sub_type = EFI_DEV_MEM_MAPPED,
.header.length = sizeof(struct efi_mem_mapped_dev_path)
};
efi_device_path_protocol_t *parent_dp, *dpp, *lf2_dp, *li_dp; efi_device_path_protocol_t *parent_dp, *dpp, *lf2_dp, *li_dp;
efi_load_file2_protocol_t zboot_load_file2; efi_load_file2_protocol_t zboot_load_file2;
efi_loaded_image_t *parent, *child; efi_loaded_image_t *parent, *child;
@ -191,13 +196,20 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
status = efi_bs_call(handle_protocol, handle, status = efi_bs_call(handle_protocol, handle,
&LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID, &LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID,
(void **)&parent_dp); (void **)&parent_dp);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS || parent_dp == NULL) {
log(L"Failed to locate parent's loaded image device path protocol"); // Create a MemoryMapped() device path node to describe
return status; // the parent image if no device path was provided.
mmdp.memory_type = parent->image_code_type;
mmdp.starting_addr = (unsigned long)parent->image_base;
mmdp.ending_addr = (unsigned long)parent->image_base +
parent->image_size - 1;
parent_dp = &mmdp.header;
dp_len = sizeof(mmdp);
} else {
dp_len = device_path_length(parent_dp);
} }
// Allocate some pool memory for device path protocol data // Allocate some pool memory for device path protocol data
dp_len = parent_dp ? device_path_length(parent_dp) : 0;
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
2 * (dp_len + sizeof(struct efi_rel_offset_dev_path) + 2 * (dp_len + sizeof(struct efi_rel_offset_dev_path) +
sizeof(struct efi_generic_dev_path)) + sizeof(struct efi_generic_dev_path)) +

View File

@ -1004,6 +1004,13 @@ struct efi_rel_offset_dev_path {
u64 ending_offset; u64 ending_offset;
} __packed; } __packed;
struct efi_mem_mapped_dev_path {
struct efi_generic_dev_path header;
u32 memory_type;
u64 starting_addr;
u64 ending_addr;
} __packed;
struct efi_dev_path { struct efi_dev_path {
union { union {
struct efi_generic_dev_path header; struct efi_generic_dev_path header;