riscv: Check if the code to patch lies in the exit section
authorAlexandre Ghiti <alexghiti@rivosinc.com>
Thu, 14 Dec 2023 09:19:26 +0000 (10:19 +0100)
committerPalmer Dabbelt <palmer@rivosinc.com>
Tue, 9 Jan 2024 18:58:59 +0000 (10:58 -0800)
Otherwise we fall through to vmalloc_to_page() which panics since the
address does not lie in the vmalloc region.

Fixes: 043cb41a85de ("riscv: introduce interfaces to patch kernel code")
Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Link: https://lore.kernel.org/r/20231214091926.203439-1-alexghiti@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/sections.h
arch/riscv/kernel/patch.c
arch/riscv/kernel/vmlinux-xip.lds.S
arch/riscv/kernel/vmlinux.lds.S

index 32336e8a17cb071dce1acfd70e8f00e1765d3d05..a393d5035c54330874c49ca982f641f13c53c02e 100644 (file)
@@ -13,6 +13,7 @@ extern char _start_kernel[];
 extern char __init_data_begin[], __init_data_end[];
 extern char __init_text_begin[], __init_text_end[];
 extern char __alt_start[], __alt_end[];
+extern char __exittext_begin[], __exittext_end[];
 
 static inline bool is_va_kernel_text(uintptr_t va)
 {
index 13ee7bf589a15e1fed201415dbe352494c1ba526..37e87fdcf6a00057663ffd636c50e85e865be3c4 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/fixmap.h>
 #include <asm/ftrace.h>
 #include <asm/patch.h>
+#include <asm/sections.h>
 
 struct patch_insn {
        void *addr;
@@ -25,6 +26,14 @@ struct patch_insn {
 int riscv_patch_in_stop_machine = false;
 
 #ifdef CONFIG_MMU
+
+static inline bool is_kernel_exittext(uintptr_t addr)
+{
+       return system_state < SYSTEM_RUNNING &&
+               addr >= (uintptr_t)__exittext_begin &&
+               addr < (uintptr_t)__exittext_end;
+}
+
 /*
  * The fix_to_virt(, idx) needs a const value (not a dynamic variable of
  * reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses".
@@ -35,7 +44,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
        uintptr_t uintaddr = (uintptr_t) addr;
        struct page *page;
 
-       if (core_kernel_text(uintaddr))
+       if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr))
                page = phys_to_page(__pa_symbol(addr));
        else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
                page = vmalloc_to_page(addr);
index 50767647fbc649de81d7722528e9bcd116d88657..8c3daa1b05313af6b35311be22b7c8de3515633d 100644 (file)
@@ -29,10 +29,12 @@ SECTIONS
        HEAD_TEXT_SECTION
        INIT_TEXT_SECTION(PAGE_SIZE)
        /* we have to discard exit text and such at runtime, not link time */
+       __exittext_begin = .;
        .exit.text :
        {
                EXIT_TEXT
        }
+       __exittext_end = .;
 
        .text : {
                _text = .;
index 492dd4b8f3d69a0bcdb6e133d47d6444e2e72804..002ca58dd998cb78b662837b5ebac988fb6c77bb 100644 (file)
@@ -69,10 +69,12 @@ SECTIONS
                __soc_builtin_dtb_table_end = .;
        }
        /* we have to discard exit text and such at runtime, not link time */
+       __exittext_begin = .;
        .exit.text :
        {
                EXIT_TEXT
        }
+       __exittext_end = .;
 
        __init_text_end = .;
        . = ALIGN(SECTION_ALIGN);