From: Felix Fu fuzhen5@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA
--------------------------------
Add arm64 kaslr memory region avoid support code, this patch refer to the kaslr avoid mem region code structure of x86.
Signed-off-by: Felix Fu fuzhen5@huawei.com --- drivers/firmware/efi/libstub/arm64-stub.c | 89 ++++++++++++++++++++++ drivers/firmware/efi/libstub/efistub.h | 8 ++ drivers/firmware/efi/libstub/randomalloc.c | 11 ++- 3 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 452b7ccd330e..d3caecd874b2 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -14,6 +14,95 @@
#include "efistub.h"
+#if defined CONFIG_UEFI_KASLR_SKIP_MEMMAP || defined(CONFIG_NOKASLR_MEM_RANGE) +enum mem_avoid_index { + MEM_AVOID_MAX, +}; + +struct mem_vector { + unsigned long long start; + unsigned long long size; +}; + +static struct mem_vector mem_avoid[MEM_AVOID_MAX]; + +static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two) +{ + if (one->start + one->size <= two->start) + return false; + if (one->start >= two->start + two->size) + return false; + return true; +} + +static bool mem_avoid_overlap(struct mem_vector *region, struct mem_vector *overlap) +{ + int i; + u64 earliest = region->start + region->size; + bool is_overlapping = false; + + for (i = 0; i < MEM_AVOID_MAX; i++) { + if (mem_overlaps(region, &mem_avoid[i]) && + mem_avoid[i].start < earliest) { + *overlap = mem_avoid[i]; + earliest = overlap->start; + is_overlapping = true; + } + } + return is_overlapping; +} + +unsigned long cal_slots_avoid_overlap(efi_memory_desc_t *md, unsigned long size, u8 cal_type, + unsigned long align_shift, unsigned long target) +{ + struct mem_vector region, overlap; + unsigned long region_end, first, last; + unsigned long align = 1UL << align_shift; + unsigned long total_slots = 0, slots; + + region.start = md->phys_addr; + region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1, (u64)ULONG_MAX); + + while (region.start < region_end) { + first = round_up(region.start, align); + last = round_down(region_end - size + 1, align); + + if (first > last) + break; + + region.size = region_end - region.start + 1; + + if (!mem_avoid_overlap(®ion, &overlap)) { + slots = ((last - first) >> align_shift) + 1; + total_slots += slots; + + if (cal_type == CAL_SLOTS_PHYADDR) + return first + target * align; + + break; + } + + if (overlap.start >= region.start + size) { + slots = ((round_up(overlap.start - size + 1, align) - first) >> + align_shift) + 1; + total_slots += slots; + + if (cal_type == CAL_SLOTS_PHYADDR) { + if (target > slots) + target -= slots; + else + return first + target * align; + } + } + + /* Clip off the overlapping region and start over. */ + region.start = overlap.start + overlap.size; + } + + return total_slots; +} +#endif + efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 212687c30d79..33cf4ab1faed 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1000,6 +1000,14 @@ efi_status_t efi_parse_options(char const *cmdline);
void efi_parse_option_graphics(char *option);
+#if defined CONFIG_UEFI_KASLR_SKIP_MEMMAP || defined(CONFIG_NOKASLR_MEM_RANGE) +#define CAL_SLOTS_NUMBER 0 +#define CAL_SLOTS_PHYADDR 1 + +unsigned long cal_slots_avoid_overlap(efi_memory_desc_t *md, unsigned long size, u8 cal_type, + unsigned long align_shift, unsigned long target); +#endif + efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto, unsigned long size);
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c index 674a064b8f7a..48bf6903017f 100644 --- a/drivers/firmware/efi/libstub/randomalloc.c +++ b/drivers/firmware/efi/libstub/randomalloc.c @@ -39,8 +39,11 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
if (first_slot > last_slot) return 0; - +#if defined(CONFIG_ARM64) && (defined CONFIG_UEFI_KASLR_SKIP_MEMMAP || defined(CONFIG_NOKASLR_MEM_RANGE)) + return cal_slots_avoid_overlap(md, size, CAL_SLOTS_NUMBER, align_shift, 0); +#else return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1; +#endif }
/* @@ -117,8 +120,12 @@ efi_status_t efi_random_alloc(unsigned long size, target_slot -= MD_NUM_SLOTS(md); continue; } - +#if defined(CONFIG_ARM64) && (defined CONFIG_UEFI_KASLR_SKIP_MEMMAP || defined(CONFIG_NOKASLR_MEM_RANGE)) + target = cal_slots_avoid_overlap(md, size, CAL_SLOTS_PHYADDR, ilog2(align), + target_slot); +#else target = round_up(md->phys_addr, align) + target_slot * align; +#endif pages = size / EFI_PAGE_SIZE;
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,