The following KASLR implementation allows to randomize the kernel mapping:
- virtually: we expect the bootloader to provide a seed in the device-tree
- physically: only implemented in the EFI stub, it relies on the firmware to
provide a seed using EFI_RNG_PROTOCOL. arm64 has a similar implementation
hence the patch 3 factorizes KASLR related functions for riscv to take
advantage.
The new virtual kernel location is limited by the early page table that only
has one PUD and with the PMD alignment constraint, the kernel can only take
< 512 positions.
base-commit-tag: v6.4-rc2
Changes in v3:
* Rebase on top of 6.4-rc2
* Make RANDOMIZE_BASE depend on 64bit
* Fix efi_icache_sync and efi_get_kimg_min_align which were undefined
in x86 (and certainly other archs)
* Add patch 4 to fix warning on rv32
Changes in v2:
* Rebase on top of 6.3-rc1
* Add a riscv cache sync after memcpying the kernel
* Add kaslr_offset implementation for KCOV
* Add forward declaration to quiet LLVM
Alexandre Ghiti (5):
riscv: Introduce virtual kernel mapping KASLR
riscv: Dump out kernel offset information on panic
arm64: libstub: Move KASLR handling functions to efi-stub-helper.c
libstub: Fix compilation warning for rv32
riscv: libstub: Implement KASLR by using generic functions
arch/arm64/include/asm/efi.h | 4 +
arch/riscv/Kconfig | 19 +++
arch/riscv/include/asm/efi.h | 4 +
arch/riscv/include/asm/page.h | 3 +
arch/riscv/kernel/image-vars.h | 1 +
arch/riscv/kernel/pi/Makefile | 2 +-
arch/riscv/kernel/pi/cmdline_early.c | 13 ++
arch/riscv/kernel/pi/fdt_early.c | 30 ++++
arch/riscv/kernel/setup.c | 25 +++
arch/riscv/mm/init.c | 36 ++++-
drivers/firmware/efi/libstub/arm64-stub.c | 112 +------------
drivers/firmware/efi/libstub/arm64.c | 5 +
.../firmware/efi/libstub/efi-stub-helper.c | 151 ++++++++++++++++++
drivers/firmware/efi/libstub/efistub.h | 18 +++
drivers/firmware/efi/libstub/riscv-stub.c | 28 ++--
drivers/firmware/efi/libstub/riscv.c | 5 +
16 files changed, 332 insertions(+), 124 deletions(-)
create mode 100644 arch/riscv/kernel/pi/fdt_early.c
--
2.39.2
Fix the following warning which appears when compiled for rv32 by using
unsigned long type instead of u64.
../drivers/firmware/efi/libstub/efi-stub-helper.c: In function 'efi_kaslr_relocate_kernel':
../drivers/firmware/efi/libstub/efi-stub-helper.c:846:28: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
846 | (u64)_end < EFI_ALLOC_LIMIT) {
Signed-off-by: Alexandre Ghiti <[email protected]>
---
drivers/firmware/efi/libstub/efi-stub-helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index a5c61a768d59..029d1581db72 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -842,7 +842,7 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
if (!check_image_region(*image_addr, kernel_memsize)) {
efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
} else if (IS_ALIGNED(*image_addr, min_kimg_align) &&
- (u64)_end < EFI_ALLOC_LIMIT) {
+ (unsigned long)_end < EFI_ALLOC_LIMIT) {
/*
* Just execute from wherever we were loaded by the
* UEFI PE/COFF loader if the placement is suitable.
--
2.39.2
This prepares for riscv to use the same functions to handle the pĥysical
kernel move when KASLR is enabled.
Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/arm64/include/asm/efi.h | 1 +
arch/riscv/include/asm/efi.h | 1 +
drivers/firmware/efi/libstub/arm64-stub.c | 112 +------------
.../firmware/efi/libstub/efi-stub-helper.c | 151 ++++++++++++++++++
drivers/firmware/efi/libstub/efistub.h | 13 ++
5 files changed, 174 insertions(+), 104 deletions(-)
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index f86b157a5da3..1870af1bc42e 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -111,6 +111,7 @@ static inline unsigned long efi_get_kimg_min_align(void)
*/
return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
}
+#define efi_get_kimg_min_align efi_get_kimg_min_align
#define EFI_ALLOC_ALIGN SZ_64K
#define EFI_ALLOC_LIMIT ((1UL << 48) - 1)
diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h
index 29e9a0d84b16..c3dafaab36a2 100644
--- a/arch/riscv/include/asm/efi.h
+++ b/arch/riscv/include/asm/efi.h
@@ -43,6 +43,7 @@ static inline unsigned long efi_get_kimg_min_align(void)
*/
return IS_ENABLED(CONFIG_64BIT) ? SZ_2M : SZ_4M;
}
+#define efi_get_kimg_min_align efi_get_kimg_min_align
#define EFI_KIMG_PREFERRED_ADDRESS efi_get_kimg_min_align()
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 770b8ecb7398..de4a64f05c07 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -14,42 +14,6 @@
#include "efistub.h"
-/*
- * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
- * to provide space, and fail to zero it). Check for this condition by double
- * checking that the first and the last byte of the image are covered by the
- * same EFI memory map entry.
- */
-static bool check_image_region(u64 base, u64 size)
-{
- struct efi_boot_memmap *map;
- efi_status_t status;
- bool ret = false;
- int map_offset;
-
- status = efi_get_memory_map(&map, false);
- if (status != EFI_SUCCESS)
- return false;
-
- for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
- efi_memory_desc_t *md = (void *)map->map + map_offset;
- u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
-
- /*
- * Find the region that covers base, and return whether
- * it covers base+size bytes.
- */
- if (base >= md->phys_addr && base < end) {
- ret = (base + size) <= end;
- break;
- }
- }
-
- efi_bs_call(free_pool, map);
-
- return ret;
-}
-
efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,
@@ -59,31 +23,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
{
efi_status_t status;
unsigned long kernel_size, kernel_codesize, kernel_memsize;
- u32 phys_seed = 0;
- u64 min_kimg_align = efi_get_kimg_min_align();
-
- if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
- efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;
- void *p;
-
- if (efi_nokaslr) {
- efi_info("KASLR disabled on kernel command line\n");
- } else if (efi_bs_call(handle_protocol, image_handle,
- &li_fixed_proto, &p) == EFI_SUCCESS) {
- efi_info("Image placement fixed by loader\n");
- } else {
- status = efi_get_random_bytes(sizeof(phys_seed),
- (u8 *)&phys_seed);
- if (status == EFI_NOT_FOUND) {
- efi_info("EFI_RNG_PROTOCOL unavailable\n");
- efi_nokaslr = true;
- } else if (status != EFI_SUCCESS) {
- efi_err("efi_get_random_bytes() failed (0x%lx)\n",
- status);
- efi_nokaslr = true;
- }
- }
- }
if (image->image_base != _text) {
efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
@@ -98,50 +37,15 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
kernel_codesize = __inittext_end - _text;
kernel_memsize = kernel_size + (_end - _edata);
*reserve_size = kernel_memsize;
+ *image_addr = (unsigned long)_text;
- if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
- /*
- * 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,
- reserve_addr, phys_seed,
- EFI_LOADER_CODE);
- if (status != EFI_SUCCESS)
- efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
- } else {
- status = EFI_OUT_OF_RESOURCES;
- }
-
- 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) &&
- (u64)_end < EFI_ALLOC_LIMIT) {
- /*
- * Just execute from wherever we were loaded by the
- * UEFI PE/COFF loader if the placement is suitable.
- */
- *image_addr = (u64)_text;
- *reserve_size = 0;
- return EFI_SUCCESS;
- }
-
- status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
- ULONG_MAX, min_kimg_align,
- EFI_LOADER_CODE);
-
- if (status != EFI_SUCCESS) {
- efi_err("Failed to relocate kernel\n");
- *reserve_size = 0;
- return status;
- }
- }
-
- *image_addr = *reserve_addr;
- memcpy((void *)*image_addr, _text, kernel_size);
- caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
- efi_remap_image(*image_addr, *reserve_size, kernel_codesize);
+ status = efi_kaslr_relocate_kernel(image_addr,
+ reserve_addr, reserve_size,
+ kernel_size, kernel_codesize,
+ kernel_memsize,
+ efi_kaslr_get_phys_seed(image_handle));
+ if (status != EFI_SUCCESS)
+ return status;
return EFI_SUCCESS;
}
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 1e0203d74691..a5c61a768d59 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -718,3 +718,154 @@ void efi_remap_image(unsigned long image_base, unsigned alloc_size,
efi_warn("Failed to remap data region non-executable\n");
}
}
+
+/**
+ * efi_kaslr_get_phys_seed() - Get random seed for physical kernel KASLR
+ * @image_handle: Handle to the image
+ *
+ * If KASLR is not disabled, obtain a random seed using EFI_RNG_PROTOCOL
+ * that will be used to move the kernel physical mapping.
+ *
+ * Return: the random seed
+ */
+u32 efi_kaslr_get_phys_seed(efi_handle_t image_handle)
+{
+ efi_status_t status;
+ u32 phys_seed;
+ efi_guid_t li_fixed_proto = LINUX_EFI_LOADED_IMAGE_FIXED_GUID;
+ void *p;
+
+ if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE))
+ return 0;
+
+ if (efi_nokaslr) {
+ efi_info("KASLR disabled on kernel command line\n");
+ } else if (efi_bs_call(handle_protocol, image_handle,
+ &li_fixed_proto, &p) == EFI_SUCCESS) {
+ efi_info("Image placement fixed by loader\n");
+ } else {
+ status = efi_get_random_bytes(sizeof(phys_seed),
+ (u8 *)&phys_seed);
+ if (status == EFI_SUCCESS) {
+ return phys_seed;
+ } else if (status == EFI_NOT_FOUND) {
+ efi_info("EFI_RNG_PROTOCOL unavailable\n");
+ efi_nokaslr = true;
+ } else if (status != EFI_SUCCESS) {
+ efi_err("efi_get_random_bytes() failed (0x%lx)\n",
+ status);
+ efi_nokaslr = true;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
+ * to provide space, and fail to zero it). Check for this condition by double
+ * checking that the first and the last byte of the image are covered by the
+ * same EFI memory map entry.
+ */
+static bool check_image_region(u64 base, u64 size)
+{
+ struct efi_boot_memmap *map;
+ efi_status_t status;
+ bool ret = false;
+ int map_offset;
+
+ status = efi_get_memory_map(&map, false);
+ if (status != EFI_SUCCESS)
+ return false;
+
+ for (map_offset = 0; map_offset < map->map_size; map_offset += map->desc_size) {
+ efi_memory_desc_t *md = (void *)map->map + map_offset;
+ u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
+
+ /*
+ * Find the region that covers base, and return whether
+ * it covers base+size bytes.
+ */
+ if (base >= md->phys_addr && base < end) {
+ ret = (base + size) <= end;
+ break;
+ }
+ }
+
+ efi_bs_call(free_pool, map);
+
+ return ret;
+}
+
+/**
+ * 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
+ * @kernel_size: Size of the text + data
+ * @kernel_codesize: Size of the text
+ * @kernel_memsize: Size of the text + data + bss
+ * @phys_seed: Random seed used for the relocation
+ *
+ * If KASLR is not enabled, this function relocates the kernel to a fixed
+ * address (or leave it as its current location). If KASLR is enabled, the
+ * kernel physical location is randomized using the seed in parameter.
+ *
+ * Return: status code, EFI_SUCCESS if relocation is successful
+ */
+efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
+ unsigned long *reserve_addr,
+ unsigned long *reserve_size,
+ unsigned long kernel_size,
+ unsigned long kernel_codesize,
+ unsigned long kernel_memsize,
+ u32 phys_seed)
+{
+ efi_status_t status;
+ u64 min_kimg_align = efi_get_kimg_min_align();
+
+ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
+ /*
+ * 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,
+ reserve_addr, phys_seed,
+ EFI_LOADER_CODE);
+ if (status != EFI_SUCCESS)
+ efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
+ } else {
+ status = EFI_OUT_OF_RESOURCES;
+ }
+
+ if (status != EFI_SUCCESS) {
+ if (!check_image_region(*image_addr, kernel_memsize)) {
+ efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
+ } else if (IS_ALIGNED(*image_addr, min_kimg_align) &&
+ (u64)_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;
+ }
+
+ status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
+ ULONG_MAX, min_kimg_align,
+ EFI_LOADER_CODE);
+
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to relocate kernel\n");
+ *reserve_size = 0;
+ return status;
+ }
+ }
+
+ memcpy((void *)*reserve_addr, (void *)*image_addr, kernel_size);
+ *image_addr = *reserve_addr;
+ caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
+ efi_remap_image(*image_addr, *reserve_size, kernel_codesize);
+
+ return status;
+}
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 67d5a20802e0..502f53100453 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1132,5 +1132,18 @@ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
void efi_remap_image(unsigned long image_base, unsigned alloc_size,
unsigned long code_size);
+efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
+ unsigned long *reserve_addr,
+ unsigned long *reserve_size,
+ unsigned long kernel_size,
+ unsigned long kernel_codesize,
+ unsigned long kernel_memsize,
+ u32 phys_seed);
+u32 efi_kaslr_get_phys_seed(efi_handle_t image_handle);
+
+#ifndef efi_get_kimg_min_align
+static inline unsigned long efi_get_kimg_min_align(void) {}
+#define efi_get_kimg_min_align efi_get_kimg_min_align
+#endif
#endif
--
2.39.2
Dump out the KASLR virtual kernel offset when panic to help debug kernel.
Signed-off-by: Zong Li <[email protected]>
Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/riscv/kernel/setup.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 36b026057503..ae5c4c2971ca 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -20,6 +20,7 @@
#include <linux/smp.h>
#include <linux/efi.h>
#include <linux/crash_dump.h>
+#include <linux/panic_notifier.h>
#include <asm/alternative.h>
#include <asm/cacheflush.h>
@@ -329,3 +330,27 @@ void free_initmem(void)
free_initmem_default(POISON_FREE_INITMEM);
}
+
+static int dump_kernel_offset(struct notifier_block *self,
+ unsigned long v, void *p)
+{
+ pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
+ kernel_map.virt_offset,
+ KERNEL_LINK_ADDR);
+
+ return 0;
+}
+
+static struct notifier_block kernel_offset_notifier = {
+ .notifier_call = dump_kernel_offset
+};
+
+static int __init register_kernel_offset_dumper(void)
+{
+ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &kernel_offset_notifier);
+
+ return 0;
+}
+device_initcall(register_kernel_offset_dumper);
--
2.39.2
We can now use arm64 functions to handle the move of the kernel physical
mapping: if KASLR is enabled, we will try to get a random seed from the
firmware, if not possible, the kernel will be moved to a location that
suits its alignment constraints.
Signed-off-by: Alexandre Ghiti <[email protected]>
---
arch/arm64/include/asm/efi.h | 3 ++
arch/riscv/include/asm/efi.h | 3 ++
arch/riscv/kernel/image-vars.h | 1 +
drivers/firmware/efi/libstub/arm64.c | 5 ++++
.../firmware/efi/libstub/efi-stub-helper.c | 2 +-
drivers/firmware/efi/libstub/efistub.h | 5 ++++
drivers/firmware/efi/libstub/riscv-stub.c | 28 +++++++------------
drivers/firmware/efi/libstub/riscv.c | 5 ++++
8 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 1870af1bc42e..796ac51d1f27 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -167,4 +167,7 @@ static inline void efi_capsule_flush_cache_range(void *addr, int size)
dcache_clean_inval_poc((unsigned long)addr, (unsigned long)addr + size);
}
+void efi_icache_sync(unsigned long start, unsigned long end);
+#define efi_icache_sync efi_icache_sync
+
#endif /* _ASM_EFI_H */
diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h
index c3dafaab36a2..6f99e8812dfd 100644
--- a/arch/riscv/include/asm/efi.h
+++ b/arch/riscv/include/asm/efi.h
@@ -52,4 +52,7 @@ void efi_virtmap_unload(void);
unsigned long stext_offset(void);
+void efi_icache_sync(unsigned long start, unsigned long end);
+#define efi_icache_sync efi_icache_sync
+
#endif /* _ASM_EFI_H */
diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h
index 15616155008c..ea1a10355ce9 100644
--- a/arch/riscv/kernel/image-vars.h
+++ b/arch/riscv/kernel/image-vars.h
@@ -27,6 +27,7 @@ __efistub__start = _start;
__efistub__start_kernel = _start_kernel;
__efistub__end = _end;
__efistub__edata = _edata;
+__efistub___init_text_end = __init_text_end;
__efistub_screen_info = screen_info;
#endif
diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
index 446e35eaf3d9..88c2fd092951 100644
--- a/drivers/firmware/efi/libstub/arm64.c
+++ b/drivers/firmware/efi/libstub/arm64.c
@@ -138,3 +138,8 @@ void __noreturn efi_enter_kernel(unsigned long entrypoint,
enter_kernel = (void *)entrypoint + primary_entry_offset();
enter_kernel(fdt_addr, 0, 0, 0);
}
+
+void efi_icache_sync(unsigned long start, unsigned long end)
+{
+ caches_clean_inval_pou(start, end);
+}
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 029d1581db72..812ac2111786 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -864,7 +864,7 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
memcpy((void *)*reserve_addr, (void *)*image_addr, kernel_size);
*image_addr = *reserve_addr;
- caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
+ efi_icache_sync(*image_addr, *image_addr + kernel_codesize);
efi_remap_image(*image_addr, *reserve_size, kernel_codesize);
return status;
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 502f53100453..89c08d3e94b2 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1146,4 +1146,9 @@ static inline unsigned long efi_get_kimg_min_align(void) {}
#define efi_get_kimg_min_align efi_get_kimg_min_align
#endif
+#ifndef efi_icache_sync
+static inline void efi_icache_sync(unsigned long start, unsigned long end) {}
+#define efi_icache_sync efi_icache_sync
+#endif
+
#endif
diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c
index 145c9f0ba217..7af07b33a993 100644
--- a/drivers/firmware/efi/libstub/riscv-stub.c
+++ b/drivers/firmware/efi/libstub/riscv-stub.c
@@ -30,32 +30,24 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_loaded_image_t *image,
efi_handle_t image_handle)
{
- unsigned long kernel_size = 0;
- unsigned long preferred_addr;
+ unsigned long kernel_size, kernel_codesize, kernel_memsize;
efi_status_t status;
kernel_size = _edata - _start;
+ kernel_codesize = __init_text_end - _start;
+ kernel_memsize = kernel_size + (_end - _edata);
*image_addr = (unsigned long)_start;
- *image_size = kernel_size + (_end - _edata);
-
- /*
- * RISC-V kernel maps PAGE_OFFSET virtual address to the same physical
- * address where kernel is booted. That's why kernel should boot from
- * as low as possible to avoid wastage of memory. Currently, dram_base
- * is occupied by the firmware. So the preferred address for kernel to
- * boot is next aligned address. If preferred address is not available,
- * relocate_kernel will fall back to efi_low_alloc_above to allocate
- * lowest possible memory region as long as the address and size meets
- * the alignment constraints.
- */
- preferred_addr = EFI_KIMG_PREFERRED_ADDRESS;
- status = efi_relocate_kernel(image_addr, kernel_size, *image_size,
- preferred_addr, efi_get_kimg_min_align(),
- 0x0);
+ *image_size = kernel_memsize;
+ *reserve_size = *image_size;
+ status = efi_kaslr_relocate_kernel(image_addr,
+ reserve_addr, reserve_size,
+ kernel_size, kernel_codesize, kernel_memsize,
+ efi_kaslr_get_phys_seed(image_handle));
if (status != EFI_SUCCESS) {
efi_err("Failed to relocate kernel\n");
*image_size = 0;
}
+
return status;
}
diff --git a/drivers/firmware/efi/libstub/riscv.c b/drivers/firmware/efi/libstub/riscv.c
index 8022b104c3e6..365f891e598f 100644
--- a/drivers/firmware/efi/libstub/riscv.c
+++ b/drivers/firmware/efi/libstub/riscv.c
@@ -96,3 +96,8 @@ void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt,
csr_write(CSR_SATP, 0);
jump_kernel(hartid, fdt);
}
+
+void efi_icache_sync(unsigned long start, unsigned long end)
+{
+ asm volatile ("fence.i" ::: "memory");
+}
--
2.39.2
Hi Alexandre,
kernel test robot noticed the following build warnings:
[auto build test WARNING on efi/next]
[also build test WARNING on linus/master v6.4-rc5 next-20230606]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexandre-Ghiti/riscv-Introduce-virtual-kernel-mapping-KASLR/20230606-203849
base: https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git next
patch link: https://lore.kernel.org/r/20230606123242.20804-4-alexghiti%40rivosinc.com
patch subject: [PATCH v3 3/5] arm64: libstub: Move KASLR handling functions to efi-stub-helper.c
config: i386-randconfig-i063-20230607 (https://download.01.org/0day-ci/archive/20230607/[email protected]/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce (this is a W=1 build):
mkdir -p ~/bin
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git remote add efi https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
git fetch efi next
git checkout efi/next
b4 shazam https://lore.kernel.org/r/[email protected]
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=i386 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/firmware/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
In file included from drivers/firmware/efi/libstub/x86-stub.c:19:
>> drivers/firmware/efi/libstub/efistub.h:1145:59: warning: non-void function does not return a value [-Wreturn-type]
static inline unsigned long efi_get_kimg_min_align(void) {}
^
1 warning generated.
--
In file included from drivers/firmware/efi/libstub/efi-stub-helper.c:17:
>> drivers/firmware/efi/libstub/efistub.h:1145:59: warning: non-void function does not return a value [-Wreturn-type]
static inline unsigned long efi_get_kimg_min_align(void) {}
^
drivers/firmware/efi/libstub/efi-stub-helper.c:867:2: warning: call to undeclared function 'caches_clean_inval_pou'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
caches_clean_inval_pou(*image_addr, *image_addr + kernel_codesize);
^
2 warnings generated.
vim +1145 drivers/firmware/efi/libstub/efistub.h
1143
1144 #ifndef efi_get_kimg_min_align
> 1145 static inline unsigned long efi_get_kimg_min_align(void) {}
1146 #define efi_get_kimg_min_align efi_get_kimg_min_align
1147 #endif
1148
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Alexandre,
kernel test robot noticed the following build errors:
[auto build test ERROR on efi/next]
[also build test ERROR on linus/master v6.4-rc5 next-20230607]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexandre-Ghiti/riscv-Introduce-virtual-kernel-mapping-KASLR/20230606-203849
base: https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git next
patch link: https://lore.kernel.org/r/20230606123242.20804-4-alexghiti%40rivosinc.com
patch subject: [PATCH v3 3/5] arm64: libstub: Move KASLR handling functions to efi-stub-helper.c
config: arm64-allyesconfig (https://download.01.org/0day-ci/archive/20230608/[email protected]/config)
compiler: aarch64-linux-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
mkdir -p ~/bin
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git remote add efi https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
git fetch efi next
git checkout efi/next
b4 shazam https://lore.kernel.org/r/[email protected]
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm64 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
aarch64-linux-ld: drivers/firmware/efi/libstub/efi-stub-helper.stub.o: in function `__efistub_efi_kaslr_relocate_kernel':
>> __efistub_efi-stub-helper.c:(.init.text+0xfec): undefined reference to `__efistub__end'
>> aarch64-linux-ld: __efistub_efi-stub-helper.c:(.init.text+0xff0): undefined reference to `__efistub__end'
aarch64-linux-ld: __efistub_efi-stub-helper.c:(.init.text+0x1058): undefined reference to `__efistub_caches_clean_inval_pou'
aarch64-linux-ld: arch/arm64/boot/vmlinuz.efi.elf: hidden symbol `__efistub__end' isn't defined
aarch64-linux-ld: final link failed: bad value
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
On Tue, 06 Jun 2023 05:32:37 PDT (-0700), [email protected] wrote:
> The following KASLR implementation allows to randomize the kernel mapping:
>
> - virtually: we expect the bootloader to provide a seed in the device-tree
> - physically: only implemented in the EFI stub, it relies on the firmware to
> provide a seed using EFI_RNG_PROTOCOL. arm64 has a similar implementation
> hence the patch 3 factorizes KASLR related functions for riscv to take
> advantage.
>
> The new virtual kernel location is limited by the early page table that only
> has one PUD and with the PMD alignment constraint, the kernel can only take
> < 512 positions.
>
> base-commit-tag: v6.4-rc2
>
> Changes in v3:
> * Rebase on top of 6.4-rc2
> * Make RANDOMIZE_BASE depend on 64bit
> * Fix efi_icache_sync and efi_get_kimg_min_align which were undefined
> in x86 (and certainly other archs)
> * Add patch 4 to fix warning on rv32
>
> Changes in v2:
> * Rebase on top of 6.3-rc1
> * Add a riscv cache sync after memcpying the kernel
> * Add kaslr_offset implementation for KCOV
> * Add forward declaration to quiet LLVM
>
> Alexandre Ghiti (5):
> riscv: Introduce virtual kernel mapping KASLR
> riscv: Dump out kernel offset information on panic
> arm64: libstub: Move KASLR handling functions to efi-stub-helper.c
> libstub: Fix compilation warning for rv32
> riscv: libstub: Implement KASLR by using generic functions
>
> arch/arm64/include/asm/efi.h | 4 +
> arch/riscv/Kconfig | 19 +++
> arch/riscv/include/asm/efi.h | 4 +
> arch/riscv/include/asm/page.h | 3 +
> arch/riscv/kernel/image-vars.h | 1 +
> arch/riscv/kernel/pi/Makefile | 2 +-
> arch/riscv/kernel/pi/cmdline_early.c | 13 ++
> arch/riscv/kernel/pi/fdt_early.c | 30 ++++
> arch/riscv/kernel/setup.c | 25 +++
> arch/riscv/mm/init.c | 36 ++++-
> drivers/firmware/efi/libstub/arm64-stub.c | 112 +------------
> drivers/firmware/efi/libstub/arm64.c | 5 +
> .../firmware/efi/libstub/efi-stub-helper.c | 151 ++++++++++++++++++
> drivers/firmware/efi/libstub/efistub.h | 18 +++
> drivers/firmware/efi/libstub/riscv-stub.c | 28 ++--
> drivers/firmware/efi/libstub/riscv.c | 5 +
> 16 files changed, 332 insertions(+), 124 deletions(-)
> create mode 100644 arch/riscv/kernel/pi/fdt_early.c
I'm marking this one as changes requested as well as LKP is pointing at
some build failures. It also touches libstub so I'd really prefer an
Ack, but folks might not be looking with the build issues.