Skip to content

Commit

Permalink
efi/libstub: arm64: Relax 2M alignment again for relocatable kernels
Browse files Browse the repository at this point in the history
[ Upstream commit 3a26242 ]

Commit 8204670 ("efi/libstub/arm64: Replace 'preferred' offset with
alignment check") simplified the way the stub moves the kernel image
around in memory before booting it, given that a relocatable image does
not need to be copied to a 2M aligned offset if it was loaded on a 64k
boundary by EFI.

Commit d32de91 ("efi/arm64: libstub: Deal gracefully with
EFI_RNG_PROTOCOL failure") inadvertently defeated this logic by
overriding the value of efi_nokaslr if EFI_RNG_PROTOCOL is not
available, which was mistaken by the loader logic as an explicit request
on the part of the user to disable KASLR and any associated relocation
of an Image not loaded on a 2M boundary.

So let's reinstate this functionality, by capturing the value of
efi_nokaslr at function entry to choose the minimum alignment.

Fixes: d32de91 ("efi/arm64: libstub: Deal gracefully with EFI_RNG_PROTOCOL failure")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
ardbiesheuvel authored and gregkh committed Aug 18, 2021
1 parent feb4a01 commit 015e2c9
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions drivers/firmware/efi/libstub/arm64-stub.c
Expand Up @@ -79,18 +79,6 @@ static bool check_image_region(u64 base, u64 size)
return ret;
}

/*
* Although relocatable kernels can fix up the misalignment with respect to
* MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
* sync with those recorded in the vmlinux when kaslr is disabled but the
* image required relocation anyway. Therefore retain 2M alignment unless
* KASLR is in use.
*/
static u64 min_kimg_align(void)
{
return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
}

efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,
Expand All @@ -101,6 +89,16 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long kernel_size, kernel_memsize = 0;
u32 phys_seed = 0;

/*
* Although relocatable kernels can fix up the misalignment with
* respect to MIN_KIMG_ALIGN, the resulting virtual text addresses are
* subtly out of sync with those recorded in the vmlinux when kaslr is
* disabled but the image required relocation anyway. Therefore retain
* 2M alignment if KASLR was explicitly disabled, even if it was not
* going to be activated to begin with.
*/
u64 min_kimg_align = efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;

if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
if (!efi_nokaslr) {
status = efi_get_random_bytes(sizeof(phys_seed),
Expand Down Expand Up @@ -130,7 +128,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
* If KASLR is enabled, and we have some randomness available,
* locate the kernel at a randomized offset in physical memory.
*/
status = efi_random_alloc(*reserve_size, min_kimg_align(),
status = efi_random_alloc(*reserve_size, min_kimg_align,
reserve_addr, phys_seed);
} else {
status = EFI_OUT_OF_RESOURCES;
Expand All @@ -139,7 +137,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
if (status != EFI_SUCCESS) {
if (!check_image_region((u64)_text, kernel_memsize)) {
efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
} else if (IS_ALIGNED((u64)_text, min_kimg_align())) {
} else if (IS_ALIGNED((u64)_text, min_kimg_align)) {
/*
* Just execute from wherever we were loaded by the
* UEFI PE/COFF loader if the alignment is suitable.
Expand All @@ -150,7 +148,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
}

status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
ULONG_MAX, min_kimg_align());
ULONG_MAX, min_kimg_align);

if (status != EFI_SUCCESS) {
efi_err("Failed to relocate kernel\n");
Expand Down

0 comments on commit 015e2c9

Please sign in to comment.