riscv: add icache flush for nommu sigreturn trampoline
authorMathis Salmen <mathis.salmen@matsal.de>
Thu, 6 Apr 2023 10:11:31 +0000 (12:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Apr 2023 10:35:12 +0000 (12:35 +0200)
commit 8d736482749f6d350892ef83a7a11d43cd49981e upstream.

In a NOMMU kernel, sigreturn trampolines are generated on the user
stack by setup_rt_frame. Currently, these trampolines are not instruction
fenced, thus their visibility to ifetch is not guaranteed.

This patch adds a flush_icache_range in setup_rt_frame to fix this
problem.

Signed-off-by: Mathis Salmen <mathis.salmen@matsal.de>
Fixes: 6bd33e1ece52 ("riscv: add nommu support")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20230406101130.82304-1-mathis.salmen@matsal.de
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/riscv/kernel/signal.c

index bfb2afa4135f89690b90da20d281252a539d8cda..dee66c9290ccee95e20f93517e47d16a133b02bb 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/signal32.h>
 #include <asm/switch_to.h>
 #include <asm/csr.h>
 #include <asm/signal32.h>
 #include <asm/switch_to.h>
 #include <asm/csr.h>
+#include <asm/cacheflush.h>
 
 extern u32 __user_rt_sigreturn[2];
 
 
 extern u32 __user_rt_sigreturn[2];
 
@@ -181,6 +182,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 {
        struct rt_sigframe __user *frame;
        long err = 0;
 {
        struct rt_sigframe __user *frame;
        long err = 0;
+       unsigned long __maybe_unused addr;
 
        frame = get_sigframe(ksig, regs, sizeof(*frame));
        if (!access_ok(frame, sizeof(*frame)))
 
        frame = get_sigframe(ksig, regs, sizeof(*frame));
        if (!access_ok(frame, sizeof(*frame)))
@@ -209,7 +211,12 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
        if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn,
                         sizeof(frame->sigreturn_code)))
                return -EFAULT;
        if (copy_to_user(&frame->sigreturn_code, __user_rt_sigreturn,
                         sizeof(frame->sigreturn_code)))
                return -EFAULT;
-       regs->ra = (unsigned long)&frame->sigreturn_code;
+
+       addr = (unsigned long)&frame->sigreturn_code;
+       /* Make sure the two instructions are pushed to icache. */
+       flush_icache_range(addr, addr + sizeof(frame->sigreturn_code));
+
+       regs->ra = addr;
 #endif /* CONFIG_MMU */
 
        /*
 #endif /* CONFIG_MMU */
 
        /*