There are three possibilities here, each a little different: - relocating for kaslr, just request extra_size like the zboot flow does when allocating from EFI - in place, attempt to allocate from EFI precisely after Image to confirm nothing weird is there, failing that - like any other error with the in place EFI location allocate non-randomly with extra_size included
Remove the callers' assignments of reserve_size since efi_kaslr_relocate_kernel() now does it. Signed-off-by: Jason Gunthorpe <[email protected]> --- drivers/firmware/efi/libstub/arm64-stub.c | 1 - drivers/firmware/efi/libstub/kaslr.c | 72 +++++++++++++++++++---- drivers/firmware/efi/libstub/riscv-stub.c | 1 - 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 1d3fc8ac13efa7..1aa169464e529e 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -38,7 +38,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, info = efi_get_image_info((unsigned long)_text); kernel_codesize = le64_to_cpu(info->code_size); kernel_memsize = kernel_size + (_end - _edata); - *reserve_size = kernel_memsize; *image_addr = (unsigned long)_text; return efi_kaslr_relocate_kernel(image_addr, reserve_addr, reserve_size, diff --git a/drivers/firmware/efi/libstub/kaslr.c b/drivers/firmware/efi/libstub/kaslr.c index 4bc963e999eb97..e419f3800af517 100644 --- a/drivers/firmware/efi/libstub/kaslr.c +++ b/drivers/firmware/efi/libstub/kaslr.c @@ -83,11 +83,47 @@ static bool check_image_region(u64 base, u64 size) return ret; } +/* + * The PE loader owns only kernel_memsize of the image. Try to own the + * requested tail separately at the exact adjacent address instead of + * relocating the complete region. + */ +static efi_status_t allocate_image_tail(unsigned long image_addr, + unsigned long kernel_memsize, + unsigned long extra_size, + unsigned long *reserve_addr, + unsigned long *reserve_size) +{ + efi_physical_addr_t tail_addr; + efi_status_t status; + + /* + * Since we intend to use efi_free() for reserve_addr it should be + * aligned to the higher alignment since efi_free() includes rounding. + * For ARM64 the kernel image is already aligned up to EFI_ALLOC_ALIGN + * by the linker. + */ + tail_addr = image_addr + kernel_memsize; + if (!IS_ALIGNED(tail_addr, EFI_ALLOC_ALIGN)) + return EFI_OUT_OF_RESOURCES; + + extra_size = round_up(extra_size, EFI_ALLOC_ALIGN); + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, + EFI_LOADER_CODE, extra_size / EFI_PAGE_SIZE, + &tail_addr); + if (status != EFI_SUCCESS) + return status; + + *reserve_addr = tail_addr; + *reserve_size = extra_size; + return EFI_SUCCESS; +} + /** * efi_kaslr_relocate_kernel() - Relocate the kernel (random if KASLR enabled) * @image_addr: Pointer to the current kernel location - * @reserve_addr: Pointer to the relocated kernel location - * @reserve_size: Size of the relocated kernel + * @reserve_addr: Pointer to any allocated memory + * @reserve_size: Size that was allocated * @kernel_size: Size of the text + data * @kernel_codesize: Size of the text * @kernel_memsize: Size of the text + data + bss @@ -109,6 +145,9 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr, { efi_status_t status; u64 min_kimg_align = efi_get_kimg_min_align(); + unsigned long extra_size = efi_drtm_get_extra_size(); + + *reserve_size = kernel_memsize + extra_size; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { /* @@ -125,16 +164,29 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr, } if (status != EFI_SUCCESS) { - if (!check_image_region(*image_addr, kernel_memsize)) { + bool image_region_ok = + check_image_region(*image_addr, kernel_memsize); + + if (!image_region_ok) { efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n"); } else if (IS_ALIGNED(*image_addr, min_kimg_align) && - (unsigned long)_end < EFI_ALLOC_LIMIT) { - /* - * Just execute from wherever we were loaded by the - * UEFI PE/COFF loader if the placement is suitable. - */ - *reserve_size = 0; - return EFI_SUCCESS; + (unsigned long)_end + extra_size < EFI_ALLOC_LIMIT) { + if (!extra_size) { + /* + * Just execute from wherever we were loaded by + * the UEFI PE/COFF loader if the placement is + * suitable. + */ + *reserve_size = 0; + return EFI_SUCCESS; + } + + status = allocate_image_tail(*image_addr, + kernel_memsize, extra_size, + reserve_addr, + reserve_size); + if (status == EFI_SUCCESS) + return EFI_SUCCESS; } status = efi_allocate_pages_aligned(*reserve_size, reserve_addr, diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c index 725b634c517919..a88b2d275e5bb0 100644 --- a/drivers/firmware/efi/libstub/riscv-stub.c +++ b/drivers/firmware/efi/libstub/riscv-stub.c @@ -37,7 +37,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, kernel_codesize = __init_text_end - _start; kernel_memsize = kernel_size + (_end - _edata); *image_addr = (unsigned long)_start; - *reserve_size = kernel_memsize; status = efi_kaslr_relocate_kernel(image_addr, reserve_addr, reserve_size, -- 2.43.0
