From: sashiko-bot@kernel.org
To: "Vladimir Kondratiev" <vladimir.kondratiev@mobileye.com>
Cc: linux-trace-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/2] riscv: probes: reject probes inside an LR/SC sequence
Date: Wed, 11 Nov 2026 17:21:55 +0000 [thread overview]
Message-ID: <sashiko-outbox-209404@kernel.org> (raw)
In-Reply-To: <20261111-probes-in-lrsc-v2-2-b2525b7e1e8e@mobileye.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] riscv: probes: riscv_probe_in_lrsc_body() returns false when
probing lr
- [Low] riscv: probes: missing Fixes trailer on LR/SC probe rejection
fix
--
commit fa1e6ee354b2fc2997caf3fb258fcb6a4fda3097
Author: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
> riscv: probes: reject probes inside an LR/SC sequence
>
> A kprobe or uprobe replaces an instruction with a breakpoint. The trap
> clears the hart's reservation, so if the breakpoint sits on the lr, on
> the sc, or on any instruction between them, the sc fails, the loop
> branches back to the lr and the probe fires again. The sequence never
> completes.
>
> This has always been possible on RISC-V, because cmpxchg and the
> conditional atomics are LR/SC loops. arm64 has the same problem and
> rejects probes inside an exclusive-load/store-exclusive region.
>
> Breakpoint can be on the lr unless it is part of the LR/SC loop.
>
> For the instructions between LR and SC, use the rules for a constrained
> LR/SC sequence: at most 16 instructions between lr and sc, all base
> integer instructions other than loads, stores, JALR, FENCE, SYSTEM and
> backward jumps or branches, or their compressed forms. Scan forward
> from the probed instruction. Reaching an sc through permitted
> instructions only means the probe sits inside a sequence; any other
> instruction, an lr, the end of the window or the end of the readable
> text means it does not. Only a sequence that follows these rules is
> guaranteed to make progress, so a probe inside any other one is
> already on unsupported ground. Scanning forward rather than tracking
> state from the start of the function also keeps an lr that has no sc,
> such as the one in __cmpwait() before wrs.nto, from affecting probes
> later in the same function.
>
> kprobes scan the kernel text up to the end of the enclosing symbol.
> uprobes have only the probed instruction copied, so they read the
> text that follows it from the task, which the caller's mmap_lock
> allows.
>
> Signed-off-by: Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
[Severity: Low]
Since this fixes a livelock present since kprobes and uprobes support was
added on RISC-V, should this include Fixes tags?
Fixes: c22b0bcb1dd0 ("riscv: Add kprobes supported")
Fixes: 74784081aac8 ("riscv: Add uprobes supported")
[ ... ]
> diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c
> index 433d9035b8882..0789754f682cb 100644
> --- a/arch/riscv/kernel/probes/decode-insn.c
> +++ b/arch/riscv/kernel/probes/decode-insn.c
> @@ -4,11 +4,102 @@
> #include <linux/kprobes.h>
> #include <linux/module.h>
> #include <linux/kallsyms.h>
> +#include <linux/bug.h>
> #include <asm/sections.h>
>
> #include "decode-insn.h"
> #include "simulate-insn.h"
>
> +/*
> + * Can insn sit between the lr and the sc of a constrained LR/SC sequence?
> + * The ISA allows base integer instructions there, except loads, stores,
> + * JALR, FENCE, SYSTEM, backward jumps and taken backward branches, plus
> + * their compressed forms. Backward branches are treated as not allowed:
> + * the retry branch follows the sc, so one inside the body is not a
> + * constrained sequence.
> + */
> +static bool __kprobes riscv_insn_is_lrsc_body(u32 insn)
> +{
> + u32 funct3;
> +
> + if (GET_INSN_LENGTH(insn) == 2) {
> + switch (insn & RVC_INSN_OPCODE_MASK) {
> + case RVC_OPCODE_C0:
> + /* c.addi4spn; the rest of the quadrant is loads and stores */
> + return (insn & RVC_INSN_FUNCT3_MASK) == 0;
> + case RVC_OPCODE_C1:
> + /* Arithmetic, c.j, c.jal and branches, bit 12 is the offset sign */
> + if (riscv_insn_is_c_j(insn) || riscv_insn_is_c_jal(insn) ||
> + riscv_insn_is_c_beqz(insn) || riscv_insn_is_c_bnez(insn))
> + return !(insn & BIT(12));
> + return true;
> + case RVC_OPCODE_C2:
> + funct3 = (insn & RVC_INSN_FUNCT3_MASK) >> RVC_INSN_FUNCT3_OPOFF;
> + if (funct3 == 0) /* c.slli */
> + return true;
> + if (funct3 == 4) /* c.mv, c.add, but not c.jr, c.jalr, c.ebreak */
> + return !riscv_insn_is_c_jr(insn) &&
> + !riscv_insn_is_c_jalr(insn) &&
> + !riscv_insn_is_c_ebreak(insn);
> + return false; /* stack loads and stores */
> + }
> + return false;
> + }
> +
> + switch (insn & RV_INSN_OPCODE_MASK) {
> + case RVG_OPCODE_OP_IMM:
> + case RVG_OPCODE_OP_IMM_32:
> + case RVG_OPCODE_LUI:
> + case RVG_OPCODE_AUIPC:
> + return true;
> + case RVG_OPCODE_OP:
> + case RVG_OPCODE_OP_32:
> + /* funct7 0 or 0x20 is base I; anything else is M, B or another extension */
> + return !((insn & RV_INSN_FUNCT7_MASK) & ~(0x20U << RV_INSN_FUNCT7_OPOFF));
> + case RVG_OPCODE_BRANCH:
> + case RVG_OPCODE_JAL:
> + /* forward only, bit 31 is the offset sign */
> + return !(insn & BIT(31));
> + }
> + return false;
> +}
> +
> +/*
> + * Does the instruction at the start of buf lie inside a constrained LR/SC
> + * sequence? Such a sequence holds at most RISCV_LRSC_MAX_BODY instructions
> + * between the lr and the sc, all from the set above. Walk forward from the
> + * probed instruction: reaching an sc through permitted instructions only
> + * means the probe sits in the body; anything else, including an lr that
> + * opens a new sequence, means it does not. The walk stops at the end of
> + * buf, so a short buffer only makes the answer more permissive.
> + */
> +bool __kprobes riscv_probe_in_lrsc_body(const u16 *buf, size_t len)
> +{
> + size_t off = 0;
> + u32 insn;
> + int n;
> +
> + for (n = 0; n < RISCV_LRSC_MAX_BODY + 2; n++) { // 2 for LR and SC itself
> + if (off + 2 > len)
> + return false;
> + insn = buf[off / 2];
> + if (GET_INSN_LENGTH(insn) == 4) {
> + if (off + 4 > len)
> + return false;
> + insn |= (u32)buf[off / 2 + 1] << 16;
> + }
> + /* if probed instruction is not lr, scan one instruction less */
> + if (n == 0 && !riscv_insn_is_lr(insn))
> + n++;
> + if (riscv_insn_is_sc(insn))
> + return true;
> + if (!riscv_insn_is_lrsc_body(insn))
> + return false;
[Severity: High]
Does riscv_probe_in_lrsc_body() always return false when the probed
instruction at n == 0 is lr?
When riscv_insn_is_lr(insn) is true at n == 0, execution still falls
through to riscv_insn_is_lrsc_body(insn). Because riscv_insn_is_lrsc_body()
rejects RVG_OPCODE_AMO, it returns false on the first iteration without
scanning for a matching sc, allowing probes on lr inside an LR/SC loop to
be accepted and livelock when single-stepped.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261111-probes-in-lrsc-v2-0-b2525b7e1e8e@mobileye.com?part=2
next prev parent reply other threads:[~2026-11-11 17:21 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 17:01 [PATCH v2 0/2] riscv: probes: reject probes inside an LR/SC sequence Vladimir Kondratiev
2026-11-11 17:01 ` Vladimir Kondratiev
2026-11-11 17:01 ` [PATCH v2 1/2] riscv: kprobes: fix out-of-bounds read in riscv_probe_decode_insn Vladimir Kondratiev
2026-11-11 17:01 ` Vladimir Kondratiev
2026-11-11 17:13 ` sashiko-bot
2026-11-11 17:01 ` [PATCH v2 2/2] riscv: probes: reject probes inside an LR/SC sequence Vladimir Kondratiev
2026-11-11 17:01 ` Vladimir Kondratiev
2026-11-11 17:21 ` sashiko-bot [this message]
2026-11-12 7:54 ` Nam Cao
2026-11-12 7:54 ` Nam Cao
2026-11-12 11:19 ` Vladimir Kondratiev
2026-11-12 11:19 ` Vladimir Kondratiev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-209404@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=vladimir.kondratiev@mobileye.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.