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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Jan 2024 23:35:50 +0000 (15:35 -0800)
[ Upstream commit 420370f3ae3d3b883813fd3051a38805160b2b9f ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
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 32336e8..a393d50 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 13ee7bf..37e87fd 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 5076764..8c3daa1 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 492dd4b..002ca58 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);