* [PATCH v6 0/2] riscv: kprobes: reject probes inside LR/SC sequences @ 2026-10-16 8:17 Xiaofeng Yuan 2026-10-16 8:17 ` [PATCH v6 1/2] " Xiaofeng Yuan 2026-10-16 8:17 ` [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection Xiaofeng Yuan 0 siblings, 2 replies; 6+ messages in thread From: Xiaofeng Yuan @ 2026-10-16 8:17 UTC (permalink / raw) To: Paul Walmsley, Palmer Dabbelt, Albert Ou Cc: Alexandre Ghiti, Nam Cao, Naveen N Rao, David S . Miller, Masami Hiramatsu, linux-riscv, linux-kernel, linux-trace-kernel, Xiaofeng Yuan A breakpoint trap taken in the middle of an LR/SC sequence clears the load reservation, so an SC following the probed instruction always fails and the enclosing retry loop re-enters the breakpoint, livelocking the CPU. This series makes the RISC-V kprobes implementation reject probes placed on an LR/SC instruction or between them, following arm64's approach for its equivalent exclusive load/store instructions. Changes since v5: - Fix a dangling stack pointer in the KUnit test: a probe that was expected to be rejected but was unexpectedly registered stayed on a stack-allocated kprobe. - Add Acked-by: Masami Hiramatsu to the implementation patch. - Annotate that test_kprobes_lrsc() is never executed and that reject[] must match the length of test_kprobes_lrsc_offsets[]. Verified by cross-compiling for RISC-V and running the kprobes KUnit test in QEMU (ok 2 kprobes_riscv). Xiaofeng Yuan (2): riscv: kprobes: reject probes inside LR/SC sequences riscv: kprobes: add KUnit test for LR/SC sequence rejection arch/riscv/include/asm/insn.h | 33 ++++++++++ arch/riscv/kernel/probes/decode-insn.c | 2 + arch/riscv/kernel/probes/kprobes.c | 63 +++++++++++++++---- .../kernel/tests/kprobes/test-kprobes-asm.S | 30 +++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.c | 31 +++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.h | 3 + 6 files changed, 150 insertions(+), 12 deletions(-) -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 1/2] riscv: kprobes: reject probes inside LR/SC sequences 2026-10-16 8:17 [PATCH v6 0/2] riscv: kprobes: reject probes inside LR/SC sequences Xiaofeng Yuan @ 2026-10-16 8:17 ` Xiaofeng Yuan 2026-10-16 10:13 ` Nam Cao [not found] ` <sashiko-outbox-174019@kernel.org> 2026-10-16 8:17 ` [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection Xiaofeng Yuan 1 sibling, 2 replies; 6+ messages in thread From: Xiaofeng Yuan @ 2026-10-16 8:17 UTC (permalink / raw) To: Paul Walmsley, Palmer Dabbelt, Albert Ou Cc: Alexandre Ghiti, Nam Cao, Naveen N Rao, David S . Miller, Masami Hiramatsu, linux-riscv, linux-kernel, linux-trace-kernel, Xiaofeng Yuan A trap taken in the middle of an LR/SC sequence clears the load reservation, so an SC following the probed instruction always fails and the enclosing retry loop re-enters the breakpoint, livelocking the CPU. Reject probes of the LR/SC instructions themselves and of any address between them. arm64's kprobes rejects its equivalent exclusive load/store instructions and, in arm_kprobe_decode_insn(), walks backward from the probe address (bounded by the enclosing symbol) to reject any address inside an exclusive sequence. RISC-V cannot walk backward because variable-length instructions make instruction boundaries ambiguous, so walk forward from the enclosing symbol, a known instruction boundary, up to the probe address and track whether an LR is still outstanding. A Zalrsc-constrained LR/SC retry loop holds at most 16 instructions, so an LR more than MAX_LRSC_GAP instructions ahead of the probe cannot start a sequence containing it. Count instructions, not bytes: compressed instructions would make a byte window ambiguous. The LR/SC instructions themselves are rejected in riscv_probe_decode_insn(), and an address inside a sequence is rejected in arch_check_kprobe(). Signed-off-by: Xiaofeng Yuan <yuanxiaofeng@eswincomputing.com> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> --- arch/riscv/include/asm/insn.h | 33 ++++++++++++++ arch/riscv/kernel/probes/decode-insn.c | 2 + arch/riscv/kernel/probes/kprobes.c | 63 +++++++++++++++++++++----- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h index ad348d8b8..46a1666d2 100644 --- a/arch/riscv/include/asm/insn.h +++ b/arch/riscv/include/asm/insn.h @@ -141,6 +141,7 @@ #define RVG_OPCODE_JALR 0x67 #define RVG_OPCODE_JAL 0x6f #define RVG_OPCODE_SYSTEM 0x73 +#define RVG_OPCODE_AMO 0x2f #define RVG_SYSTEM_CSR_OFF 20 #define RVG_SYSTEM_CSR_MASK GENMASK(11, 0) @@ -175,6 +176,8 @@ #define RVG_FUNCT3_BGE 0x5 #define RVG_FUNCT3_BLTU 0x6 #define RVG_FUNCT3_BGEU 0x7 +#define RVG_FUNCT3_AMO_W 0x2 +#define RVG_FUNCT3_AMO_D 0x3 /* parts of funct3 code for C extension*/ #define RVC_FUNCT3_C_BEQZ 0x6 @@ -263,6 +266,36 @@ __RISCV_INSN_FUNCS(ebreak, RVG_MASK_EBREAK, RVG_MATCH_EBREAK) __RISCV_INSN_FUNCS(sret, RVG_MASK_SRET, RVG_MATCH_SRET) __RISCV_INSN_FUNCS(fence, RVG_MASK_FENCE, RVG_MATCH_FENCE); +/* + * LR/SC are identified by the AMO opcode plus the funct3 width field + * (.w/.d) and the funct5 field (funct7[6:2]) distinguishing LR from SC. + * The aq/rl bits (funct7[1:0]) are ignored. For LR the rs2 field must + * encode x0. + */ +#define RVG_AMO_FUNCT5_LR 0x02 +#define RVG_AMO_FUNCT5_SC 0x03 + +static __always_inline bool riscv_insn_is_lr(u32 code) +{ + u32 funct5 = (code >> 27) & 0x1f; + u32 funct3 = (code >> 12) & 0x7; + + return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_AMO && + funct5 == RVG_AMO_FUNCT5_LR && + (funct3 == RVG_FUNCT3_AMO_W || funct3 == RVG_FUNCT3_AMO_D) && + !(code & GENMASK(24, 20)); +} + +static __always_inline bool riscv_insn_is_sc(u32 code) +{ + u32 funct5 = (code >> 27) & 0x1f; + u32 funct3 = (code >> 12) & 0x7; + + return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_AMO && + funct5 == RVG_AMO_FUNCT5_SC && + (funct3 == RVG_FUNCT3_AMO_W || funct3 == RVG_FUNCT3_AMO_D); +} + /* special case to catch _any_ system instruction */ static __always_inline bool riscv_insn_is_system(u32 code) { diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c index 433d9035b..e6a889467 100644 --- a/arch/riscv/kernel/probes/decode-insn.c +++ b/arch/riscv/kernel/probes/decode-insn.c @@ -23,6 +23,8 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api) */ RISCV_INSN_REJECTED(system, insn); RISCV_INSN_REJECTED(fence, insn); + RISCV_INSN_REJECTED(lr, insn); + RISCV_INSN_REJECTED(sc, insn); /* * Simulate instructions list: diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index a76eab297..8f20f1535 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -7,11 +7,13 @@ #include <linux/slab.h> #include <linux/stop_machine.h> #include <linux/vmalloc.h> +#include <linux/unaligned.h> #include <asm/ptrace.h> #include <linux/uaccess.h> #include <asm/sections.h> #include <asm/cacheflush.h> #include <asm/bug.h> +#include <asm/insn.h> #include <asm/text-patching.h> #include "decode-insn.h" @@ -49,35 +51,72 @@ 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(unsigned long addr) +/* + * A trap taken in the middle of an LR/SC sequence clears the load + * reservation, so an SC following the probed instruction would always + * fail and the enclosing retry loop would re-enter the breakpoint. + * Reject probes inside such a sequence. + * + * RISC-V instruction boundaries cannot be recovered by walking + * backwards - a 32-bit instruction whose upper halfword looks like a + * compressed instruction is ambiguous - so walk forward from the + * enclosing symbol, a known instruction boundary, up to the probe address + * and track whether an LR is still outstanding. A Zalrsc-constrained + * LR/SC retry loop holds at most 16 instructions, so an LR more than + * that many instructions ahead of the probe cannot start a sequence + * containing it. Count instructions, not bytes: compressed + * instructions would make a byte window ambiguous. + */ +#define MAX_LRSC_GAP 16 + +/* + * Verify that @addr points at the start of an instruction and is not + * inside an LR/SC sequence. Returns 0 on success, -EILSEQ if @addr is + * not an instruction boundary, or -EINVAL if the probe would land + * inside an LR/SC sequence. + */ +static int __kprobes arch_check_kprobe(unsigned long addr) { - unsigned long tmp, offset; + unsigned long pc, offset; + int outstanding_lr = -1; - /* start iterating at the closest preceding symbol */ if (!kallsyms_lookup_size_offset(addr, NULL, &offset)) - return false; + return -EILSEQ; - tmp = addr - offset; + /* pc starts at the closest preceding symbol, a known instruction boundary */ + pc = addr - offset; - while (tmp <= addr) { - if (tmp == addr) - return true; + while (pc < addr) { + u32 insn = get_unaligned((u32 *)pc); + unsigned int len = GET_INSN_LENGTH(insn); - tmp += GET_INSN_LENGTH(*(u16 *)tmp); + if (riscv_insn_is_lr(insn)) + outstanding_lr = 0; + else if (riscv_insn_is_sc(insn)) + outstanding_lr = -1; + else if (outstanding_lr >= 0 && ++outstanding_lr > MAX_LRSC_GAP) + outstanding_lr = -1; + + pc += len; } - return false; + if (pc != addr) + return -EILSEQ; + + return outstanding_lr >= 0 ? -EINVAL : 0; } int __kprobes arch_prepare_kprobe(struct kprobe *p) { u16 *insn = (u16 *)p->addr; + int ret; if ((unsigned long)insn & 0x1) return -EILSEQ; - if (!arch_check_kprobe((unsigned long)p->addr)) - return -EILSEQ; + ret = arch_check_kprobe((unsigned long)p->addr); + if (ret) + return ret; /* copy instruction */ p->opcode = (kprobe_opcode_t)(*insn++); -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 1/2] riscv: kprobes: reject probes inside LR/SC sequences 2026-10-16 8:17 ` [PATCH v6 1/2] " Xiaofeng Yuan @ 2026-10-16 10:13 ` Nam Cao [not found] ` <sashiko-outbox-174019@kernel.org> 1 sibling, 0 replies; 6+ messages in thread From: Nam Cao @ 2026-10-16 10:13 UTC (permalink / raw) To: Xiaofeng Yuan, Paul Walmsley, Palmer Dabbelt, Albert Ou Cc: Alexandre Ghiti, Naveen N Rao, David S . Miller, Masami Hiramatsu, linux-riscv, linux-kernel, linux-trace-kernel, Xiaofeng Yuan Xiaofeng Yuan <yuanxiaofeng@eswincomputing.com> writes: > +static __always_inline bool riscv_insn_is_lr(u32 code) > +{ > + u32 funct5 = (code >> 27) & 0x1f; > + u32 funct3 = (code >> 12) & 0x7; > + > + return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_AMO && > + funct5 == RVG_AMO_FUNCT5_LR && > + (funct3 == RVG_FUNCT3_AMO_W || funct3 == RVG_FUNCT3_AMO_D) && > + !(code & GENMASK(24, 20)); > +} > + > +static __always_inline bool riscv_insn_is_sc(u32 code) > +{ > + u32 funct5 = (code >> 27) & 0x1f; > + u32 funct3 = (code >> 12) & 0x7; > + > + return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_AMO && > + funct5 == RVG_AMO_FUNCT5_SC && > + (funct3 == RVG_FUNCT3_AMO_W || funct3 == RVG_FUNCT3_AMO_D); > +} There are already RV_EXTRACT_FUNCT3() and RV_EXTRACT_RS2_REG(), we should use them to avoid code duplications. And I think we should also have RV_EXTRACT_FUNCT5() to stay consistent. > +static int __kprobes arch_check_kprobe(unsigned long addr) > { > - unsigned long tmp, offset; > + unsigned long pc, offset; > + int outstanding_lr = -1; > > - /* start iterating at the closest preceding symbol */ > if (!kallsyms_lookup_size_offset(addr, NULL, &offset)) > - return false; > + return -EILSEQ; > > - tmp = addr - offset; > + /* pc starts at the closest preceding symbol, a known instruction boundary */ > + pc = addr - offset; > > - while (tmp <= addr) { > - if (tmp == addr) > - return true; > + while (pc < addr) { > + u32 insn = get_unaligned((u32 *)pc); > + unsigned int len = GET_INSN_LENGTH(insn); > > - tmp += GET_INSN_LENGTH(*(u16 *)tmp); > + if (riscv_insn_is_lr(insn)) > + outstanding_lr = 0; > + else if (riscv_insn_is_sc(insn)) > + outstanding_lr = -1; > + else if (outstanding_lr >= 0 && ++outstanding_lr > MAX_LRSC_GAP) > + outstanding_lr = -1; > + > + pc += len; > } The spec says "The loop comprises only an LR/SC sequence and code to retry the sequence in the case of failure, and must comprise at most 16 instructions placed sequentially in memory". The 16 instructions limit includes LR. So I think this implementation is off by one: lr (outstanding_lr=0) inst1 (outstanding_lr=1) inst2 (outstanding_lr=2) ... inst16 (outstanding_lr=16) inst17 (outstanding_lr=-1) As it is considering instruction from LR to inst16 to be a loop, so it allows 17 instructions. Nam ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <sashiko-outbox-174019@kernel.org>]
* Re: Re: [PATCH v6 1/2] riscv: kprobes: reject probes inside LR/SC sequences [not found] ` <sashiko-outbox-174019@kernel.org> @ 2026-10-19 3:32 ` 袁晓峰 0 siblings, 0 replies; 6+ messages in thread From: 袁晓峰 @ 2026-10-19 3:32 UTC (permalink / raw) To: Masami Hiramatsu, sashiko-reviews Cc: linux-trace-kernel, Paul Walmsley, Palmer Dabbelt, Albert Ou, Nam Cao, Alexandre Ghiti, Naveen N Rao, David S. Miller, linux-riscv, linux-kernel Hi Masami, I looked into the issue Sashiko reported for riscv_probe_decode_insn(). Sharing the analysis below; the short version is that this read predates this series, and I'm happy to send a separate patch if the maintainers think it is worth fixing. First, the context: "probe_opcode_t insn = *addr;" is pre-existing code. This series only adds two RISCV_INSN_REJECTED() entries, which consume the already-loaded value and do not change how memory is accessed. On the unaligned part: with default configurations, misaligned accesses are emulated, either by the firmware or by the kernel itself (RISCV_SCALAR_MISALIGNED), so an oops would require a NONPORTABLE kernel built with RISCV_SLOW/EFFICIENT_UNALIGNED_ACCESS running on hardware that does not actually support unaligned accesses. On the page-crossing part: this one is real in theory, though the window is narrow. It cannot happen for built-in kernel text (the linear mapping is contiguous). For modules, it needs a compressed instruction at the last two bytes of a module text page followed by the vmalloc guard page, plus a kprobe registered exactly there. A 32-bit instruction cannot sit at that location on a working module (its encoding would cross into the unmapped guard page, so it could never be fetched), which is also why the two-u16-step copy in arch_prepare_kprobe() is safe. If it is worth fixing, the cleanest approach seems to be passing the opcode by value instead of a pointer: arch_prepare_kprobe() already holds a safely copied p->opcode, and the uprobes caller passes a stack variable, so both call sites would be covered. There is a third similar raw read in uprobes.c (the auprobe->insn[] dereference) that could be folded in as well. Either way, this doesn't need to be handled in the series: the upcoming v7 will only address Nam's review comments. Thanks, Xiaofeng > -----原始邮件----- > 发件人: sashiko-bot@kernel.org > 发送时间:2026-10-16 16:29:42 (星期五) > 收件人: "Xiaofeng Yuan" <yuanxiaofeng@eswincomputing.com> > 抄送: linux-trace-kernel@vger.kernel.org > 主题: Re: [PATCH v6 1/2] riscv: kprobes: reject probes inside LR/SC sequences > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [High] riscv: kprobes: unsafe 32-bit read in riscv_probe_decode_insn can page fault > -- > > commit 6f940578d2f096970e9abd6cc2894de008e29f6f > Author: Xiaofeng Yuan <yuanxiaofeng@eswincomputing.com> > > riscv: kprobes: reject probes inside LR/SC sequences > > This patch rejects kprobes placed inside LR/SC sequences or on the LR/SC > instructions themselves to avoid livelock. It updates riscv_probe_decode_insn() > to reject the instructions and adds instruction walking logic in > arch_check_kprobe() to reject addresses within a sequence. > > [ ... ] > > > diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c > > index 433d9035b8882..e6a8894677b10 100644 > > --- a/arch/riscv/kernel/probes/decode-insn.c > > +++ b/arch/riscv/kernel/probes/decode-insn.c > > @@ -23,6 +23,8 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api) > > */ > > RISCV_INSN_REJECTED(system, insn); > > RISCV_INSN_REJECTED(fence, insn); > > + RISCV_INSN_REJECTED(lr, insn); > > + RISCV_INSN_REJECTED(sc, insn); > > [Severity: High] > Does evaluating these macros rely on the insn variable, which is read > unconditionally as a native 32-bit integer earlier in the function? > > arch/riscv/kernel/probes/decode-insn.c:riscv_probe_decode_insn() { > probe_opcode_t insn = *addr; > ... > > If addr is 2-byte aligned, will this native 32-bit dereference perform > an unaligned memory access, potentially oopsing on RISC-V hardware that > lacks kernel-mode unaligned access support? > > Furthermore, if addr points to a 16-bit compressed instruction at the > end of a mapped page and the next page is an unmapped vmalloc guard > page, could this 32-bit read cross the page boundary into unmapped > memory? > > Would this trigger a kernel page fault and panic when tracing tools > register a kprobe at such an address? > > -- > Sashiko AI review · https://sashiko.dev/#/patchset/20261016081706.1085-1-yuanxiaofeng@eswincomputing.com?part=1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection 2026-10-16 8:17 [PATCH v6 0/2] riscv: kprobes: reject probes inside LR/SC sequences Xiaofeng Yuan 2026-10-16 8:17 ` [PATCH v6 1/2] " Xiaofeng Yuan @ 2026-10-16 8:17 ` Xiaofeng Yuan 2026-10-16 10:42 ` Nam Cao 1 sibling, 1 reply; 6+ messages in thread From: Xiaofeng Yuan @ 2026-10-16 8:17 UTC (permalink / raw) To: Paul Walmsley, Palmer Dabbelt, Albert Ou Cc: Alexandre Ghiti, Nam Cao, Naveen N Rao, David S . Miller, Masami Hiramatsu, linux-riscv, linux-kernel, linux-trace-kernel, Xiaofeng Yuan Extend the kprobes KUnit test with a function containing an LR/SC sequence and assert that register_kprobe() accepts a probe placed right before or right after the sequence, and rejects a probe placed on the LR, on an instruction inside the sequence, or on the SC. Signed-off-by: Xiaofeng Yuan <yuanxiaofeng@eswincomputing.com> --- .../kernel/tests/kprobes/test-kprobes-asm.S | 30 ++++++++++++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.c | 31 +++++++++++++++++++ .../riscv/kernel/tests/kprobes/test-kprobes.h | 3 ++ 3 files changed, 64 insertions(+) diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S b/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S index 15e50934b..76826bf7e 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes-asm.S @@ -100,6 +100,27 @@ test_kprobes_branch_addr8: .option pop SYM_FUNC_END(test_kprobes_branch) +/* + * This function is never executed; it only provides the probe addresses + * in test_kprobes_lrsc_offsets[] for test_kprobe_lrsc(). The lr.w/sc.w + * use the invalid address 0(x0) and would fault if executed, so do not + * add this function to test_kprobes_functions[]. + */ +SYM_FUNC_START(test_kprobes_lrsc) +.Llrsc_before: + nop +1: +.Llrsc_lr: + lr.w t0, 0(x0) +.Llrsc_inside: + addi t0, t0, 1 +.Llrsc_sc: + sc.w t0, t0, 0(x0) + bnez t0, 1b +.Llrsc_after: + ret +SYM_FUNC_END(test_kprobes_lrsc) + #ifdef CONFIG_RISCV_ISA_C SYM_FUNC_START(test_kprobes_c_j) @@ -253,3 +274,12 @@ SYM_DATA_START(test_kprobes_functions) #endif /* CONFIG_RISCV_ISA_C */ RISCV_PTR 0 SYM_DATA_END(test_kprobes_functions) + +.section .rodata +SYM_DATA_START(test_kprobes_lrsc_offsets) + RISCV_PTR .Llrsc_before + RISCV_PTR .Llrsc_lr + RISCV_PTR .Llrsc_inside + RISCV_PTR .Llrsc_sc + RISCV_PTR .Llrsc_after +SYM_DATA_END(test_kprobes_lrsc_offsets) diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.c b/arch/riscv/kernel/tests/kprobes/test-kprobes.c index 027424a3f..c2d9c87f2 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes.c +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.c @@ -43,8 +43,39 @@ static void test_kprobe_riscv(struct kunit *test) kfree(kp); } +static void test_kprobe_lrsc(struct kunit *test) +{ + /* + * test_kprobes_lrsc_offsets[] points, in order, at an instruction + * right before an LR/SC sequence, the LR itself, an instruction + * inside the sequence, the SC, and an instruction right after it. + * reject[] must have the same number of entries. + */ + bool reject[] = { false, true, true, true, false }; + int i; + + for (i = 0; i < ARRAY_SIZE(reject); i++) { + struct kprobe kp = {}; + int ret; + + kp.pre_handler = kprobe_dummy_handler; + kp.addr = (kprobe_opcode_t *)test_kprobes_lrsc_offsets[i]; + + ret = register_kprobe(&kp); + + if (reject[i]) + KUNIT_EXPECT_LT(test, ret, 0); + else + KUNIT_EXPECT_EQ(test, ret, 0); + + if (!ret) + unregister_kprobe(&kp); + } +} + static struct kunit_case kprobes_testcases[] = { KUNIT_CASE(test_kprobe_riscv), + KUNIT_CASE(test_kprobe_lrsc), {} }; diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.h b/arch/riscv/kernel/tests/kprobes/test-kprobes.h index 537f44aa9..65a8e7217 100644 --- a/arch/riscv/kernel/tests/kprobes/test-kprobes.h +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.h @@ -19,6 +19,9 @@ extern void *test_kprobes_addresses[]; /* array of functions that return KPROBE_TEST_MAGIC */ extern long (*test_kprobes_functions[])(void); +/* offsets of the probe points inside test_kprobes_lrsc() */ +extern void *test_kprobes_lrsc_offsets[]; + #endif /* __ASSEMBLER__ */ #endif /* TEST_KPROBES_H */ -- 2.34.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection 2026-10-16 8:17 ` [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection Xiaofeng Yuan @ 2026-10-16 10:42 ` Nam Cao 0 siblings, 0 replies; 6+ messages in thread From: Nam Cao @ 2026-10-16 10:42 UTC (permalink / raw) To: Xiaofeng Yuan, Paul Walmsley, Palmer Dabbelt, Albert Ou Cc: Alexandre Ghiti, Naveen N Rao, David S . Miller, Masami Hiramatsu, linux-riscv, linux-kernel, linux-trace-kernel, Xiaofeng Yuan Xiaofeng Yuan <yuanxiaofeng@eswincomputing.com> writes: > +.section .rodata > +SYM_DATA_START(test_kprobes_lrsc_offsets) > + RISCV_PTR .Llrsc_before > + RISCV_PTR .Llrsc_lr > + RISCV_PTR .Llrsc_inside > + RISCV_PTR .Llrsc_sc > + RISCV_PTR .Llrsc_after > +SYM_DATA_END(test_kprobes_lrsc_offsets) "_offsets" is not precise, as this array has absolute addresses. Maybe rename to "_addresses"? > diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.c b/arch/riscv/kernel/tests/kprobes/test-kprobes.c > index 027424a3f..c2d9c87f2 100644 > --- a/arch/riscv/kernel/tests/kprobes/test-kprobes.c > +++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.c > @@ -43,8 +43,39 @@ static void test_kprobe_riscv(struct kunit *test) > kfree(kp); > } > > +static void test_kprobe_lrsc(struct kunit *test) > +{ > + /* > + * test_kprobes_lrsc_offsets[] points, in order, at an instruction > + * right before an LR/SC sequence, the LR itself, an instruction > + * inside the sequence, the SC, and an instruction right after it. > + * reject[] must have the same number of entries. > + */ > + bool reject[] = { false, true, true, true, false }; I am not a fan of coupled code. A change at test_kprobes_lrsc_offsets mandates a change here. Instead of this, how about we split test_kprobes_lrsc_offsets into test_kprobes_lrsc_allowed_addresses and test_kprobes_lrsc_rejected_addresses? Nam ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-19 3:32 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-16 8:17 [PATCH v6 0/2] riscv: kprobes: reject probes inside LR/SC sequences Xiaofeng Yuan
2026-10-16 8:17 ` [PATCH v6 1/2] " Xiaofeng Yuan
2026-10-16 10:13 ` Nam Cao
[not found] ` <sashiko-outbox-174019@kernel.org>
2026-10-19 3:32 ` 袁晓峰
2026-10-16 8:17 ` [PATCH v6 2/2] riscv: kprobes: add KUnit test for LR/SC sequence rejection Xiaofeng Yuan
2026-10-16 10:42 ` Nam Cao
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®