diff options
| author | Fabian Vogt <fvogt@suse.de> | 2025-09-10 17:25:13 +0200 |
|---|---|---|
| committer | Paul Walmsley <pjw@kernel.org> | 2025-10-09 19:36:45 -0600 |
| commit | 9e68bd803fac49274fde914466fd3b07c4d602c8 (patch) | |
| tree | 165f7102554fb236fd26f02ce55530f9b6a295b8 /arch | |
| parent | c199745d3ac3f836515a5734a6ca5c6f55a8809b (diff) | |
| download | linux-9e68bd803fac49274fde914466fd3b07c4d602c8.tar.gz linux-9e68bd803fac49274fde914466fd3b07c4d602c8.tar.bz2 linux-9e68bd803fac49274fde914466fd3b07c4d602c8.zip | |
riscv: kprobes: Fix probe address validation
When adding a kprobe such as "p:probe/tcp_sendmsg _text+15392192",
arch_check_kprobe would start iterating all instructions starting from
_text until the probed address. Not only is this very inefficient, but
literal values in there (e.g. left by function patching) are
misinterpreted in a way that causes a desync.
Fix this by doing it like x86: start the iteration at the closest
preceding symbol instead of the given starting point.
Fixes: 87f48c7ccc73 ("riscv: kprobe: Fixup kernel panic when probing an illegal position")
Signed-off-by: Fabian Vogt <fvogt@suse.de>
Signed-off-by: Marvin Friedrich <marvin.friedrich@suse.com>
Acked-by: Guo Ren <guoren@kernel.org>
Link: https://lore.kernel.org/r/6191817.lOV4Wx5bFT@fvogt-thinkpad
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/riscv/kernel/probes/kprobes.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index c0738d6c6498..8723390c7cad 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -49,10 +49,15 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs) post_kprobe_handler(p, kcb, regs); } -static bool __kprobes arch_check_kprobe(struct kprobe *p) +static bool __kprobes arch_check_kprobe(unsigned long addr) { - unsigned long tmp = (unsigned long)p->addr - p->offset; - unsigned long addr = (unsigned long)p->addr; + unsigned long tmp, offset; + + /* start iterating at the closest preceding symbol */ + if (!kallsyms_lookup_size_offset(addr, NULL, &offset)) + return false; + + tmp = addr - offset; while (tmp <= addr) { if (tmp == addr) @@ -71,7 +76,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if ((unsigned long)insn & 0x1) return -EILSEQ; - if (!arch_check_kprobe(p)) + if (!arch_check_kprobe((unsigned long)p->addr)) return -EILSEQ; /* copy instruction */ |
