2023-02-07 14:29:38

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 0/5] LoongArch: Add kernel relocation and KASLR support

This patch series to support kernel relocation and KASLR (only 64bit).

I've only tested new toolchains (CONFIG_AS_HAS_EXPLICIT_RELOCS=y)
consisted of Binutils-2.40, and GCC-12.2 heavily patched to support new
relocs. Unfortunately I've purged my old toolchain installation (because
it contained a buggy GCC-12.1 miscompiling some code). Please test the
configuration with old toolchain.

Test results with CONFIG_RANDOMIZE_BASE=y on a 3A5000-7A2000-EVB:

First boot:

$ sudo cat /proc/iomem | grep Kernel
010e0000-018fffff : Kernel code
01900000-01e4b5ff : Kernel data
01e4b600-01f56e9f : Kernel bss

Second boot:

$ sudo cat /proc/iomem | grep Kernel
019a0000-021bffff : Kernel code
021c0000-0270b5ff : Kernel data
0270b600-02816e9f : Kernel bss

Changes from v1:

- Relocate the handlers instead of using a trampoline, to avoid
performance issue on NUMA systems.
- Fix compiler warnings.

Xi Ruoyao (2):
LoongArch: Use la.pcrel instead of la.abs when it's trivially possible
LoongArch: Use la.pcrel instead of la.abs for exception handlers

Youling Tang (3):
LoongArch: Add JUMP_LINK_ADDR macro implementation to avoid using
la.abs
LoongArch: Add support for kernel relocation
LoongArch: Add support for kernel address space layout randomization
(KASLR)

arch/loongarch/Kconfig | 37 +++++
arch/loongarch/Makefile | 5 +
arch/loongarch/include/asm/page.h | 6 +
arch/loongarch/include/asm/setup.h | 6 +-
arch/loongarch/include/asm/stackframe.h | 13 +-
arch/loongarch/include/asm/uaccess.h | 1 -
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/entry.S | 2 +-
arch/loongarch/kernel/genex.S | 40 ++++-
arch/loongarch/kernel/head.S | 30 +++-
arch/loongarch/kernel/relocate.c | 211 ++++++++++++++++++++++++
arch/loongarch/kernel/setup.c | 3 +
arch/loongarch/kernel/traps.c | 138 +++++++++++++---
arch/loongarch/kernel/vmlinux.lds.S | 11 +-
arch/loongarch/mm/tlb.c | 23 +--
arch/loongarch/mm/tlbex.S | 72 +++++++-
arch/loongarch/power/suspend_asm.S | 5 +-
17 files changed, 543 insertions(+), 62 deletions(-)
create mode 100644 arch/loongarch/kernel/relocate.c

--
2.37.0



2023-02-07 14:30:45

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 1/5] LoongArch: Use la.pcrel instead of la.abs when it's trivially possible

Let's start to kill la.abs inpreparation for the subsequent support of the
PIE kernel.

Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/include/asm/stackframe.h | 2 +-
arch/loongarch/include/asm/uaccess.h | 1 -
arch/loongarch/kernel/entry.S | 2 +-
arch/loongarch/kernel/head.S | 2 +-
arch/loongarch/mm/tlbex.S | 3 +--
5 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index 4ca953062b5b..7deb043ce387 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -90,7 +90,7 @@
.endm

.macro set_saved_sp stackp temp temp2
- la.abs \temp, kernelsp
+ la.pcrel \temp, kernelsp
#ifdef CONFIG_SMP
LONG_ADD \temp, \temp, u0
#endif
diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
index 255899d4a7c3..0d22991ae430 100644
--- a/arch/loongarch/include/asm/uaccess.h
+++ b/arch/loongarch/include/asm/uaccess.h
@@ -22,7 +22,6 @@
extern u64 __ua_limit;

#define __UA_ADDR ".dword"
-#define __UA_LA "la.abs"
#define __UA_LIMIT __ua_limit

/*
diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
index d53b631c9022..2566977f2f68 100644
--- a/arch/loongarch/kernel/entry.S
+++ b/arch/loongarch/kernel/entry.S
@@ -20,7 +20,7 @@
.align 5
SYM_FUNC_START(handle_syscall)
csrrd t0, PERCPU_BASE_KS
- la.abs t1, kernelsp
+ la.pcrel t1, kernelsp
add.d t1, t1, t0
move t2, sp
ld.d sp, t1, 0
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 57bada6b4e93..aa6181714ec3 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -117,7 +117,7 @@ SYM_CODE_START(smpboot_entry)
li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
csrwr t0, LOONGARCH_CSR_EUEN

- la.abs t0, cpuboot_data
+ la.pcrel t0, cpuboot_data
ld.d sp, t0, CPU_BOOT_STACK
ld.d tp, t0, CPU_BOOT_TINFO

diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
index 58781c6e4191..3dd2a9615cd9 100644
--- a/arch/loongarch/mm/tlbex.S
+++ b/arch/loongarch/mm/tlbex.S
@@ -24,8 +24,7 @@
move a0, sp
REG_S a2, sp, PT_BVADDR
li.w a1, \write
- la.abs t0, do_page_fault
- jirl ra, t0, 0
+ bl do_page_fault
RESTORE_ALL_AND_RET
SYM_FUNC_END(tlb_do_page_fault_\write)
.endm
--
2.37.0


2023-02-07 14:31:41

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 2/5] LoongArch: Use la.pcrel instead of la.abs for exception handlers

It's needed to build the kernel as a PIE, or the linker will complain.

For the consideration about performance, we copy the exception handlers
to a dedicated 64 KB area for each CPU. So, the PC-relative offset
calculated at link time will be incorrect and we need to relocate the
exception handlers after copying them.

For the simplicity, we don't use the ELF R_LARCH_* relocations, but code
an relocation entry as simply (offset_in_the_handler, symbol_addr). For
each exception handler, we also code the number of relocation entries.
Then we can use the relocation information to fix up the handlers after
copying them.

Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/include/asm/setup.h | 6 +-
arch/loongarch/include/asm/stackframe.h | 3 +-
arch/loongarch/kernel/genex.S | 40 ++++++-
arch/loongarch/kernel/traps.c | 138 ++++++++++++++++++++----
arch/loongarch/mm/tlb.c | 23 ++--
arch/loongarch/mm/tlbex.S | 69 ++++++++++--
6 files changed, 234 insertions(+), 45 deletions(-)

diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h
index 72ead58039f3..f0a2b34365f1 100644
--- a/arch/loongarch/include/asm/setup.h
+++ b/arch/loongarch/include/asm/setup.h
@@ -11,6 +11,9 @@

#define VECSIZE 0x200

+struct handler_reloc;
+
+extern struct handler_reloc *eentry_reloc[];
extern unsigned long eentry;
extern unsigned long tlbrentry;
extern char init_command_line[COMMAND_LINE_SIZE];
@@ -18,7 +21,8 @@ extern void tlb_init(int cpu);
extern void cpu_cache_init(void);
extern void cache_error_setup(void);
extern void per_cpu_trap_init(int cpu);
-extern void set_handler(unsigned long offset, void *addr, unsigned long len);
+extern void set_handler(unsigned long exccode, void *addr);
extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len);
+extern void reloc_handler(unsigned long handler, struct handler_reloc *rel);

#endif /* __SETUP_H */
diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index 7deb043ce387..bbec1e56b61b 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -77,7 +77,8 @@
* new value in sp.
*/
.macro get_saved_sp docfi=0
- la.abs t1, kernelsp
+ /* The label is used for generating reloc tables for handlers */
+514: la.pcrel t1, t0, kernelsp
#ifdef CONFIG_SMP
csrrd t0, PERCPU_BASE_KS
LONG_ADD t1, t1, t0
diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S
index 7e5c293ed89f..005a10fe5a50 100644
--- a/arch/loongarch/kernel/genex.S
+++ b/arch/loongarch/kernel/genex.S
@@ -34,7 +34,7 @@ SYM_FUNC_END(__arch_cpu_idle)
SYM_FUNC_START(handle_vint)
BACKUP_T0T1
SAVE_ALL
- la.abs t1, __arch_cpu_idle
+0: la.pcrel t1, t2, __arch_cpu_idle
LONG_L t0, sp, PT_ERA
/* 32 byte rollback region */
ori t0, t0, 0x1f
@@ -43,11 +43,25 @@ SYM_FUNC_START(handle_vint)
LONG_S t0, sp, PT_ERA
1: move a0, sp
move a1, sp
- la.abs t0, do_vint
+2: la.pcrel t0, t2, do_vint
jirl ra, t0, 0
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_vint)

+SYM_DATA_START(rel_handle_vint)
+LONG 3
+
+LONG 514b - handle_vint
+LONG kernelsp
+
+LONG 0b - handle_vint
+LONG __arch_cpu_idle
+
+LONG 2b - handle_vint
+LONG do_vint
+
+SYM_DATA_END(rel_handle_vint)
+
SYM_FUNC_START(except_vec_cex)
b cache_parity_error
SYM_FUNC_END(except_vec_cex)
@@ -72,12 +86,24 @@ SYM_FUNC_END(except_vec_cex)
SAVE_ALL
build_prep_\prep
move a0, sp
- la.abs t0, do_\handler
+ 667:
+ la.pcrel t0, t1, do_\handler
jirl ra, t0, 0
668:
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_\exception)
SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
+
+ SYM_DATA_START(rel_handle_\exception)
+ LONG 2
+
+ LONG 514b - 666b
+ LONG kernelsp
+
+ LONG 667b - 666b
+ LONG do_\handler
+
+ SYM_DATA_END(rel_handle_\exception)
.endm

BUILD_HANDLER ade ade badv
@@ -93,6 +119,12 @@ SYM_FUNC_END(except_vec_cex)
BUILD_HANDLER reserved reserved none /* others */

SYM_FUNC_START(handle_sys)
- la.abs t0, handle_syscall
+ la.pcrel t0, t1, handle_syscall
jr t0
SYM_FUNC_END(handle_sys)
+
+SYM_DATA_START(rel_handle_sys)
+LONG 1
+LONG 0
+LONG handle_syscall
+SYM_DATA_END(rel_handle_sys)
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index 547ab6843d14..b47cd5ccace3 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -62,6 +62,107 @@ extern asmlinkage void handle_reserved(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_vint(void);

+struct handler_reloc_entry {
+ unsigned long offset;
+ unsigned long sym;
+};
+
+struct handler_reloc {
+ unsigned long cnt;
+ struct handler_reloc_entry entries[];
+};
+
+extern struct handler_reloc rel_handle_tlb_load;
+extern struct handler_reloc rel_handle_tlb_store;
+extern struct handler_reloc rel_handle_tlb_modify;
+extern struct handler_reloc rel_handle_tlb_protect;
+extern struct handler_reloc rel_handle_ade;
+extern struct handler_reloc rel_handle_ale;
+extern struct handler_reloc rel_handle_sys;
+extern struct handler_reloc rel_handle_bp;
+extern struct handler_reloc rel_handle_ri;
+extern struct handler_reloc rel_handle_fpu;
+extern struct handler_reloc rel_handle_lsx;
+extern struct handler_reloc rel_handle_lasx;
+extern struct handler_reloc rel_handle_fpe;
+extern struct handler_reloc rel_handle_lbt;
+extern struct handler_reloc rel_handle_watch;
+extern struct handler_reloc rel_handle_reserved;
+extern struct handler_reloc rel_handle_vint;
+
+struct handler_reloc *eentry_reloc[128] = {
+ [0] = NULL, /* merr handler */
+ [EXCCODE_TLBL] = &rel_handle_tlb_load,
+ [EXCCODE_TLBS] = &rel_handle_tlb_store,
+ [EXCCODE_TLBI] = &rel_handle_tlb_load,
+ [EXCCODE_TLBM] = &rel_handle_tlb_modify,
+ [EXCCODE_TLBNR] = &rel_handle_tlb_protect,
+ [EXCCODE_TLBNX] = &rel_handle_tlb_protect,
+ [EXCCODE_TLBPE] = &rel_handle_tlb_protect,
+ [EXCCODE_ADE] = &rel_handle_ade,
+ [EXCCODE_ALE] = &rel_handle_ale,
+ [EXCCODE_SYS] = &rel_handle_sys,
+ [EXCCODE_BP] = &rel_handle_bp,
+ [EXCCODE_INE] = &rel_handle_ri,
+ [EXCCODE_IPE] = &rel_handle_ri,
+ [EXCCODE_FPDIS] = &rel_handle_fpu,
+ [EXCCODE_LSXDIS] = &rel_handle_lsx,
+ [EXCCODE_LASXDIS] = &rel_handle_lasx,
+ [EXCCODE_FPE] = &rel_handle_fpe,
+ [EXCCODE_BTDIS] = &rel_handle_lbt,
+ [EXCCODE_WATCH] = &rel_handle_watch,
+ [(EXCCODE_WATCH + 1) ... (EXCCODE_INT_START - 1)] = &rel_handle_reserved,
+ [EXCCODE_INT_START ... (EXCCODE_INT_END - 1)] = &rel_handle_vint,
+};
+
+void reloc_handler(unsigned long handler, struct handler_reloc *rel)
+{
+ if (!rel)
+ return;
+
+ for (unsigned long i = 0; i < rel->cnt; i++) {
+ unsigned long pc = handler + rel->entries[i].offset;
+ unsigned long v = rel->entries[i].sym;
+ /* Use s32 for a sign-extension deliberately. */
+ s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
+ (void *)(pc & ~0xfff);
+ unsigned long anchor = (pc & ~0xfff) + offset_hi20;
+ ptrdiff_t offset_rem = (void *)v - (void *)anchor;
+ union loongarch_instruction *insn =
+ (union loongarch_instruction *)pc;
+
+ insn[1].reg2i12_format.immediate = v & 0xfff;
+ v = offset_hi20 >> 12;
+ insn[0].reg1i20_format.immediate = v & 0xfffff;
+ v = offset_rem >> 32;
+ insn[2].reg1i20_format.immediate = v & 0xfffff;
+ v = offset_rem >> 52;
+ insn[3].reg2i12_format.immediate = v & 0xfff;
+ }
+}
+
+/* Install CPU exception handler */
+static void do_set_handler(unsigned long exccode, void *addr,
+ struct handler_reloc *rel)
+{
+ unsigned long dest_addr = eentry + exccode * VECSIZE;
+
+ memcpy((void *)dest_addr, addr, VECSIZE);
+ reloc_handler(dest_addr, rel);
+ local_flush_icache_range(dest_addr, dest_addr + VECSIZE);
+}
+
+/* Install CPU exception handler, with the reloc table from eentry_reloc */
+void set_handler(unsigned long exccode, void *addr)
+{
+ do_set_handler(exccode, addr, eentry_reloc[exccode]);
+}
+
+static void set_handler_reserved(unsigned long exccode)
+{
+ do_set_handler(exccode, handle_reserved, &rel_handle_reserved);
+}
+
static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
const char *loglvl, bool user)
{
@@ -781,19 +882,12 @@ void per_cpu_trap_init(int cpu)
/* Initialise exception handlers */
if (cpu == 0)
for (i = 0; i < 64; i++)
- set_handler(i * VECSIZE, handle_reserved, VECSIZE);
+ set_handler_reserved(i);

tlb_init(cpu);
cpu_cache_init();
}

-/* Install CPU exception handler */
-void set_handler(unsigned long offset, void *addr, unsigned long size)
-{
- memcpy((void *)(eentry + offset), addr, size);
- local_flush_icache_range(eentry + offset, eentry + offset + size);
-}
-
static const char panic_null_cerr[] =
"Trying to set NULL cache error exception handler\n";

@@ -818,20 +912,20 @@ void __init trap_init(void)

/* Set interrupt vector handler */
for (i = EXCCODE_INT_START; i < EXCCODE_INT_END; i++)
- set_handler(i * VECSIZE, handle_vint, VECSIZE);
-
- set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE);
- set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE);
- set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE);
- set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE);
- set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE);
- set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE);
- set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE);
- set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE);
- set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE);
- set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE);
- set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE);
- set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE);
+ set_handler(i, handle_vint);
+
+ set_handler(EXCCODE_ADE, handle_ade);
+ set_handler(EXCCODE_ALE, handle_ale);
+ set_handler(EXCCODE_SYS, handle_sys);
+ set_handler(EXCCODE_BP, handle_bp);
+ set_handler(EXCCODE_INE, handle_ri);
+ set_handler(EXCCODE_IPE, handle_ri);
+ set_handler(EXCCODE_FPDIS, handle_fpu);
+ set_handler(EXCCODE_LSXDIS, handle_lsx);
+ set_handler(EXCCODE_LASXDIS, handle_lasx);
+ set_handler(EXCCODE_FPE, handle_fpe);
+ set_handler(EXCCODE_BTDIS, handle_lbt);
+ set_handler(EXCCODE_WATCH, handle_watch);

cache_error_setup();

diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c
index 8bad6b0cff59..6f70aab7202a 100644
--- a/arch/loongarch/mm/tlb.c
+++ b/arch/loongarch/mm/tlb.c
@@ -253,7 +253,6 @@ static void output_pgtable_bits_defines(void)
#ifdef CONFIG_NUMA
unsigned long pcpu_handlers[NR_CPUS];
#endif
-extern long exception_handlers[VECSIZE * 128 / sizeof(long)];

void setup_tlb_handler(int cpu)
{
@@ -264,19 +263,20 @@ void setup_tlb_handler(int cpu)
if (cpu == 0) {
memcpy((void *)tlbrentry, handle_tlb_refill, 0x80);
local_flush_icache_range(tlbrentry, tlbrentry + 0x80);
- set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE);
- set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE);
- set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE);
- set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE);
- set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE);
- set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE);
- set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE);
+ set_handler(EXCCODE_TLBI, handle_tlb_load);
+ set_handler(EXCCODE_TLBL, handle_tlb_load);
+ set_handler(EXCCODE_TLBS, handle_tlb_store);
+ set_handler(EXCCODE_TLBM, handle_tlb_modify);
+ set_handler(EXCCODE_TLBNR, handle_tlb_protect);
+ set_handler(EXCCODE_TLBNX, handle_tlb_protect);
+ set_handler(EXCCODE_TLBPE, handle_tlb_protect);
}
#ifdef CONFIG_NUMA
else {
void *addr;
+ unsigned long addr_ul;
struct page *page;
- const int vec_sz = sizeof(exception_handlers);
+ const int vec_sz = VECSIZE * 128;

if (pcpu_handlers[cpu])
return;
@@ -286,8 +286,11 @@ void setup_tlb_handler(int cpu)
return;

addr = page_address(page);
+ addr_ul = (unsigned long)addr;
pcpu_handlers[cpu] = (unsigned long)addr;
- memcpy((void *)addr, (void *)eentry, vec_sz);
+ memcpy(addr, (void *)eentry, vec_sz);
+ for (unsigned long i = 0; i < 128; i++)
+ reloc_handler(addr_ul + i * VECSIZE, eentry_reloc[i]);
local_flush_icache_range((unsigned long)addr, (unsigned long)addr + vec_sz);
csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY);
csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY);
diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S
index 3dd2a9615cd9..044c2190771a 100644
--- a/arch/loongarch/mm/tlbex.S
+++ b/arch/loongarch/mm/tlbex.S
@@ -39,11 +39,21 @@ SYM_FUNC_START(handle_tlb_protect)
move a1, zero
csrrd a2, LOONGARCH_CSR_BADV
REG_S a2, sp, PT_BVADDR
- la.abs t0, do_page_fault
+1: la.pcrel t0, t1, do_page_fault
jirl ra, t0, 0
RESTORE_ALL_AND_RET
SYM_FUNC_END(handle_tlb_protect)

+SYM_DATA_START(rel_handle_tlb_protect)
+ LONG 2
+
+ LONG 514b - handle_tlb_protect
+ LONG kernelsp
+
+ LONG 1b - handle_tlb_protect
+ LONG do_page_fault
+SYM_DATA_END(rel_handle_tlb_protect)
+
SYM_FUNC_START(handle_tlb_load)
csrwr t0, EXCEPTION_KS0
csrwr t1, EXCEPTION_KS1
@@ -115,7 +125,8 @@ smp_pgtable_change_load:

#ifdef CONFIG_64BIT
vmalloc_load:
- la.abs t1, swapper_pg_dir
+ /* The first insn of vmalloc_done_load overwrites ra */
+1: la.pcrel t1, ra, swapper_pg_dir
b vmalloc_done_load
#endif

@@ -186,10 +197,24 @@ tlb_huge_update_load:
nopage_tlb_load:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_0
+2: la.pcrel t0, t1, tlb_do_page_fault_0
jr t0
SYM_FUNC_END(handle_tlb_load)

+SYM_DATA_START(rel_handle_tlb_load)
+#ifdef CONFIG_64BIT
+ LONG 2
+
+ LONG 1b - handle_tlb_load
+ LONG swapper_pg_dir
+#else
+ LONG 1
+#endif
+
+ LONG 2b - handle_tlb_load
+ LONG tlb_do_page_fault_0
+SYM_DATA_END(rel_handle_tlb_load)
+
SYM_FUNC_START(handle_tlb_store)
csrwr t0, EXCEPTION_KS0
csrwr t1, EXCEPTION_KS1
@@ -262,7 +287,8 @@ smp_pgtable_change_store:

#ifdef CONFIG_64BIT
vmalloc_store:
- la.abs t1, swapper_pg_dir
+ /* The first insn of vmalloc_done_store overwrites ra */
+1: la.pcrel t1, ra, swapper_pg_dir
b vmalloc_done_store
#endif

@@ -335,10 +361,24 @@ tlb_huge_update_store:
nopage_tlb_store:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_1
+2: la.pcrel t0, t1, tlb_do_page_fault_1
jr t0
SYM_FUNC_END(handle_tlb_store)

+SYM_DATA_START(rel_handle_tlb_store)
+#ifdef CONFIG_64BIT
+ LONG 2
+
+ LONG 1b - handle_tlb_store
+ LONG swapper_pg_dir
+#else
+ LONG 1
+#endif
+
+ LONG 2b - handle_tlb_store
+ LONG tlb_do_page_fault_1
+SYM_DATA_END(rel_handle_tlb_store)
+
SYM_FUNC_START(handle_tlb_modify)
csrwr t0, EXCEPTION_KS0
csrwr t1, EXCEPTION_KS1
@@ -410,7 +450,8 @@ smp_pgtable_change_modify:

#ifdef CONFIG_64BIT
vmalloc_modify:
- la.abs t1, swapper_pg_dir
+ /* The first insn of vmalloc_done_modify overwrites ra */
+1: la.pcrel t1, ra, swapper_pg_dir
b vmalloc_done_modify
#endif

@@ -482,10 +523,24 @@ tlb_huge_update_modify:
nopage_tlb_modify:
dbar 0
csrrd ra, EXCEPTION_KS2
- la.abs t0, tlb_do_page_fault_1
+2: la.pcrel t0, t1, tlb_do_page_fault_1
jr t0
SYM_FUNC_END(handle_tlb_modify)

+SYM_DATA_START(rel_handle_tlb_modify)
+#ifdef CONFIG_64BIT
+ LONG 2
+
+ LONG 1b - handle_tlb_modify
+ LONG swapper_pg_dir
+#else
+ LONG 1
+#endif
+
+ LONG 2b - handle_tlb_modify
+ LONG tlb_do_page_fault_1
+SYM_DATA_END(rel_handle_tlb_modify)
+
SYM_FUNC_START(handle_tlb_refill)
csrwr t0, LOONGARCH_CSR_TLBRSAVE
csrrd t0, LOONGARCH_CSR_PGD
--
2.37.0


2023-02-07 14:33:05

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 3/5] LoongArch: Add JUMP_LINK_ADDR macro implementation to avoid using la.abs

From: Youling Tang <[email protected]>

Add JUMP_LINK_ADDR macro implementation to avoid using la.abs.

Signed-off-by: Youling Tang <[email protected]>
---
arch/loongarch/include/asm/stackframe.h | 8 ++++++++
arch/loongarch/kernel/head.S | 10 ++++------
arch/loongarch/power/suspend_asm.S | 5 ++---
3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index bbec1e56b61b..cd8240858599 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -217,4 +217,12 @@
RESTORE_SP_AND_RET \docfi
.endm

+/* Jump to the virtual address of the link. */
+ .macro JUMP_LINK_ADDR
+ li.d t0, CACHE_BASE
+ pcaddi t1, 0
+ or t0, t0, t1
+ jirl zero, t0, 0xc
+ .endm
+
#endif /* _ASM_STACKFRAME_H */
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index aa6181714ec3..e8a4bf9d7599 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -52,9 +52,8 @@ SYM_CODE_START(kernel_entry) # kernel entry point

/* We might not get launched at the address the kernel is linked to,
so we jump there. */
- la.abs t0, 0f
- jr t0
-0:
+ JUMP_LINK_ADDR
+
/* Enable PG */
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
csrwr t0, LOONGARCH_CSR_CRMD
@@ -106,9 +105,8 @@ SYM_CODE_START(smpboot_entry)
li.d t0, CSR_DMW1_INIT # CA, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN1

- la.abs t0, 0f
- jr t0
-0:
+ JUMP_LINK_ADDR
+
/* Enable PG */
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
csrwr t0, LOONGARCH_CSR_CRMD
diff --git a/arch/loongarch/power/suspend_asm.S b/arch/loongarch/power/suspend_asm.S
index eb2675642f9f..596a682a7924 100644
--- a/arch/loongarch/power/suspend_asm.S
+++ b/arch/loongarch/power/suspend_asm.S
@@ -78,9 +78,8 @@ SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL)
li.d t0, CSR_DMW1_INIT # CA, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN1

- la.abs t0, 0f
- jr t0
-0:
+ JUMP_LINK_ADDR
+
la.pcrel t0, acpi_saved_sp
ld.d sp, t0, 0
SETUP_WAKEUP
--
2.37.0


2023-02-07 14:33:32

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 4/5] LoongArch: Add support for kernel relocation

From: Youling Tang <[email protected]>

arch/loongarch/kernel/relocate.c contains the functions necessary to
relocate the kernel elsewhere in memory.

The kernel makes a copy of itself at the new address. It uses the
relocation table inserted by the relocs tool to fix symbol references
within the new image.

If copy/relocation is successful then the entry point of the new kernel
is returned, otherwise fall back to starting the kernel in place.

Signed-off-by: Youling Tang <[email protected]>
Signed-off-by: Xi Ruoyao <[email protected]> # Fix compiler warnings
---
arch/loongarch/Kconfig | 15 +++++
arch/loongarch/Makefile | 5 ++
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/head.S | 18 ++++++
arch/loongarch/kernel/relocate.c | 96 +++++++++++++++++++++++++++++
arch/loongarch/kernel/vmlinux.lds.S | 11 +++-
6 files changed, 145 insertions(+), 2 deletions(-)
create mode 100644 arch/loongarch/kernel/relocate.c

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 0e2427d4ee50..db83f71ba1c0 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -48,6 +48,7 @@ config LOONGARCH
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_HUGETLBFS
select ARCH_SUPPORTS_NUMA_BALANCING
+ select SYS_SUPPORTS_RELOCATABLE
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_USE_QUEUED_RWLOCKS
@@ -229,6 +230,11 @@ config SCHED_OMIT_FRAME_POINTER
config AS_HAS_EXPLICIT_RELOCS
def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))

+config SYS_SUPPORTS_RELOCATABLE
+ bool
+ help
+ Selected if the platform supports relocating the kernel.
+
menu "Kernel type and options"

source "kernel/Kconfig.hz"
@@ -474,6 +480,15 @@ config PHYSICAL_START
specified in the "crashkernel=YM@XM" command line boot parameter
passed to the panic-ed kernel).

+config RELOCATABLE
+ bool "Relocatable kernel"
+ depends on SYS_SUPPORTS_RELOCATABLE
+ help
+ This builds the kernel as a Position Independent Executable (PIE),
+ which retains all relocation metadata required to relocate the
+ kernel binary at runtime to a different virtual address than the
+ address it was linked at.
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 4402387d2755..27b5a70ff31c 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -71,6 +71,11 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
endif

+ifeq ($(CONFIG_RELOCATABLE),y)
+LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
+KBUILD_CFLAGS_KERNEL += -fPIE
+endif
+
cflags-y += -ffreestanding
cflags-y += $(call cc-option, -mno-check-zero-division)

diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index c8cfbd562921..3341dd5f0926 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -31,6 +31,8 @@ endif
obj-$(CONFIG_MODULES) += module.o module-sections.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o

+obj-$(CONFIG_RELOCATABLE) += relocate.o
+
obj-$(CONFIG_PROC_FS) += proc.o

obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index e8a4bf9d7599..6db1549177ad 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -88,7 +88,25 @@ SYM_CODE_START(kernel_entry) # kernel entry point
PTR_ADD sp, sp, tp
set_saved_sp sp, t0, t1

+#ifdef CONFIG_RELOCATABLE
+ /* Copy kernel and apply the relocations */
+ bl relocate_kernel
+
+ /* Repoint the sp into the new kernel image */
+ PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
+ PTR_ADD sp, sp, tp
+ set_saved_sp sp, t0, t1
+ PTR_ADDI sp, sp, -4 * SZREG # init stack pointer
+
+ /*
+ * relocate_kernel returns the entry point either
+ * in the relocated kernel or the original if for
+ * some reason relocation failed.
+ */
+ jr a0
+#else
bl start_kernel
+#endif
ASM_BUG()

SYM_CODE_END(kernel_entry)
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
new file mode 100644
index 000000000000..9c61e03d3e91
--- /dev/null
+++ b/arch/loongarch/kernel/relocate.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for Kernel relocation at boot time
+ *
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/printk.h>
+#include <linux/panic_notifier.h>
+#include <asm/bootinfo.h>
+#include <asm/inst.h>
+#include <asm/sections.h>
+
+#define RELOCATED(x) ((void *)((long)x + offset))
+
+extern long __rela_dyn_start;
+extern long __rela_dyn_end;
+
+/*
+ * Choose a new address for the kernel, for now we'll hard
+ * code the destination.
+ */
+static inline void __init *determine_relocation_address(void)
+{
+ return (void *)(CACHE_BASE + 0x02000000);
+}
+
+static inline int __init relocation_addr_valid(void *loc_new)
+{
+ if ((unsigned long)loc_new & 0x0000ffff) {
+ /* Inappropriately aligned new location */
+ return 0;
+ }
+ if ((unsigned long)loc_new < (unsigned long)_end) {
+ /* New location overlaps original kernel */
+ return 0;
+ }
+ return 1;
+}
+
+void *__init relocate_kernel(void)
+{
+ Elf64_Rela *rela, *rela_end;
+ void *loc_new;
+ unsigned long kernel_length;
+ long offset = 0;
+ /* Default to original kernel entry point */
+ void *kernel_entry = start_kernel;
+
+ kernel_length = (long)(_end) - (long)(_text);
+
+ loc_new = determine_relocation_address();
+
+ /* Sanity check relocation address */
+ if (relocation_addr_valid(loc_new))
+ offset = (unsigned long)loc_new - (unsigned long)(_text);
+
+ if (offset) {
+ /* Copy the kernel to it's new location */
+ memcpy(loc_new, _text, kernel_length);
+
+ /* Sync the caches ready for execution of new kernel */
+ __asm__ __volatile__ (
+ "ibar 0 \t\n"
+ "dbar 0 \t\n");
+
+ rela = (Elf64_Rela *)RELOCATED(&__rela_dyn_start);
+ rela_end = (Elf64_Rela *)RELOCATED(&__rela_dyn_end);
+
+ for ( ; rela < rela_end; rela++) {
+ Elf64_Addr addr = rela->r_offset;
+ Elf64_Addr relocated_addr = rela->r_addend;
+
+ if (rela->r_info != R_LARCH_RELATIVE)
+ continue;
+
+ if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
+ relocated_addr =
+ (Elf64_Addr)RELOCATED(relocated_addr);
+
+ *(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
+
+ }
+
+ /* The current thread is now within the relocated image */
+ __current_thread_info = RELOCATED(__current_thread_info);
+
+ /* Return the new kernel's entry point */
+ kernel_entry = RELOCATED(start_kernel);
+ }
+
+ return kernel_entry;
+}
diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
index 733b16e8d55d..aec0b6567d24 100644
--- a/arch/loongarch/kernel/vmlinux.lds.S
+++ b/arch/loongarch/kernel/vmlinux.lds.S
@@ -70,6 +70,8 @@ SECTIONS
.plt : ALIGN(16) { *(.plt) }
.got.plt : ALIGN(16) { *(.got.plt) }

+ .data.rel : { *(.data.rel*) }
+
. = ALIGN(PECOFF_SEGMENT_ALIGN);
__init_begin = .;
__inittext_begin = .;
@@ -93,8 +95,6 @@ SECTIONS
PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
#endif

- .rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
-
.init.bss : {
*(.init.bss)
}
@@ -107,6 +107,12 @@ SECTIONS
RO_DATA(4096)
RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)

+ .rela.dyn : ALIGN(8) {
+ __rela_dyn_start = .;
+ *(.rela.dyn) *(.rela*)
+ __rela_dyn_end = .;
+ }
+
.sdata : {
*(.sdata)
}
@@ -133,6 +139,7 @@ SECTIONS

DISCARDS
/DISCARD/ : {
+ *(.dynamic .dynsym .dynstr .hash .gnu.hash)
*(.gnu.attributes)
*(.options)
*(.eh_frame)
--
2.37.0


2023-02-07 14:33:46

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH v2 5/5] LoongArch: Add support for kernel address space layout randomization (KASLR)

From: Youling Tang <[email protected]>

This patch adds support for relocating the kernel to a random address.

Entropy is derived from the banner, which will change every build and
random_get_entropy() which should provide additional runtime entropy.

The kernel is relocated by up to RANDOMIZE_BASE_MAX_OFFSET bytes from
its link address. Because relocation happens so early in the kernel boot,
the amount of physical memory has not yet been determined. This means
the only way to limit relocation within the available memory is via
Kconfig. Limit the maximum value of RANDOMIZE_BASE_MAX_OFFSET to
256M(0x10000000) because our memory layout has many holes.

KERNELOFFSET (kaslr_offset) is added to vmcoreinfo in the future, for
crash --kaslr support.

Signed-off-by: Youling Tang <[email protected]>
Signed-off-by: Xi Ruoyao <[email protected]> # Use arch_initcall
---
arch/loongarch/Kconfig | 22 ++++++
arch/loongarch/include/asm/page.h | 6 ++
arch/loongarch/kernel/relocate.c | 115 ++++++++++++++++++++++++++++++
arch/loongarch/kernel/setup.c | 3 +
4 files changed, 146 insertions(+)

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index db83f71ba1c0..4ceb16ce080a 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -489,6 +489,28 @@ config RELOCATABLE
kernel binary at runtime to a different virtual address than the
address it was linked at.

+config RANDOMIZE_BASE
+ bool "Randomize the address of the kernel image (KASLR)"
+ depends on RELOCATABLE
+ help
+ Randomizes the physical and virtual address at which the
+ kernel image is loaded, as a security feature that
+ deters exploit attempts relying on knowledge of the location
+ of kernel internals.
+
+ The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET.
+
+ If unsure, say N.
+
+config RANDOMIZE_BASE_MAX_OFFSET
+ hex "Maximum KASLR offset" if EXPERT
+ depends on RANDOMIZE_BASE
+ range 0x0 0x10000000 if 64BIT
+ default "0x01000000"
+ help
+ When KASLR is active, this provides the maximum offset that will
+ be applied to the kernel image.
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h
index 53f284a96182..6dda0d6271ca 100644
--- a/arch/loongarch/include/asm/page.h
+++ b/arch/loongarch/include/asm/page.h
@@ -106,6 +106,12 @@ extern int __virt_addr_valid(volatile void *kaddr);
((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)

+extern unsigned long __kaslr_offset;
+static inline unsigned long kaslr_offset(void)
+{
+ return __kaslr_offset;
+}
+
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>

diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index 9c61e03d3e91..351168b70b7a 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -11,6 +11,7 @@
#include <linux/printk.h>
#include <linux/panic_notifier.h>
#include <asm/bootinfo.h>
+#include <asm/early_ioremap.h>
#include <asm/inst.h>
#include <asm/sections.h>

@@ -19,6 +20,70 @@
extern long __rela_dyn_start;
extern long __rela_dyn_end;

+#ifdef CONFIG_RANDOMIZE_BASE
+
+static inline __init unsigned long rotate_xor(unsigned long hash,
+ const void *area, size_t size)
+{
+ size_t i;
+ unsigned long *ptr = (unsigned long *)area;
+
+ for (i = 0; i < size / sizeof(hash); i++) {
+ /* Rotate by odd number of bits and XOR. */
+ hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
+ hash ^= ptr[i];
+ }
+
+ return hash;
+}
+
+static inline __init unsigned long get_random_boot(void)
+{
+ unsigned long entropy = random_get_entropy();
+ unsigned long hash = 0;
+
+ /* Attempt to create a simple but unpredictable starting entropy. */
+ hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
+
+ /* Add in any runtime entropy we can get */
+ hash = rotate_xor(hash, &entropy, sizeof(entropy));
+
+ return hash;
+}
+
+static inline __init bool kaslr_disabled(void)
+{
+ char *str;
+
+ str = strstr(boot_command_line, "nokaslr");
+ if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
+ return true;
+
+ return false;
+}
+
+/* Choose a new address for the kernel */
+static inline void __init *determine_relocation_address(void)
+{
+ unsigned long kernel_length;
+ void *dest = _text;
+ unsigned long offset;
+
+ if (kaslr_disabled())
+ return dest;
+
+ kernel_length = (long)_end - (long)_text;
+
+ offset = get_random_boot() << 16;
+ offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
+ if (offset < kernel_length)
+ offset += ALIGN(kernel_length, 0xffff);
+
+ return RELOCATED(dest);
+}
+
+#else
+
/*
* Choose a new address for the kernel, for now we'll hard
* code the destination.
@@ -28,6 +93,8 @@ static inline void __init *determine_relocation_address(void)
return (void *)(CACHE_BASE + 0x02000000);
}

+#endif
+
static inline int __init relocation_addr_valid(void *loc_new)
{
if ((unsigned long)loc_new & 0x0000ffff) {
@@ -41,6 +108,13 @@ static inline int __init relocation_addr_valid(void *loc_new)
return 1;
}

+static inline void __init update_kaslr_offset(unsigned long *addr, long offset)
+{
+ unsigned long *new_addr = (unsigned long *)RELOCATED(addr);
+
+ *new_addr = (unsigned long)offset;
+}
+
void *__init relocate_kernel(void)
{
Elf64_Rela *rela, *rela_end;
@@ -49,6 +123,10 @@ void *__init relocate_kernel(void)
long offset = 0;
/* Default to original kernel entry point */
void *kernel_entry = start_kernel;
+ char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE);
+
+ /* Boot command line was passed in fw_arg1 */
+ strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);

kernel_length = (long)(_end) - (long)(_text);

@@ -90,7 +168,44 @@ void *__init relocate_kernel(void)

/* Return the new kernel's entry point */
kernel_entry = RELOCATED(start_kernel);
+
+ /* Error may occur before, so keep it at last */
+ update_kaslr_offset(&__kaslr_offset, offset);
}

return kernel_entry;
}
+
+/*
+ * Show relocation information on panic.
+ */
+static void show_kernel_relocation(const char *level)
+{
+ if (__kaslr_offset > 0) {
+ printk(level);
+ pr_cont("Kernel relocated offset @ 0x%lx\n", __kaslr_offset);
+ pr_cont(" .text @ 0x%lx\n", (unsigned long)&_text);
+ pr_cont(" .data @ 0x%lx\n", (unsigned long)&_sdata);
+ pr_cont(" .bss @ 0x%lx\n", (unsigned long)&__bss_start);
+ }
+}
+
+static int kernel_location_notifier_fn(struct notifier_block *self,
+ unsigned long v, void *p)
+{
+ show_kernel_relocation(KERN_EMERG);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block kernel_location_notifier = {
+ .notifier_call = kernel_location_notifier_fn
+};
+
+static int __init register_kernel_offset_dumper(void)
+{
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &kernel_location_notifier);
+ return 0;
+}
+
+arch_initcall(register_kernel_offset_dumper);
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 4344502c0b31..b2ba2741945c 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -82,6 +82,9 @@ static struct resource code_resource = { .name = "Kernel code", };
static struct resource data_resource = { .name = "Kernel data", };
static struct resource bss_resource = { .name = "Kernel bss", };

+unsigned long __kaslr_offset __ro_after_init;
+EXPORT_SYMBOL(__kaslr_offset);
+
const char *get_system_type(void)
{
return "generic-loongson-machine";
--
2.37.0


2023-02-07 14:41:52

by Xi Ruoyao

[permalink] [raw]
Subject: Re: [PATCH v2 2/5] LoongArch: Use la.pcrel instead of la.abs for exception handlers

On Tue, 2023-02-07 at 22:28 +0800, Xi Ruoyao wrote:
> +struct handler_reloc *eentry_reloc[128] = {
> +       [0] = NULL, /* merr handler */

Self review:

This is actually incorrect. Currently the merr handler (except_vec_cex)
is coded as:

SYM_FUNC_START(except_vec_cex)
b cache_parity_error
SYM_FUNC_END(except_vec_cex)

Once this is copied into the per-cpu handler page, the offset (coded in
the b instruction) will be absolutely wrong. But it's already incorrect
in the current mainline, and I'm not familiar with CSR.CRMD.DA=1
configuration so I'm not sure how to fix it.

--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2023-02-08 00:59:28

by Jinyang He

[permalink] [raw]
Subject: Re: [PATCH v2 2/5] LoongArch: Use la.pcrel instead of la.abs for exception handlers


On 2023-02-07 22:39, Xi Ruoyao wrote:
> On Tue, 2023-02-07 at 22:28 +0800, Xi Ruoyao wrote:
>> +struct handler_reloc *eentry_reloc[128] = {
>> +       [0] = NULL, /* merr handler */
> Self review:
>
> This is actually incorrect. Currently the merr handler (except_vec_cex)
> is coded as:
>
> SYM_FUNC_START(except_vec_cex)
> b cache_parity_error
> SYM_FUNC_END(except_vec_cex)
>
> Once this is copied into the per-cpu handler page, the offset (coded in
> the b instruction) will be absolutely wrong. But it's already incorrect
> in the current mainline, and I'm not familiar with CSR.CRMD.DA=1
> configuration so I'm not sure how to fix it.
>
It bothers me, too. And I've mentioned it to Huacai offline before.
Besides, after fixing this issue I'll support a series of patches
to fix the cfi note in asm files.



2023-02-08 04:37:51

by Youling Tang

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] LoongArch: Add kernel relocation and KASLR support

Hi, Ruoyao

On 02/07/2023 10:28 PM, Xi Ruoyao wrote:
> This patch series to support kernel relocation and KASLR (only 64bit).
>
> I've only tested new toolchains (CONFIG_AS_HAS_EXPLICIT_RELOCS=y)
> consisted of Binutils-2.40, and GCC-12.2 heavily patched to support new
> relocs. Unfortunately I've purged my old toolchain installation (because
> it contained a buggy GCC-12.1 miscompiling some code). Please test the
> configuration with old toolchain.
I tested it through QEMU.

Testing in the new toolchains is successful,
/ # dmesg | head
[ 0.000000] Linux version 6.2.0-rc7+ (root@bogon)
(loongarch64-unknown-linux-gnu-gcc (GCC) 13.0.0 20220906 (experimental),
GNU ld (GNU Binutils) 2.39.50.20220906) #67 SMP PREEMPT Wed Feb 8
09:42:49 CST 2023
/ # cat /proc/iomem | head
00000000-0fffffff : System RAM
00000000-002c3fff : Reserved
002c4000-008c3fff : Reserved
02a50000-0399ffff : Kernel code
039a0000-0426d9ff : Kernel data
0426da00-0439ae37 : Kernel bss


But testing in the old toolchains failed, stuck in the following
position,
[ 0.000000] Linux version 6.2.0-rc7+ (root@bogon)
(loongarch64-unknown-linux-gnu-gcc (GCC) 12.1.0, GNU ld (GNU Binutils)
2.38.50.20220519) #68 SMP PREEMPT Wed Feb 8 09:52:49 CST 2023
...
[ 0.000000] rcu: srcu_init: Setting srcu_struct sizes based on
contention.
[ 0.000000] Constant clock event device register
[ 0.000000] clocksource: Constant: mask: 0xffffffffffffffff
max_cycles: 0x171024e7e0, max_idle_ns: 440795205315 ns
[ 0.000289] sched_clock: 64 bits at 100MHz, resolution 10ns, wraps
every 4398046511100ns
[ 0.000715] Constant clock source device register


In the case of "[Patch v2 2/5] LoongArch: use la.pcrel instenad of
la.abs for exception handlerS", the above failure will occur.

Patch2 may have certain problems when using the old toolchains.

Youling.

>
> Test results with CONFIG_RANDOMIZE_BASE=y on a 3A5000-7A2000-EVB:
>
> First boot:
>
> $ sudo cat /proc/iomem | grep Kernel
> 010e0000-018fffff : Kernel code
> 01900000-01e4b5ff : Kernel data
> 01e4b600-01f56e9f : Kernel bss
>
> Second boot:
>
> $ sudo cat /proc/iomem | grep Kernel
> 019a0000-021bffff : Kernel code
> 021c0000-0270b5ff : Kernel data
> 0270b600-02816e9f : Kernel bss
>
> Changes from v1:
>
> - Relocate the handlers instead of using a trampoline, to avoid
> performance issue on NUMA systems.
> - Fix compiler warnings.
>
> Xi Ruoyao (2):
> LoongArch: Use la.pcrel instead of la.abs when it's trivially possible
> LoongArch: Use la.pcrel instead of la.abs for exception handlers
>
> Youling Tang (3):
> LoongArch: Add JUMP_LINK_ADDR macro implementation to avoid using
> la.abs
> LoongArch: Add support for kernel relocation
> LoongArch: Add support for kernel address space layout randomization
> (KASLR)
>
> arch/loongarch/Kconfig | 37 +++++
> arch/loongarch/Makefile | 5 +
> arch/loongarch/include/asm/page.h | 6 +
> arch/loongarch/include/asm/setup.h | 6 +-
> arch/loongarch/include/asm/stackframe.h | 13 +-
> arch/loongarch/include/asm/uaccess.h | 1 -
> arch/loongarch/kernel/Makefile | 2 +
> arch/loongarch/kernel/entry.S | 2 +-
> arch/loongarch/kernel/genex.S | 40 ++++-
> arch/loongarch/kernel/head.S | 30 +++-
> arch/loongarch/kernel/relocate.c | 211 ++++++++++++++++++++++++
> arch/loongarch/kernel/setup.c | 3 +
> arch/loongarch/kernel/traps.c | 138 +++++++++++++---
> arch/loongarch/kernel/vmlinux.lds.S | 11 +-
> arch/loongarch/mm/tlb.c | 23 +--
> arch/loongarch/mm/tlbex.S | 72 +++++++-
> arch/loongarch/power/suspend_asm.S | 5 +-
> 17 files changed, 543 insertions(+), 62 deletions(-)
> create mode 100644 arch/loongarch/kernel/relocate.c
>


2023-02-08 08:27:42

by Xi Ruoyao

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] LoongArch: Add kernel relocation and KASLR support

On Wed, 2023-02-08 at 12:37 +0800, Youling Tang wrote:
> In the case of "[Patch v2 2/5] LoongArch: use la.pcrel instenad of
> la.abs for exception handlerS", the above failure will occur.
>
> Patch2 may have certain problems when using the old toolchains.
>
> Youling.

Thanks for the test...

The problem is: old toolchain uses pcaddu12i/ori/lu32i.d/lu52i.d/add.d
for a 3-operand la.pcrel, while the new toolchain uses
pcalau12i/addi.d/lu32i/lu52i/add.d. (I've somehow forgotten all the
difference!)

We can fix it with something like...

> +void reloc_handler(unsigned long handler, struct handler_reloc *rel)
> +{
> + if (!rel)
> + return;
> +
> + for (unsigned long i = 0; i < rel->cnt; i++) {
> + unsigned long pc = handler + rel->entries[i].offset;
> + unsigned long v = rel->entries[i].sym;

/* anchor etc. moved into do_reloc_pcalau12i */

> + union loongarch_instruction *insn =
> + (union loongarch_instruction *)pc;

switch insn[0]->reg1i20_format->reg1i20_format {
case pcaddu12i_op:
do_reloc_pcaddu12i(insn, pc, v);
break;
case pcalau12i_op: /* TODO: add it for asm/inst.h */
do_reloc_pcalau12i(insn, pc, v);
break;
default:
panic("what the f**k");
}

Alternatively, we can also emit the pcalau12i/addi.d/lu32i/lu52i
sequence and overwrite the pcaddu12i/ori sequence generated by the old
toolchain.

Which way do you like?
--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2023-02-09 06:35:01

by Youling Tang

[permalink] [raw]
Subject: Re: [PATCH v2 0/5] LoongArch: Add kernel relocation and KASLR support



On 02/08/2023 04:27 PM, Xi Ruoyao wrote:
> On Wed, 2023-02-08 at 12:37 +0800, Youling Tang wrote:
>> In the case of "[Patch v2 2/5] LoongArch: use la.pcrel instenad of
>> la.abs for exception handlerS", the above failure will occur.
>>
>> Patch2 may have certain problems when using the old toolchains.
>>
>> Youling.
>
> Thanks for the test...
>
> The problem is: old toolchain uses pcaddu12i/ori/lu32i.d/lu52i.d/add.d
> for a 3-operand la.pcrel, while the new toolchain uses
> pcalau12i/addi.d/lu32i/lu52i/add.d. (I've somehow forgotten all the
> difference!)
>
> We can fix it with something like...
>
>> +void reloc_handler(unsigned long handler, struct handler_reloc *rel)
>> +{
>> + if (!rel)
>> + return;
>> +
>> + for (unsigned long i = 0; i < rel->cnt; i++) {
>> + unsigned long pc = handler + rel->entries[i].offset;
>> + unsigned long v = rel->entries[i].sym;
>
> /* anchor etc. moved into do_reloc_pcalau12i */
>
>> + union loongarch_instruction *insn =
>> + (union loongarch_instruction *)pc;
>
> switch insn[0]->reg1i20_format->reg1i20_format {
> case pcaddu12i_op:
> do_reloc_pcaddu12i(insn, pc, v);
> break;
> case pcalau12i_op: /* TODO: add it for asm/inst.h */
> do_reloc_pcalau12i(insn, pc, v);
> break;
> default:
> panic("what the f**k");
> }
>
> Alternatively, we can also emit the pcalau12i/addi.d/lu32i/lu52i
> sequence and overwrite the pcaddu12i/ori sequence generated by the old
> toolchain.
>
> Which way do you like?

v3 tested successfully in both new and old toolchains.

Youling.
>