From 9fb4f25452363184f7428de3041b91031387b40d Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Tue, 26 Dec 2023 17:23:14 +0800 Subject: [PATCH 1/6] efi/libstub: add arm64 kaslr memory region avoid support 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 --- arch/arm64/Kconfig | 14 +++ drivers/firmware/efi/libstub/randomalloc.c | 102 ++++++++++++++++++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 42079bfdf40a..60961f37e23f 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2259,6 +2259,20 @@ config RANDOMIZE_MODULE_REGION_FULL the region is exhausted. In this particular case of region exhaustion, modules might be able to fall back to a larger 2GB area. +config KASLR_SKIP_MEM_RANGE + bool "Skip specified memory range when randomize the kernel image" + depends on RANDOMIZE_BASE + default n + help + Skip specified memory range when randomize the kernel image. This + feature support memmap and nokalsr kernel parameter in arm64. + Memmap kernel parameter are described by the memmap=nn[KMG]$ss[KMG], + Region of memory to be reserved is from ss to ss+nn. Nokaslr + kernel parameters are described by the nokaslr=nn[KMG]-ss[KMG]. + Region of memory to be reserved is from nn to ss. The region must + be in the range of existed memory, otherwise will be ignored.This + feature support up to 32 memmap regions and 4 nokaslr regions. + config CC_HAVE_STACKPROTECTOR_SYSREG def_bool $(cc-option,-mstack-protector-guard=sysreg -mstack-protector-guard-reg=sp_el0 -mstack-protector-guard-offset=0) diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c index 674a064b8f7a..93ef20bb5e05 100644 --- a/drivers/firmware/efi/libstub/randomalloc.c +++ b/drivers/firmware/efi/libstub/randomalloc.c @@ -9,6 +9,97 @@ #include "efistub.h" +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) +#define CAL_SLOTS_NUMBER 0 +#define CAL_SLOTS_PHYADDR 1 + +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; +} + +static 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 /* * Return the number of slots covered by this entry, i.e., the number of * addresses it covers that are suitably aligned and supply enough room @@ -39,8 +130,11 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, if (first_slot > last_slot) return 0; - +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) + 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 +211,12 @@ efi_status_t efi_random_alloc(unsigned long size, target_slot -= MD_NUM_SLOTS(md); continue; } - +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) + 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, -- Gitee From 26ab8bd8ee8bd879d1ad529d07f473977014456d Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Tue, 26 Dec 2023 17:23:13 +0800 Subject: [PATCH 2/6] efi/libstub: arm64: support strchr function for EFI stub hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA -------------------------------- support strchr function for EFI stub, it will be used to parse cmdline args. Signed-off-by: Gaosheng Cui Signed-off-by: Felix Fu --- drivers/firmware/efi/libstub/string.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c index 168fe8e79abc..372bd386ad67 100644 --- a/drivers/firmware/efi/libstub/string.c +++ b/drivers/firmware/efi/libstub/string.c @@ -202,3 +202,22 @@ void *memchr(const void *s, int c, size_t n) } #endif #endif +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) +#ifndef EFI_HAVE_STRCHR +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + * + * Note that the %NUL-terminator is considered part of the string, and can + * be searched for. + */ +char *strchr(const char *s, int c) +{ + for (; *s != (char)c; ++s) + if (*s == '\0') + return NULL; + return (char *)s; +} +#endif +#endif \ No newline at end of file -- Gitee From 68684c9c9347706a7dc1f97018f0781568484603 Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Tue, 26 Dec 2023 17:23:15 +0800 Subject: [PATCH 3/6] efi/libstub: arm64: Fix KASLR and memmap= collision hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA -------------------------------- Kaslr will randomizes the physical address at which the kernel image is loaded, we will check and skip the memmap reserved memory. Signed-off-by: Gaosheng Cui Signed-off-by: Felix Fu --- .../firmware/efi/libstub/efi-stub-helper.c | 4 +++ drivers/firmware/efi/libstub/efistub.h | 4 +++ drivers/firmware/efi/libstub/randomalloc.c | 36 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index bfa30625f5d0..62bfe1a3e002 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -91,6 +91,10 @@ efi_status_t efi_parse_options(char const *cmdline) } else if (!strcmp(param, "video") && val && strstarts(val, "efifb:")) { efi_parse_option_graphics(val + strlen("efifb:")); +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) + } else if (!strcmp(param, "memmap") && val) { + mem_avoid_memmap(val); +#endif } } efi_bs_call(free_pool, buf); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 212687c30d79..10dbb82b8254 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1000,6 +1000,10 @@ efi_status_t efi_parse_options(char const *cmdline); void efi_parse_option_graphics(char *option); +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) +void mem_avoid_memmap(char *str); +#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 93ef20bb5e05..ecbdba2ae347 100644 --- a/drivers/firmware/efi/libstub/randomalloc.c +++ b/drivers/firmware/efi/libstub/randomalloc.c @@ -13,7 +13,11 @@ #define CAL_SLOTS_NUMBER 0 #define CAL_SLOTS_PHYADDR 1 +#define MAX_MEMMAP_REGIONS 32 + enum mem_avoid_index { + MAX_MEMMAP_REGIONS_BEGIN = 0, + MAX_MEMMAP_REGIONS_END = MAX_MEMMAP_REGIONS_BEGIN + MAX_MEMMAP_REGIONS - 1, MEM_AVOID_MAX, }; @@ -99,6 +103,38 @@ static unsigned long cal_slots_avoid_overlap(efi_memory_desc_t *md, unsigned lon return total_slots; } + +void mem_avoid_memmap(char *str) +{ + static int i; + + while (str && (i < MAX_MEMMAP_REGIONS)) { + char *oldstr; + u64 start, size; + char *k = strchr(str, ','); + + if (k) + *k++ = 0; + + oldstr = str; + size = memparse(str, &str); + if (str == oldstr || *str != '$') { + efi_warn("memap values error.\n"); + break; + } + + start = memparse(str + 1, &str); + if (size <= 0) { + efi_warn("memap values error, size should be more than 0.\n"); + break; + } + + mem_avoid[MAX_MEMMAP_REGIONS_BEGIN + i].start = start; + mem_avoid[MAX_MEMMAP_REGIONS_BEGIN + i].size = size; + str = k; + i++; + } +} #endif /* * Return the number of slots covered by this entry, i.e., the number of -- Gitee From 9bac1dbc97a6d5af7af0784e7b46b522fdf11b70 Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Tue, 26 Dec 2023 17:23:16 +0800 Subject: [PATCH 4/6] efi/libstub: add arm64 nokaslr memory regions hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA -------------------------------- allow users to mark at most 4 regions as not available for kaslr Signed-off-by: Felix Fu --- .../firmware/efi/libstub/efi-stub-helper.c | 7 +++- drivers/firmware/efi/libstub/efistub.h | 1 + drivers/firmware/efi/libstub/randomalloc.c | 35 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 62bfe1a3e002..8f31804d2147 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -68,7 +68,12 @@ efi_status_t efi_parse_options(char const *cmdline) break; if (!strcmp(param, "nokaslr")) { - efi_nokaslr = true; +#if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) + if (val) + mem_avoid_mem_nokaslr(val); + else +#endif + efi_nokaslr = true; } else if (!strcmp(param, "quiet")) { efi_loglevel = CONSOLE_LOGLEVEL_QUIET; } else if (!strcmp(param, "noinitrd")) { diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 10dbb82b8254..1a70c9e45aba 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1002,6 +1002,7 @@ void efi_parse_option_graphics(char *option); #if defined (CONFIG_KASLR_SKIP_MEM_RANGE) && defined (CONFIG_ARM64) void mem_avoid_memmap(char *str); +void mem_avoid_mem_nokaslr(char *str); #endif efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto, diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c index ecbdba2ae347..39cd2e4894e3 100644 --- a/drivers/firmware/efi/libstub/randomalloc.c +++ b/drivers/firmware/efi/libstub/randomalloc.c @@ -14,10 +14,13 @@ #define CAL_SLOTS_PHYADDR 1 #define MAX_MEMMAP_REGIONS 32 +#define MAX_MEM_NOKASLR_REGIONS 4 enum mem_avoid_index { MAX_MEMMAP_REGIONS_BEGIN = 0, MAX_MEMMAP_REGIONS_END = MAX_MEMMAP_REGIONS_BEGIN + MAX_MEMMAP_REGIONS - 1, + MEM_AVOID_MEM_NOKASLR_BEGIN, + MEM_AVOID_MEM_NOKASLR_END = MEM_AVOID_MEM_NOKASLR_BEGIN + MAX_MEM_NOKASLR_REGIONS - 1, MEM_AVOID_MAX, }; @@ -135,6 +138,38 @@ void mem_avoid_memmap(char *str) i++; } } + +void mem_avoid_mem_nokaslr(char *str) +{ + int i = 0; + + while (str && (i < MAX_MEM_NOKASLR_REGIONS)) { + char *oldstr; + u64 start, end; + char *k = strchr(str, ','); + + if (k) + *k++ = 0; + + oldstr = str; + start = memparse(str, &str); + if (str == oldstr || *str != '-') { + efi_warn("nokaslr values error.\n"); + break; + } + + end = memparse(str + 1, &str); + if (start >= end) { + efi_warn("nokaslr values error, start should be less than end.\n"); + break; + } + + mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].start = start; + mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].size = end - start; + str = k; + i++; + } +} #endif /* * Return the number of slots covered by this entry, i.e., the number of -- Gitee From 426e9a5104a0d90d65d3a27aa4cf246c557331ea Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Tue, 26 Dec 2023 17:23:17 +0800 Subject: [PATCH 5/6] x86/boot: add x86 nokaslr memory regions hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA -------------------------------- allow users to mark at most 4 regions as not available for kaslr Signed-off-by: Felix Fu --- arch/x86/Kconfig | 12 +++++++++ arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 66bfabae8814..dcbf0e5534ba 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2155,6 +2155,18 @@ config RANDOMIZE_BASE If unsure, say Y. +config KASLR_SKIP_MEM_RANGE + bool "Skip specified memory range when randomize the kernel image" + depends on RANDOMIZE_BASE + default n + help + Skip specified memory range when randomize the kernel image. This + feature support nokalsr kernel parameter in x86. Nokaslr kernel + parameters are described by the nokaslr=nn[KMG]-ss[KMG]. + Region of memory to be reserved is from nn to ss. The region must + be in the range of existed memory, otherwise will be ignored.This + feature support up to 4 nokaslr regions. + # Relocation on x86 needs some additional build support config X86_NEED_RELOCS def_bool y diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 9193acf0e9cd..bdf28859ef8d 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -75,6 +75,10 @@ static unsigned long get_boot_seed(void) /* Only supporting at most 4 unusable memmap regions with kaslr */ #define MAX_MEMMAP_REGIONS 4 +#ifdef CONFIG_KASLR_SKIP_MEM_RANGE +#define MAX_MEM_NOKASLR_REGIONS 4 +#endif + static bool memmap_too_large; @@ -94,6 +98,10 @@ enum mem_avoid_index { MEM_AVOID_BOOTPARAMS, MEM_AVOID_MEMMAP_BEGIN, MEM_AVOID_MEMMAP_END = MEM_AVOID_MEMMAP_BEGIN + MAX_MEMMAP_REGIONS - 1, +#ifdef CONFIG_KASLR_SKIP_MEM_RANGE + MEM_AVOID_MEM_NOKASLR_BEGIN, + MEM_AVOID_MEM_NOKASLR_END = MEM_AVOID_MEM_NOKASLR_BEGIN + MAX_MEM_NOKASLR_REGIONS - 1, +#endif MEM_AVOID_MAX, }; @@ -223,6 +231,39 @@ static void mem_avoid_memmap(enum parse_mode mode, char *str) memmap_too_large = true; } +#ifdef CONFIG_KASLR_SKIP_MEM_RANGE +static void mem_avoid_mem_nokaslr(char *str) +{ + int i = 0; + + while (str && (i < MAX_MEM_NOKASLR_REGIONS)) { + char *oldstr; + u64 start, end; + char *k = strchr(str, ','); + + if (k) + *k++ = 0; + + oldstr = str; + start = memparse(str, &str); + if (str == oldstr || *str != '-') { + warn("Nokaslr values error.\n"); + break; + } + + end = memparse(str + 1, &str); + if (start >= end) { + warn("Nokaslr values error, start should be less than end.\n"); + break; + } + + mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].start = start; + mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].size = end - start; + str = k; + i++; + } +} +#endif /* Store the number of 1GB huge pages which users specified: */ static unsigned long max_gb_huge_pages; @@ -298,6 +339,10 @@ static void handle_mem_options(void) } else if (!strcmp(param, "efi_fake_mem")) { mem_avoid_memmap(PARSE_EFI, val); } +#ifdef CONFIG_KASLR_SKIP_MEM_RANGE + else if (!strcmp(param, "nokaslr") && val) + mem_avoid_mem_nokaslr(val); +#endif } free(tmp_cmdline); -- Gitee From 95019500e821bc604a70cfc6ad5b818b73738af1 Mon Sep 17 00:00:00 2001 From: Felix Fu Date: Wed, 3 Jan 2024 11:45:39 +0800 Subject: [PATCH 6/6] kaslr: enable CONFIG_SKIP_KASLR_MEM_RANGE in openeuler defconfig hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8RJ1I CVE: NA -------------------------------- enable CONFIG_SKIP_KASLR_MEM_RANGE in openeuler defconfig of x86 and arm64 Signed-off-by: Felix Fu --- arch/arm64/configs/openeuler_defconfig | 1 + arch/x86/configs/openeuler_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 0312c2d082df..c3d9c5c77c7a 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -519,6 +519,7 @@ CONFIG_ARM64_PSEUDO_NMI=y # CONFIG_ARM64_DEBUG_PRIORITY_MASKING is not set CONFIG_RELOCATABLE=y CONFIG_RANDOMIZE_BASE=y +CONFIG_KASLR_SKIP_MEM_RANGE=y CONFIG_RANDOMIZE_MODULE_REGION_FULL=y CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y CONFIG_STACKPROTECTOR_PER_TASK=y diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index 9948d6c918df..1bf18b7b0e94 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -494,6 +494,7 @@ CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y CONFIG_PHYSICAL_START=0x1000000 CONFIG_RELOCATABLE=y CONFIG_RANDOMIZE_BASE=y +CONFIG_KASLR_SKIP_MEM_RANGE=y CONFIG_X86_NEED_RELOCS=y CONFIG_PHYSICAL_ALIGN=0x200000 CONFIG_DYNAMIC_MEMORY_LAYOUT=y -- Gitee