Skip to content

Commit 9f564b9

Browse files
bjorn-rivospalmer-dabbelt
authored andcommitted
riscv: Only consider swbp/ss handlers for correct privileged mode
RISC-V software breakpoint trap handlers are used for {k,u}probes. When trapping from kernelmode, only the kernelmode handlers should be considered. Vice versa, only usermode handlers for usermode traps. This is not the case on RISC-V, which can trigger a bug if a userspace process uses uprobes, and a WARN() is triggered from kernelmode (which is implemented via {c.,}ebreak). The kernel will trap on the kernelmode {c.,}ebreak, look for uprobes handlers, realize incorrectly that uprobes need to be handled, and exit the trap handler early. The trap returns to re-executing the {c.,}ebreak, and enter an infinite trap-loop. The issue was found running the BPF selftest [1]. Fix this issue by only considering the swbp/ss handlers for kernel/usermode respectively. Also, move CONFIG ifdeffery from traps.c to the asm/{k,u}probes.h headers. Note that linux/uprobes.h only include asm/uprobes.h if CONFIG_UPROBES is defined, which is why asm/uprobes.h needs to be unconditionally included in traps.c Link: https://lore.kernel.org/linux-riscv/[email protected]/ # [1] Fixes: 7478408 ("riscv: Add uprobes supported") Reviewed-by: Guo Ren <[email protected]> Reviewed-by: Nam Cao <[email protected]> Tested-by: Puranjay Mohan <[email protected]> Signed-off-by: Björn Töpel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent b06fab0 commit 9f564b9

File tree

3 files changed

+40
-12
lines changed

3 files changed

+40
-12
lines changed

arch/riscv/include/asm/kprobes.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ void arch_remove_kprobe(struct kprobe *p);
4040
int kprobe_fault_handler(struct pt_regs *regs, unsigned int trapnr);
4141
bool kprobe_breakpoint_handler(struct pt_regs *regs);
4242
bool kprobe_single_step_handler(struct pt_regs *regs);
43-
43+
#else
44+
static inline bool kprobe_breakpoint_handler(struct pt_regs *regs)
45+
{
46+
return false;
47+
}
48+
49+
static inline bool kprobe_single_step_handler(struct pt_regs *regs)
50+
{
51+
return false;
52+
}
4453
#endif /* CONFIG_KPROBES */
4554
#endif /* _ASM_RISCV_KPROBES_H */

arch/riscv/include/asm/uprobes.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,18 @@ struct arch_uprobe {
3434
bool simulate;
3535
};
3636

37+
#ifdef CONFIG_UPROBES
3738
bool uprobe_breakpoint_handler(struct pt_regs *regs);
3839
bool uprobe_single_step_handler(struct pt_regs *regs);
39-
40+
#else
41+
static inline bool uprobe_breakpoint_handler(struct pt_regs *regs)
42+
{
43+
return false;
44+
}
45+
46+
static inline bool uprobe_single_step_handler(struct pt_regs *regs)
47+
{
48+
return false;
49+
}
50+
#endif /* CONFIG_UPROBES */
4051
#endif /* _ASM_RISCV_UPROBES_H */

arch/riscv/kernel/traps.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <linux/kdebug.h>
1414
#include <linux/uaccess.h>
1515
#include <linux/kprobes.h>
16+
#include <linux/uprobes.h>
17+
#include <asm/uprobes.h>
1618
#include <linux/mm.h>
1719
#include <linux/module.h>
1820
#include <linux/irq.h>
@@ -247,22 +249,28 @@ static inline unsigned long get_break_insn_length(unsigned long pc)
247249
return GET_INSN_LENGTH(insn);
248250
}
249251

252+
static bool probe_single_step_handler(struct pt_regs *regs)
253+
{
254+
bool user = user_mode(regs);
255+
256+
return user ? uprobe_single_step_handler(regs) : kprobe_single_step_handler(regs);
257+
}
258+
259+
static bool probe_breakpoint_handler(struct pt_regs *regs)
260+
{
261+
bool user = user_mode(regs);
262+
263+
return user ? uprobe_breakpoint_handler(regs) : kprobe_breakpoint_handler(regs);
264+
}
265+
250266
void handle_break(struct pt_regs *regs)
251267
{
252-
#ifdef CONFIG_KPROBES
253-
if (kprobe_single_step_handler(regs))
268+
if (probe_single_step_handler(regs))
254269
return;
255270

256-
if (kprobe_breakpoint_handler(regs))
257-
return;
258-
#endif
259-
#ifdef CONFIG_UPROBES
260-
if (uprobe_single_step_handler(regs))
271+
if (probe_breakpoint_handler(regs))
261272
return;
262273

263-
if (uprobe_breakpoint_handler(regs))
264-
return;
265-
#endif
266274
current->thread.bad_cause = regs->cause;
267275

268276
if (user_mode(regs))

0 commit comments

Comments
 (0)