efi_loader: Fix loaded image alignment

We are ignoring the alignment communicated via the PE/COFF header.
Starting 5.10 the Linux kernel will loudly complain about it. For more
details look at [1] (in linux kernel).

So add a function that can allocate aligned EFI memory and use it for our
relocated loaded image.

[1] c32ac11da3f83 ("efi/libstub: arm64: Double check image alignment at entry")

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Tested-by: Vincent Stehlé <vincent.stehle@arm.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Ilias Apalodimas 2021-10-11 15:10:23 +03:00 committed by Heinrich Schuchardt
parent fa00b6fc3f
commit ebdea88d57
3 changed files with 60 additions and 6 deletions

View file

@ -675,6 +675,8 @@ struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid);
#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) #define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
/* Generic EFI memory allocator, call this to get memory */ /* Generic EFI memory allocator, call this to get memory */
void *efi_alloc(uint64_t len, int memory_type); void *efi_alloc(uint64_t len, int memory_type);
/* Allocate pages on the specified alignment */
void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align);
/* More specific EFI memory allocator, called by EFI payloads */ /* More specific EFI memory allocator, called by EFI payloads */
efi_status_t efi_allocate_pages(enum efi_allocate_type type, efi_status_t efi_allocate_pages(enum efi_allocate_type type,
enum efi_memory_type memory_type, enum efi_memory_type memory_type,

View file

@ -898,9 +898,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
image_base = opt->ImageBase; image_base = opt->ImageBase;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
handle->image_type = opt->Subsystem; handle->image_type = opt->Subsystem;
virt_size = ALIGN(virt_size, opt->SectionAlignment); efi_reloc = efi_alloc_aligned_pages(virt_size,
efi_reloc = efi_alloc(virt_size, loaded_image_info->image_code_type,
loaded_image_info->image_code_type); opt->SectionAlignment);
if (!efi_reloc) { if (!efi_reloc) {
log_err("Out of memory\n"); log_err("Out of memory\n");
ret = EFI_OUT_OF_RESOURCES; ret = EFI_OUT_OF_RESOURCES;
@ -914,9 +914,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
image_base = opt->ImageBase; image_base = opt->ImageBase;
efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); efi_set_code_and_data_type(loaded_image_info, opt->Subsystem);
handle->image_type = opt->Subsystem; handle->image_type = opt->Subsystem;
virt_size = ALIGN(virt_size, opt->SectionAlignment); efi_reloc = efi_alloc_aligned_pages(virt_size,
efi_reloc = efi_alloc(virt_size, loaded_image_info->image_code_type,
loaded_image_info->image_code_type); opt->SectionAlignment);
if (!efi_reloc) { if (!efi_reloc) {
log_err("Out of memory\n"); log_err("Out of memory\n");
ret = EFI_OUT_OF_RESOURCES; ret = EFI_OUT_OF_RESOURCES;

View file

@ -549,6 +549,58 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
return ret; return ret;
} }
/**
* efi_alloc_aligned_pages - allocate
*
* @len: len in bytes
* @memory_type: usage type of the allocated memory
* @align: alignment in bytes
* Return: aligned memory or NULL
*/
void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align)
{
u64 req_pages = efi_size_in_pages(len);
u64 true_pages = req_pages + efi_size_in_pages(align) - 1;
u64 free_pages;
u64 aligned_mem;
efi_status_t r;
u64 mem;
/* align must be zero or a power of two */
if (align & (align - 1))
return NULL;
/* Check for overflow */
if (true_pages < req_pages)
return NULL;
if (align < EFI_PAGE_SIZE) {
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type,
req_pages, &mem);
return (r == EFI_SUCCESS) ? (void *)(uintptr_t)mem : NULL;
}
r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type,
true_pages, &mem);
if (r != EFI_SUCCESS)
return NULL;
aligned_mem = ALIGN(mem, align);
/* Free pages before alignment */
free_pages = efi_size_in_pages(aligned_mem - mem);
if (free_pages)
efi_free_pages(mem, free_pages);
/* Free trailing pages */
free_pages = true_pages - (req_pages + free_pages);
if (free_pages) {
mem = aligned_mem + req_pages * EFI_PAGE_SIZE;
efi_free_pages(mem, free_pages);
}
return (void *)(uintptr_t)aligned_mem;
}
/** /**
* efi_allocate_pool - allocate memory from pool * efi_allocate_pool - allocate memory from pool
* *