Skip to content

Commit d49cce2

Browse files
guoren83gregkh
authored andcommitted
riscv: kprobe: Fixup kernel panic when probing an illegal position
[ Upstream commit 87f48c7 ] The kernel would panic when probed for an illegal position. eg: (CONFIG_RISCV_ISA_C=n) echo 'p:hello kernel_clone+0x16 a0=%a0' >> kprobe_events echo 1 > events/kprobes/hello/enable cat trace Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: __do_sys_newfstatat+0xb8/0xb8 CPU: 0 PID: 111 Comm: sh Not tainted 6.2.0-rc1-00027-g2d398fe49a4d torvalds#490 Hardware name: riscv-virtio,qemu (DT) Call Trace: [<ffffffff80007268>] dump_backtrace+0x38/0x48 [<ffffffff80c5e83c>] show_stack+0x50/0x68 [<ffffffff80c6da28>] dump_stack_lvl+0x60/0x84 [<ffffffff80c6da6c>] dump_stack+0x20/0x30 [<ffffffff80c5ecf4>] panic+0x160/0x374 [<ffffffff80c6db94>] generic_handle_arch_irq+0x0/0xa8 [<ffffffff802deeb0>] sys_newstat+0x0/0x30 [<ffffffff800158c0>] sys_clone+0x20/0x30 [<ffffffff800039e8>] ret_from_syscall+0x0/0x4 ---[ end Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: __do_sys_newfstatat+0xb8/0xb8 ]--- That is because the kprobe's ebreak instruction broke the kernel's original code. The user should guarantee the correction of the probe position, but it couldn't make the kernel panic. This patch adds arch_check_kprobe in arch_prepare_kprobe to prevent an illegal position (Such as the middle of an instruction). Fixes: c22b0bc ("riscv: Add kprobes supported") Signed-off-by: Guo Ren <[email protected]> Signed-off-by: Guo Ren <[email protected]> Reviewed-by: Björn Töpel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent e5b6da5 commit d49cce2

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

arch/riscv/kernel/probes/kprobes.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
4646
post_kprobe_handler(p, kcb, regs);
4747
}
4848

49+
static bool __kprobes arch_check_kprobe(struct kprobe *p)
50+
{
51+
unsigned long tmp = (unsigned long)p->addr - p->offset;
52+
unsigned long addr = (unsigned long)p->addr;
53+
54+
while (tmp <= addr) {
55+
if (tmp == addr)
56+
return true;
57+
58+
tmp += GET_INSN_LENGTH(*(u16 *)tmp);
59+
}
60+
61+
return false;
62+
}
63+
4964
int __kprobes arch_prepare_kprobe(struct kprobe *p)
5065
{
5166
unsigned long probe_addr = (unsigned long)p->addr;
@@ -56,6 +71,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
5671
return -EINVAL;
5772
}
5873

74+
if (!arch_check_kprobe(p))
75+
return -EILSEQ;
76+
5977
/* copy instruction */
6078
p->opcode = *p->addr;
6179

0 commit comments

Comments
 (0)