* [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_SDIV and BPF_SMOD in RV32 JIT
[not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:46 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] RISC-V: errata: Add SiFive MAL-9092 workaround Sasha Levin
` (4 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:46 UTC (permalink / raw)
To: patches, stable
Cc: Kuan-Wei Chiu, Pu Lehui, Kumar Kartikeya Dwivedi, Sasha Levin,
ast, daniel, andrii, eddyz87, luke.r.nels, xi.wang, pjw, palmer,
aou, bpf, linux-riscv, linux-kernel
From: Kuan-Wei Chiu <visitorckw@gmail.com>
[ Upstream commit 2e0fa2389c50fd3a69bb738efa74e127b7516938 ]
The current rv32 bpf jit compiler incorrectly treats BPF_SDIV and
BPF_SMOD as unsigned operations. The BPF instruction set allows
signed division and modulo by reusing the BPF_DIV and BPF_MOD opcodes
with the instruction offset set to 1.
Update the emit_alu_r32() function to accept an 'is_sdiv' variable and
emit the correct div and rem instructions when the offset is 1.
Before this patch:
[ 44.161771] test_bpf: #165 ALU_SDIV_X: -6 / 2 = -3 jited:1 ret 2147483645 != -3 (0x7ffffffd != 0xfffffffd)FAIL (1 times)
[ 44.167385] test_bpf: #166 ALU_SDIV_K: -6 / 2 = -3 jited:1 ret 2147483645 != -3 (0x7ffffffd != 0xfffffffd)FAIL (1 times)
[ 44.171053] test_bpf: #169 ALU_SMOD_X: -7 % 2 = -1 jited:1 ret 1 != -1 (0x1 != 0xffffffff)FAIL (1 times)
[ 44.172081] test_bpf: #170 ALU_SMOD_K: -7 % 2 = -1 jited:1 ret 1 != -1 (0x1 != 0xffffffff)FAIL (1 times)
After this patch:
[ 16.002192] test_bpf: #165 ALU_SDIV_X: -6 / 2 = -3 jited:1 95 PASS
[ 16.002983] test_bpf: #166 ALU_SDIV_K: -6 / 2 = -3 jited:1 1059 PASS
[ 16.017167] test_bpf: #169 ALU_SMOD_X: -7 % 2 = -1 jited:1 136 PASS
[ 16.023002] test_bpf: #170 ALU_SMOD_K: -7 % 2 = -1 jited:1 109 PASS
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Reviewed-by: Pu Lehui <pulehui@huawei.com>
Link: https://lore.kernel.org/bpf/20260714002451.4091139-2-visitorckw@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1 — Subject**
Record: `[riscv, bpf] [Add support] Treat BPF_SDIV/BPF_SMOD as signed in
the RV32 JIT, not as unsigned DIV/MOD.`
**Step 1.2 — Tags**
Record:
- Reviewed-by: Pu Lehui `<pulehui@huawei.com>` (RISC-V BPF JIT reviewer;
author of the RV64 signed-div JIT)
- Link: `https://lore.kernel.org/bpf/20260714002451.4091139-2-
visitorckw@gmail.com`
- Signed-off-by: Kuan-Wei Chiu (author)
- Signed-off-by: Kumar Kartikeya Dwivedi (BPF maintainer, applied to
bpf-next)
- No Fixes:, no Cc: stable, no Reported-by, no Tested-by on the commit
itself (Tested-by: Pu Lehui is on the series cover)
- Absence of Fixes/Cc: stable is expected for this review and is not a
negative signal
**Step 1.3 — Body**
Record: The RV32 JIT emits `divu`/`remu` for `BPF_DIV`/`BPF_MOD` even
when `insn->off == 1` (the BPF encoding for signed div/mod). Symptom is
silent wrong results with the program still marked JIT’d (`jited:1`):
`-6 / 2` → `2147483645` instead of `-3`; `-7 % 2` → `1` instead of `-1`.
Root cause: offset field ignored. After: those `test_bpf` cases PASS.
**Step 1.4 — Hidden bug fix?**
Record: Yes. Title says “Add support”, but this is a JIT miscompilation
fix. The JIT already handles DIV/MOD; it just uses the unsigned RISC-V
ops. Cover-letter v3 dropped a Fixes: tag and retitled the series as
enablement; that is framing, not a lack of a bug.
## Phase 2: Diff analysis
**Step 2.1 — Inventory**
Record: One file, `arch/riscv/net/bpf_jit_comp32.c`, +10/−5. Functions:
`emit_alu_r32()` (signature + DIV/MOD cases), `bpf_jit_emit_insn()` (two
call sites). Surgical, single-file.
**Step 2.2 — Flow**
Record:
- Before: `emit_alu_r32(..., u8 op)` always emits `rv_divu` / `rv_remu`.
- After: it takes `const struct bpf_insn *insn`, sets `is_signed =
insn->off == 1`, and emits `rv_div`/`rv_rem` vs `rv_divu`/`rv_remu`.
- Callers pass `insn` instead of `BPF_OP(code)`. Both register (`BPF_X`)
and immediate (`BPF_K`) 32-bit DIV/MOD already go through this path
(no RISC-V I-type div).
- 64-bit DIV/MOD on RV32 still `goto notsupported` (interpreter
fallback). This patch does not touch that path.
**Step 2.3 — Bug mechanism**
Record: Logic/correctness. Signed vs unsigned opcode selected by
`insn->off`. Not a leak, race, or UAF.
**Step 2.4 — Fix quality**
Record: Obviously correct and minimal. Regression risk is low: unsigned
path is unchanged when `off == 0`; signed ops are the matching RISC-V
M-extension instructions. No API or data-structure change. Minor nit:
commit text says an `is_sdiv` argument; the code uses `is_signed` from
`insn->off`. Harmless.
## Phase 3: Git history
**Step 3.1 — Blame**
Record: Unsigned `rv_divu`/`rv_remu` in `emit_alu_r32` come from
`5f316b65e99f` (“riscv, bpf: Add RV32G eBPF JIT”, 2020-03,
**v5.7-rc1**). At that time BPF had no signed div. The encoding (`off ==
1`) landed in `ec0e2da95f72d` (“bpf: Support new signed div/mod
instructions.”, 2023-07, **v6.6-rc1**), which updated the interpreter
and x86 JIT only. RV64 JIT followed in `3e18ff4bce9b5` (**v6.6-rc1**).
RV32 stayed on unsigned emit until this commit.
**Step 3.2 — Fixes: tag**
Record: None on the landed commit. v1/v2 had a Fixes: tag; v3 removed
it. CI bot later suggested `Fixes: 5f316b65e99f`; Pu Lehui replied that
a Fixes tag was not needed. That objection is about blaming the 2020 JIT
(which was correct then), not about whether today’s unsigned emit is
wrong.
**Step 3.3 — File history / series**
Record: bpf-next v4 1/3 of “signed operations and 32-bit atomics”:
1. this SDIV/SMOD patch (`2e0fa2389c50f`)
2. BPF_MOVSX (`c6a08afdfe3a8`)
3. 32-bit atomics (`a1b37972efc0b`)
This patch does not depend on 2 or 3. Merge: `426a6befd01f9`.
**Step 3.4 — Author**
Record: Kuan-Wei Chiu; not the RV32 JIT original author. Nearby work is
this series only. Reviewer Pu Lehui is the established RISC-V BPF JIT
contributor.
**Step 3.5 — Prerequisites**
Record: Needs `rv_div()` / `rv_rem()` in `arch/riscv/net/bpf_jit.h`
(added by `3e18ff4bce9b5`, present here). Needs `emit_alu_r32` and
32-bit DIV/MOD cases (present since v5.7). Standalone on this tree.
## Phase 4: Mailing list
**Step 4.1 — Original discussion**
Record: Lore from `b4 dig`:
`https://patch.msgid.link/20260714002451.4091139-2-visitorckw@gmail.com`
Revisions: v3 (2026-07-06) and v4 (2026-07-14). v3 changelog: pass
`insn` into `emit_alu_r32`; **remove Fixes: tag and update title**.
Applied version is v4 (latest). No NAK on this patch. No Cc: stable in
the thread.
**Step 4.2 — Recipients**
Record: bpf@vger, linux-riscv, ast, daniel, andrii, eddyz87, memxor,
palmer, aou, pulehui, martin.lau, yonghong.song, alex@ghiti.fr. Right
lists and maintainers. Reviewed-by Pu Lehui; applied by Kumar Kartikeya
Dwivedi.
**Step 4.3 — Bug report**
Record: No syzbot/bugzilla. Evidence is in-tree `test_bpf` (#165, #166,
#169, #170) plus Pu Lehui Tested-by on the cover. Cover also notes
`test_bpf.ko` going to 0 failures on the author’s setup.
**Step 4.4 — Series**
Record: 1/3 is this fix. 2/3 (MOVSX) and 3/3 (atomics) are separate ISA-
coverage patches. 3/3 is closer to a feature (more JIT’d atomics;
interpreter already worked). This patch is self-contained.
**Step 4.5 — stable@**
Record: UNVERIFIED. lore.kernel.org returned 403 to HTTP fetch; the
saved mboxes have no stable@ nomination.
## Phase 5: Semantic analysis
**Step 5.1 — Functions**
Record: `emit_alu_r32`, `bpf_jit_emit_insn`.
**Step 5.2 — Callers**
Record: `emit_alu_r32` is only called from `bpf_jit_emit_insn` (ALU
32-bit X/K DIV/MOD/MUL/shifts, and NEG). `bpf_jit_emit_insn` is called
from `arch/riscv/net/bpf_jit_core.c` during JIT of a loaded BPF program.
**Step 5.3 — Callees**
Record: `bpf_get_reg32` / `bpf_put_reg32`,
`rv_div`/`rv_divu`/`rv_rem`/`rv_remu`. No new locks or allocations.
**Step 5.4 — Reachability**
Record: Yes, from BPF program load on RV32 with `CONFIG_BPF_JIT`
(`HAVE_EBPF_JIT if MMU`). Userspace that can load BPF (privileged; or
unprivileged if enabled) can hit it. `lib/test_bpf.c` exercises it
directly. With `BPF_JIT_ALWAYS_ON`, interpreter fallback is gone and a
wrong JIT is the only path.
**Step 5.5 — Similar patterns**
Record: RV64 already branched on signed vs unsigned in
`bpf_jit_comp64.c`. Interpreter in `kernel/bpf/fixups.c` uses `insn->off
== 1` the same way. ARM32 added 32-bit signed div in `5097faa559a60`
(v6.7-rc1). RV32 64-bit SDIV is still not JIT’d (`notsupported`) —
different, safe fallback.
## Phase 6: Local tree (this checkout)
**Step 6.1 — Does the buggy code exist here?**
Record: Local tree is **7.3.0-rc4** (`v7.3-rc4-27-gf0100363d8c37`). RV32
JIT, signed-div ISA, and `rv_div`/`rv_rem` are all present. The
unsigned-only emit existed in this lineage from v6.6 until
`2e0fa2389c50f` (contained in **v7.3-rc1**). Current `emit_alu_r32`
already has `is_signed = insn->off == 1`. The bug class is in this
tree’s history; the file this patch touches is here.
**Step 6.2 — Backport difficulty**
Record: Clean apply on this code. Pre-image matches the parent of
`2e0fa2389c50f`. Helpers already exist.
**Step 6.3 — Related fixes already here**
Record: This commit is already an ancestor of HEAD (landed in 7.3-rc1).
That is origin-tree presence, not a reason to treat it as “already
selected for stable.” No alternate RV32 SDIV fix. Later series patches
(MOVSX, atomics) are independent.
## Phase 7: Subsystem context
**Step 7.1**
Record: `arch/riscv/net` BPF JIT. Criticality: **PERIPHERAL** for
hardware (RV32 Linux with MMU), **IMPORTANT** for correctness of JIT’d
BPF on that platform. Makefile: `bpf_jit_comp32.o` only when not
`CONFIG_ARCH_RV64I`.
**Step 7.2**
Record: File is mature (since v5.7) with occasional ISA catch-up. Not a
staging driver.
## Phase 8: Impact and risk
**Step 8.1 — Who**
Record: RV32 + BPF JIT users (embedded RISC-V with MMU). Not RV64. Not
no-MMU (no eBPF JIT).
**Step 8.2 — Trigger**
Record: Loading/running a BPF program that uses 32-bit signed DIV or MOD
(`off == 1`). Common in `test_bpf`; less common in production filters,
but a valid ISA op since v6.6. Typically requires BPF-load privilege.
**Step 8.3 — Failure mode**
Record: Silent wrong ALU result while still reporting `jited:1`. Not a
panic. Wrong packet/cgroup/seccomp decisions are possible if a program
uses signed div. Severity: **HIGH** for correctness, not CRITICAL
crash/corruption of kernel memory.
**Step 8.4 — Risk/benefit**
Record: Benefit: correct 32-bit signed div/mod on RV32 JIT; `test_bpf`
failures gone. Risk: very low (~10 lines, ALU emit only, unsigned path
unchanged). Ratio: favorable.
## Phase 9: Synthesis
**Evidence FOR**
- JIT emits unsigned ops for a signed encoding; programs get wrong
answers and still count as JIT’d.
- Reproduced by `test_bpf`; reviewed and tested by Pu Lehui.
- Small, obviously correct, no new UAPI.
- Independent of the rest of the series.
- All helpers and call sites exist in this tree.
- Same class of ISA handling RV64 and the interpreter already do.
**Evidence AGAINST**
- Subject/cover are “Add support”; sent to bpf-next, not bpf.
- Maintainer said a Fixes tag was not needed (“not a bugfix”) — aimed at
the 2020 JIT commit, which predates signed div.
- RV32 is a small user base; 64-bit SDIV still not JIT’d (safe
fallback).
- Not a crash, deadlock, or kernel memory-safety bug.
**Unresolved**
- UNVERIFIED: whether stable@ ever discussed this (lore HTTP 403).
- UNVERIFIED: exact v1/v2 subject/Fixes SHA (v3 changelog confirms a
Fixes tag was removed).
**Stable rules**
1. Obviously correct and tested? **PASS** — review + `test_bpf`
before/after + Tested-by.
2. Real bug affecting users? **PASS** — wrong JIT output for a valid
insn, not a new opcode.
3. Important? **PASS** — silent miscompilation of ALU; high correctness
impact, not a panic.
4. Small and contained? **PASS** — one file, ~10 lines.
5. No new features/APIs? **PASS** — selects existing RISC-V `div`/`rem`
when `off==1`; BPF ISA already has this encoding.
6. Applies to this tree? **PASS** — file, helpers, and DIV/MOD path are
here.
**Exception category:** none (not an ID/quirk/DT/build/doc patch).
The “add support” wording is leftover from a feature series. Behavior is
a JIT bug: the compiler accepts SDIV/SMOD and emits the wrong RISC-V
instruction. That is appropriate for this tree.
Verification:
- [Phase 1] Parsed tags: Reviewed-by Pu Lehui; Link to bpf lore; no
Fixes/Cc: stable/Reported-by
- [Phase 1] Body documents `test_bpf` #165/#166/#169/#170 wrong results
with `jited:1`
- [Phase 2] Diff: `emit_alu_r32` takes `insn`; `is_signed = insn->off ==
1`; `rv_div`/`rv_rem` vs `divu`/`remu`; two call-site updates
- [Phase 2] Confirmed 64-bit DIV/MOD still `goto notsupported` (no
incomplete 64-bit signed path)
- [Phase 3] `git blame` on parent: unsigned emit from `5f316b65e99f`
(v5.7-rc1)
- [Phase 3] `ec0e2da95f72d` added signed div ISA in v6.6-rc1; RV64 JIT
`3e18ff4bce9b5` same cycle
- [Phase 3] `git describe --contains 2e0fa2389c50f` → `v7.3-rc1~...`;
`git merge-base --is-ancestor` confirms it is in HEAD
- [Phase 3] Series 2/3 and 3/3 are independent; no prerequisite besides
`rv_div`/`rv_rem` (present)
- [Phase 4] `b4 dig -c 2e0fa2389c50f`: patch-id match; v3 and v4;
applied v4 1/3
- [Phase 4] `b4 dig -w`: bpf + linux-riscv + BPF/RISC-V maintainers
- [Phase 4] v3 mbox: CI suggested Fixes: 5f316b65e99f; Pu Lehui: “not
need to add fixes tag, as this not a bugfix”; Pu Reviewed-by on the
code
- [Phase 4] Cover: “Remove the Fixes: tag and update title”; Tested-by
Pu Lehui
- [Phase 4] WebFetch lore: 403 Forbidden — discussion taken from b4
mboxes instead
- [Phase 5] Callers: only `bpf_jit_emit_insn`; JIT compile path from
`bpf_jit_core.c`
- [Phase 5] `lib/test_bpf.c` has ALU_SDIV_* / ALU_SMOD_* cases matching
the commit
- [Phase 6] `make kernelversion` / `git describe HEAD`: 7.3.0-rc4 /
v7.3-rc4-27-gf0100363d8c37
- [Phase 6] `arch/riscv/net/Makefile`: comp32 used when not RV64I;
`HAVE_EBPF_JIT if MMU`
- [Phase 6] Current file already has the signed emit (commit ancestor of
HEAD)
- [Phase 8] Failure mode: wrong 32-bit signed div/mod in JIT’d BPF;
severity HIGH correctness
- UNVERIFIED: stable@ mailing list history (lore 403)
The patch is a small, tested JIT correctness fix for a real miscompile
on RV32. It meets stable rules for this tree.
**YES**
arch/riscv/net/bpf_jit_comp32.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
index 592dd86fbf811..89153946a4e46 100644
--- a/arch/riscv/net/bpf_jit_comp32.c
+++ b/arch/riscv/net/bpf_jit_comp32.c
@@ -509,12 +509,15 @@ static void emit_alu_r64(const s8 *dst, const s8 *src,
}
static void emit_alu_r32(const s8 *dst, const s8 *src,
- struct rv_jit_context *ctx, const u8 op)
+ struct rv_jit_context *ctx,
+ const struct bpf_insn *insn)
{
const s8 *tmp1 = bpf2rv32[TMP_REG_1];
const s8 *tmp2 = bpf2rv32[TMP_REG_2];
const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
+ u8 op = BPF_OP(insn->code);
+ bool is_signed = insn->off == 1;
switch (op) {
case BPF_MOV:
@@ -539,10 +542,12 @@ static void emit_alu_r32(const s8 *dst, const s8 *src,
emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx);
break;
case BPF_DIV:
- emit(rv_divu(lo(rd), lo(rd), lo(rs)), ctx);
+ emit(is_signed ? rv_div(lo(rd), lo(rd), lo(rs)) :
+ rv_divu(lo(rd), lo(rd), lo(rs)), ctx);
break;
case BPF_MOD:
- emit(rv_remu(lo(rd), lo(rd), lo(rs)), ctx);
+ emit(is_signed ? rv_rem(lo(rd), lo(rd), lo(rs)) :
+ rv_remu(lo(rd), lo(rd), lo(rs)), ctx);
break;
case BPF_LSH:
emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx);
@@ -1041,7 +1046,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
emit_imm32(tmp2, imm, ctx);
src = tmp2;
}
- emit_alu_r32(dst, src, ctx, BPF_OP(code));
+ emit_alu_r32(dst, src, ctx, insn);
break;
case BPF_ALU | BPF_MOV | BPF_K:
@@ -1065,7 +1070,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
* src is ignored---choose tmp2 as a dummy register since it
* is not on the stack.
*/
- emit_alu_r32(dst, tmp2, ctx, BPF_OP(code));
+ emit_alu_r32(dst, tmp2, ctx, insn);
break;
case BPF_ALU | BPF_END | BPF_FROM_LE:
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 6.18] RISC-V: errata: Add SiFive MAL-9092 workaround
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_SDIV and BPF_SMOD in RV32 JIT Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-6.6] riscv: kprobes: Prevent probes in breakpoint handlers Sasha Levin
` (3 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable
Cc: Yong-Xuan Wang, Samuel Holland, Paul Walmsley, Sasha Levin,
palmer, aou, linux-riscv, linux-kernel
From: Yong-Xuan Wang <yongxuan.wang@sifive.com>
[ Upstream commit 148ab873d8194cb44f29474da3b4428fa2e100d1 ]
SiFive cores with MAL-9092 require fence.rw instructions around
HLV/HLVX/HSV hypervisor instructions to ensure proper memory ordering
when accessing guest memory.
Note that HSTATUS.HU is cleared during KVM initialization, restricting
hypervisor instructions to HS-mode only. If future changes enable
HSTATUS.HU for U-mode access, additional errata considerations will be
needed.
Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
Link: https://patch.msgid.link/20260817-sifive-errata-v1-1-6a80f1a2743d@sifive.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.18.y** (`v6.18.57`). This SiFive MAL-9092 change
is a hardware-errata workaround for KVM guest-memory accesses, and the
code it patches is already in this series.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: [subsystem: RISC-V errata/SiFive] [action verb: Add] [workaround
for SiFive MAL-9092: `fence.rw` around HLV/HLVX/HSV]
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- No `Fixes:` tag (expected for this review queue)
- No `Reported-by:` / `Tested-by:` / `Acked-by:`
- `Reviewed-by: Samuel Holland <samuel.holland@sifive.com>` (SiFive,
same vendor)
- `Link: https://patch.msgid.link/20260817-sifive-
errata-v1-1-6a80f1a2743d@sifive.com`
- `Signed-off-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>` (author,
SiFive)
- `Signed-off-by: Paul Walmsley <pjw@kernel.org>` (RISC-V arch
maintainer)
- No `Cc: stable@vger.kernel.org` (expected; not a negative signal)
- Sasha Levin SOB ignored per instructions
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- [Bug] SiFive cores with MAL-9092 do not provide the required memory
ordering around hypervisor load/store (`HLV`/`HLVX`/`HSV`) when
touching guest memory.
- [Symptom] Wrong/stale guest instruction or data observed by the host
hypervisor (KVM unprivileged guest-memory access). Not a documented
oops; it is an architecture-level ordering hole.
- [Version] None stated. Paul queued it for v7.3-rc. Affected `mimpid`
values look like 2025-10-31, 2025-12-17, and 2026-03-20 silicon.
- [Root cause] Missing `fence.rw` around those hypervisor instructions
on specific `marchid`/`mimpid` combinations. `HSTATUS.HU` is left
clear in KVM setup, so the workaround is HS-mode only.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. It is an explicit hardware-errata
workaround, which is a stable exception category (quirks/workarounds).
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- `arch/riscv/Kconfig.errata`: +14 (`CONFIG_ERRATA_SIFIVE_MAL_9092`,
`depends on ERRATA_SIFIVE && 64BIT`, `default y`)
- `arch/riscv/errata/sifive/errata.c`: +20 (`errata_mal_9092_check_func`
+ list entry)
- `arch/riscv/include/asm/errata_list_vendors.h`: +2/-1
(`ERRATA_SIFIVE_MAL_9092 2`, `ERRATA_SIFIVE_NUMBER 3`)
- `arch/riscv/include/asm/insn-def.h`: +13/-3 (ALTERNATIVE nop→`fence
rw,rw` around `HLVX_HU`/`HLV_W`/`HLV_D`)
- Total: **4 files, +49/-4**. Functions: `errata_mal_9092_check_func`
(new), `errata_list[]` (extended), HLV macros. Scope: single-arch
surgical errata, not a refactor.
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- Probe: previously only CIP-453/CIP-1200. After,
`marchid==0x8000000000000109` and `mimpid` in
`{0x19251031,0x19251217,0x19260320}` also set bit
`ERRATA_SIFIVE_MAL_9092`.
- HLV macros: previously a single hypervisor load. After, `nop` (or
patched `fence rw,rw`) both before and after the instruction via the
existing `ALTERNATIVE` framework.
- Normal KVM path (`kvm_riscv_vcpu_unpriv_read`), not an error path.
Unaffected CPUs keep `nop`.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: [category: hardware workaround / memory-ordering errata]
[mechanism: SiFive MAL-9092 omits ordering around HS-mode guest-memory
hypervisor ops; alternatives patch in `fence.rw` only on matching CPUs]
No HSV macros exist in this tree; wrapping HLV/HLVX is the complete in-
tree coverage.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Matches CIP-453/CIP-1200 style. CPU-ID gated, `default y`,
reviewed by SiFive and queued by the arch maintainer. Regression risk is
low: extra nops on other CPUs; fences only on listed IDs. Residual
risks: `insn-def.h` relies on include order for
`ALTERNATIVE`/`SIFIVE_VENDOR_ID`/`ERRATA_SIFIVE_MAL_9092`;
`warn_miss_errata()` can warn at boot if KVM is not built-in because the
only alternative sites are in KVM.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record: HLV macros come from `26b73f14933e9c` (2022-10-02, “riscv: KVM:
Apply insn-def to hlv encodings”). SiFive errata probe/list from
`800149a77c2cb8` / `bff3ff525460b4` (2021, CIP-453/CIP-1200). The
hypervisor accessors have been in tree for years; the errata is new
silicon, not new kernel code.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. The defect is in the CPU, not in a prior kernel
commit. Not applicable.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Recent `arch/riscv` errata work is MIPS P8700, T-Head
GHOSTWRITE, vendor-header split (`16d18e3eaf29b`). None of those is a
prerequisite for this patch. Standalone v1, not patch X/Y.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Yong-Xuan Wang is a SiFive contributor with RISC-V KVM work in
this history (APLIC, Svade/Svadu). Samuel Holland (SiFive) reviewed. Not
the arch maintainer; Paul Walmsley queued it.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Needs RISC-V alternatives, `ERRATA_SIFIVE`,
`errata_list_vendors.h`, and the HLV macros. All are ancestors of
`v6.18.57` (`git merge-base --is-ancestor` succeeded for `16d18e3eaf29b`
and `26b73f14933e9c`). Applies standalone.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c f36eeaaaecc2c` → https://patch.msgid.link/20260817-sifive-
errata-v1-1-6a80f1a2743d@sifive.com
- `b4 dig -a`: **v1 only** (2026-08-17). No v2/v3.
- Thread: patch + Paul Walmsley “Thanks, queued for v7.3-rc.” No NAKs,
no stable nomination, no reviewer risk flags.
- lore.kernel.org WebFetch returned 403; thread recovered via `b4 dig
-m` mbox.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: `b4 dig -w` To/Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Samuel Holland, other SiFive engineers, linux-riscv,
linux-kernel. Appropriate RISC-V maintainers were on the patch.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla/user crash thread. This is a vendor errata
from SiFive, not a fuzzer report. Public MAL-9092 documentation beyond
the patch was not found.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Single standalone patch (`[PATCH]`, not `[PATCH 1/N]`). No
follow-ups on these files after this commit on HEAD.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: Web search of stable/MAL-9092 found no stable-list discussion
and no stated reason to keep it out of stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `errata_mal_9092_check_func` (new); `errata_list[]`; macros
`ALT_SIFIVE_MAL_9092_FENCE`, `HLVX_HU`, `HLV_W`, `HLV_D`. Existing
`sifive_errata_probe` / `sifive_errata_patch_func` pick it up via
`ERRATA_SIFIVE_NUMBER`.
**Step 5.2: TRACE CALLERS**
Record:
- `HLV*` used only in `arch/riscv/kvm/vcpu_exit.c` →
`kvm_riscv_vcpu_unpriv_read()`
- Callers of that: `kvm_riscv_vcpu_virtual_insn()` in `vcpu_insn.c`
(guest insn fetch when `stval` is 0 / 16-bit); `vcpu_sbi_v01.c` (SBI
0.1 SEND_IPI / remote fence hart-mask reads)
- Context: KVM VM-exit handling, not IRQ-entry core. Reachable whenever
a guest traps.
**Step 5.3: TRACE CALLEES**
Record: Probe only compares `archid`/`impid`. Patching uses
`patch_text_nosync` under `text_mutex`, same as CIP errata. Macros
expand to `ALTERNATIVE("nop", "fence rw, rw", ...)`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace QEMU/KVM on RISC-V → guest trap →
`kvm_riscv_vcpu_unpriv_read` → HLV/HLVX. Unprivileged guest code can
induce those exits. Only relevant with `CONFIG_KVM` on matching SiFive
cores.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same pattern as CIP-453 and CIP-1200 in this tree. No HSV macros
in `arch/riscv` at `v6.18.57` or HEAD, so nothing else to wrap here.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. Local tree: `git describe HEAD` =
`v6.18.57-155-gcdf239ca885b2`, `make kernelversion` = **6.18.57**. `git
merge-base --is-ancestor f36eeaaaecc2c v6.18.57` failed (workaround not
in 6.18.57). `v6.18.57` already has HLV macros in `insn-def.h`, KVM
`vcpu_exit.c`, and SiFive errata with `ERRATA_SIFIVE_NUMBER 2`. The
hardware bug is therefore live for matching CPUs running this series.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: `git diff --stat v6.18.57 f36eeaaaecc2c -- <the four files>` is
exactly +49/-4. Clean apply. No conflicting refactor in 6.18.57 vs this
patch.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: `git log --grep=MAL-9092` only finds this candidate. No earlier
equivalent workaround.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: [arch/riscv errata + KVM guest-memory access] [IMPORTANT, not
CORE: RISC-V-specific, and only listed SiFive cores with KVM]. Wrong
guest-memory ordering is still a real virt correctness issue for those
systems.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: RISC-V errata and KVM are actively maintained. This is new-
silicon errata on a mature HLV/KVM path, not a rewrite of a brand-new
subsystem.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: RISC-V + `CONFIG_ERRATA_SIFIVE` (selected by `ARCH_SIFIVE`) +
`CONFIG_64BIT` + KVM + `marchid 0x8000000000000109` with one of three
`mimpid`s. Driver/platform-specific, not universal.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Trigger is KVM using HLV/HLVX to read guest memory (instruction
emulate, SBI 0.1 hart masks). Common for any VM on those cores. Guest
(typically unprivileged) can cause the VM-exit. Not a rare error-path-
only bug.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: [Failure mode: missing memory fence → stale/wrong guest insn or
data in the hypervisor] [Severity: HIGH — guest corruption or incorrect
emulation; not a documented host panic]. Silent wrongness is worse than
a WARN.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: HIGH for KVM on the listed SiFive cores (correct guest-memory
access).
- Risk: LOW — ~50 lines, ID-gated alternatives, same mechanism as
CIP-1200 already in 6.18.57. Unaffected CPUs only gain nops.
- Ratio: benefit outweighs risk for this 6.18.y tree.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Hardware errata/quirk, which stable explicitly accepts
- Real KVM guest-memory ordering bug on shipping/soon-shipping SiFive
cores
- Small (+49/-4), uses existing alternatives/errata machinery
- HLV/KVM/SiFive errata all present in 6.18.57; applies cleanly
- Reviewed by SiFive, queued by RISC-V arch maintainer, no NAKs
- CPU-ID match so other RISC-V systems are not functionally changed
AGAINST:
- New Kconfig symbol (standard for RISC-V errata, `default y`)
- No field crash/syzbot report (vendor errata, typical)
- Possible `warn_miss_errata` noise if KVM is disabled on an affected
CPU
- HSV mentioned in text but no HSV macros here (not a functional gap in
6.18.y)
UNRESOLVED:
- Public MAL-9092 datasheet text was not found (only the kernel patch)
- lore.kernel.org HTTP 403; discussion recovered from b4 mbox instead
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — ID-gated alternative fences;
SiFive review; maintainer queued for 7.3-rc
2. Fixes a real bug that affects users? **PASS** — KVM guest-memory
ordering on listed cores
3. Important issue? **PASS** — HIGH: incorrect hypervisor guest
instruction/data reads (corruption / bad emulation)
4. Small and contained? **PASS** — 4 files, +49/-4
5. No new features or APIs? **PASS** — no userspace ABI; Kconfig is the
usual errata toggle
6. Can apply to the local tree? **PASS** — clean vs `v6.18.57`
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Hardware quirk/workaround (SiFive CPU errata), same class as
USB/PCI quirks and existing CIP-453/CIP-1200.
**Step 9.4: DECISION**
This belongs on **this** 6.18.y tree. The HLV path has been here since
2022; 6.18.57 just lacks the fence workaround. LTS users who run KVM on
these SiFive cores get a contained, ID-gated fix with the same shape as
errata already in the series.
Verification:
- [Phase 1] Parsed tags: Reviewed-by Samuel Holland; Link to msgid
20260817-sifive-errata-v1-1; SOB Yong-Xuan Wang and Paul Walmsley; no
Fixes/Reported-by/Cc:stable
- [Phase 2] Diff: +49/-4 across Kconfig.errata, errata.c,
errata_list_vendors.h, insn-def.h; ALTERNATIVE nop→fence around
HLVX_HU/HLV_W/HLV_D
- [Phase 3] git blame v6.18.57 insn-def.h: HLV macros from
26b73f14933e9c (2022); errata framework from 2021 CIP commits
- [Phase 3] No Fixes: tag; standalone, not a series
- [Phase 3] git merge-base --is-ancestor 26b73f14933e9c v6.18.57 → yes;
16d18e3eaf29b v6.18.57 → yes
- [Phase 4] b4 dig -c f36eeaaaecc2c: lore URL found; -a: v1 only; -w:
RISC-V maintainers on To/Cc; mbox: Paul “queued for v7.3-rc”; no NAK
- [Phase 4] lore WebFetch 403; mbox used instead
- [Phase 5] HLV* only used in kvm/vcpu_exit.c; callers vcpu_insn.c and
vcpu_sbi_v01.c; git grep HSV_ in arch/riscv: none
- [Phase 6] git describe HEAD: v6.18.57-155-gcdf239ca885b2;
kernelversion 6.18.57
- [Phase 6] git merge-base --is-ancestor f36eeaaaecc2c v6.18.57 → not in
6.18.57; git grep MAL-9092 v6.18.57 → none
- [Phase 6] git diff --stat v6.18.57 f36eeaaaecc2c -- the four files →
exact patch, clean apply
- [Phase 7] ARCH_SIFIVE selects ERRATA_SIFIVE; KVM is
arch/riscv/kvm/Kconfig
- [Phase 8] Failure mode: missing fence → wrong guest memory in KVM,
severity HIGH
- UNVERIFIED: full public MAL-9092 silicon manual; compile of
vcpu_exit.c was inferred from include order, not by building
The workaround is small, ID-gated, and fixes a real KVM memory-ordering
erratum on hardware that 6.18.y can boot. It meets the stable rules and
the hardware-quirk exception.
**YES**
arch/riscv/Kconfig.errata | 14 ++++++++++++++
arch/riscv/errata/sifive/errata.c | 20 ++++++++++++++++++++
arch/riscv/include/asm/errata_list_vendors.h | 3 ++-
arch/riscv/include/asm/insn-def.h | 16 +++++++++++++---
4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 6f230aebd4968..65d00fb9db9d7 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -95,6 +95,20 @@ config ERRATA_STARFIVE_JH7100
Say "Y" if you want to support the BeagleV Starlight and/or
StarFive VisionFive V1 boards.
+config ERRATA_SIFIVE_MAL_9092
+ bool "Apply SiFive HLV/HLVX/HSV fence errata"
+ depends on ERRATA_SIFIVE && 64BIT
+ default y
+ help
+ This will apply the SiFive MAL-9092 errata to add fence.rw
+ instructions around all HLV/HLVX/HSV instructions.
+
+ Note: HSTATUS.HU is cleared during KVM initialization. If future
+ changes enable HSTATUS.HU to allow hypervisor instructions in
+ U-mode, additional errata handling may be required.
+
+ If you don't know what to do here, say "Y".
+
config ERRATA_THEAD
bool "T-HEAD errata"
depends on RISCV_ALTERNATIVE
diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c
index 38aac2c47845a..3025b9d6966f8 100644
--- a/arch/riscv/errata/sifive/errata.c
+++ b/arch/riscv/errata/sifive/errata.c
@@ -51,6 +51,22 @@ static bool errata_cip_1200_check_func(unsigned long arch_id, unsigned long imp
return true;
}
+static bool errata_mal_9092_check_func(unsigned long arch_id, unsigned long impid)
+{
+ /*
+ * Affected cores:
+ * Architecture ID: 0x8000000000000109
+ * Implementation ID: 0x19251031, 0x19251217, 0x19260320
+ */
+
+ if (arch_id != 0x8000000000000109)
+ return false;
+ if (impid != 0x19251031 && impid != 0x19251217 && impid != 0x19260320)
+ return false;
+
+ return true;
+}
+
static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
{
.name = "cip-453",
@@ -60,6 +76,10 @@ static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
.name = "cip-1200",
.check_func = errata_cip_1200_check_func
},
+ {
+ .name = "mal-9092",
+ .check_func = errata_mal_9092_check_func
+ },
};
static u32 __init_or_module sifive_errata_probe(unsigned long archid,
diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h
index ec7eba3734371..c62a82f60468a 100644
--- a/arch/riscv/include/asm/errata_list_vendors.h
+++ b/arch/riscv/include/asm/errata_list_vendors.h
@@ -11,7 +11,8 @@
#ifdef CONFIG_ERRATA_SIFIVE
#define ERRATA_SIFIVE_CIP_453 0
#define ERRATA_SIFIVE_CIP_1200 1
-#define ERRATA_SIFIVE_NUMBER 2
+#define ERRATA_SIFIVE_MAL_9092 2
+#define ERRATA_SIFIVE_NUMBER 3
#endif
#ifdef CONFIG_ERRATA_THEAD
diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h
index d29da6ccd3dd8..b1b97eab91007 100644
--- a/arch/riscv/include/asm/insn-def.h
+++ b/arch/riscv/include/asm/insn-def.h
@@ -191,18 +191,28 @@
INSN_R(OPCODE_SYSTEM, FUNC3(0), FUNC7(49), \
__RD(0), RS1(gaddr), RS2(vmid))
+#define ALT_SIFIVE_MAL_9092_FENCE \
+ALTERNATIVE("nop", "fence rw, rw", SIFIVE_VENDOR_ID, \
+ ERRATA_SIFIVE_MAL_9092, CONFIG_ERRATA_SIFIVE_MAL_9092)
+
#define HLVX_HU(dest, addr) \
+ ALT_SIFIVE_MAL_9092_FENCE "\n" \
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(50), \
- RD(dest), RS1(addr), __RS2(3))
+ RD(dest), RS1(addr), __RS2(3)) "\n" \
+ ALT_SIFIVE_MAL_9092_FENCE
#define HLV_W(dest, addr) \
+ ALT_SIFIVE_MAL_9092_FENCE "\n" \
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(52), \
- RD(dest), RS1(addr), __RS2(0))
+ RD(dest), RS1(addr), __RS2(0)) "\n" \
+ ALT_SIFIVE_MAL_9092_FENCE
#ifdef CONFIG_64BIT
#define HLV_D(dest, addr) \
+ ALT_SIFIVE_MAL_9092_FENCE "\n" \
INSN_R(OPCODE_SYSTEM, FUNC3(4), FUNC7(54), \
- RD(dest), RS1(addr), __RS2(0))
+ RD(dest), RS1(addr), __RS2(0)) "\n" \
+ ALT_SIFIVE_MAL_9092_FENCE
#else
#define HLV_D(dest, addr) \
__ASM_STR(.error "hlv.d requires 64-bit support")
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 6.18-6.6] riscv: kprobes: Prevent probes in breakpoint handlers
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_SDIV and BPF_SMOD in RV32 JIT Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18] RISC-V: errata: Add SiFive MAL-9092 workaround Sasha Levin
@ 2026-10-19 13:49 ` Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-6.1] gpio: sifive: add missing MODULE_DEVICE_TABLE() Sasha Levin
` (2 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:49 UTC (permalink / raw)
To: patches, stable
Cc: Rui Qi, Nam Cao, Paul Walmsley, Sasha Levin, palmer, aou,
linux-riscv, linux-kernel
From: Rui Qi <qirui.001@bytedance.com>
[ Upstream commit e7d8ea6c6d1bc685a8943ffad2d3679be92d164f ]
The ftrace selftest multiple_kprobes.tc registers kprobe events on
the first 256 text symbols from /proc/kallsyms. If handle_break() is
selected as a probe target on RISC-V, the breakpoint exception path
can trap again before it reaches the kprobe breakpoint handler. That
recursively enters do_trap_break() and can make the system
unresponsive.
Mark handle_break() and its local probe dispatch helpers as nokprobe
symbols so they are added to the kprobe blacklist, matching other
low-level breakpoint exception paths.
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
Reviewed-by: Nam Cao <namcao@linutronix.de>
Link: https://patch.msgid.link/20260806043807.2583001-1-qirui.001@bytedance.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This is a 3-line RISC-V kprobe blacklist restore that prevents recursive
breakpoint traps from hanging the machine. The local tree is
**6.12.111** (`pending-6.12`); the buggy `handle_break()` path is
present and the patch applies cleanly.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: [riscv: kprobes] [Prevent] [Stop kprobes on RISC-V breakpoint
exception handlers so a probe on that path cannot recurse]
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- Signed-off-by: Rui Qi \<qirui.001@bytedance.com\> (author)
- Reviewed-by: Nam Cao \<namcao@linutronix.de\>
- Link: https://patch.msgid.link/20260806043807.2583001-1-
qirui.001@bytedance.com
- Signed-off-by: Paul Walmsley \<pjw@kernel.org\> (RISC-V maintainer)
- No Fixes: tag (expected)
- No Reported-by / Tested-by / Cc: stable
- No syzbot
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- Bug: `multiple_kprobes.tc` plants kprobes on the first 256
`/proc/kallsyms` text symbols. If `handle_break()` is one of them, the
breakpoint exception path hits another ebreak before
`kprobe_breakpoint_handler()` runs.
- Symptom: recursive `do_trap_break()` → system unresponsive (hang).
- Root cause: those C helpers are not on the kprobe blacklist.
- Fix: `NOKPROBE_SYMBOL()` on `handle_break()`,
`probe_breakpoint_handler()`, and `probe_single_step_handler()`.
- Version info: none in the message. The hang is RISC-V + kprobes, not a
new-kernel-only issue.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. The subject says “Prevent” and the body describes a
hang. This is an explicit bug fix.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `arch/riscv/kernel/traps.c` only (+3 / −0)
- Functions: `probe_single_step_handler`, `probe_breakpoint_handler`,
`handle_break`
- Scope: single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- Before: all three are normal `.text` symbols. `handle_break()` is
global, so it is always in kallsyms. A kprobe on it patches ebreak at
the function entry.
- Path: ebreak → `do_trap_break()` (noinstr) → `handle_break()` → ebreak
again → nested `do_trap_break()` → hang/stack blow-up.
`kprobe_breakpoint_handler()` is never reached because the trap
happens at the start of `handle_break()`.
- After: the three symbols go in `_kprobe_blacklist`.
`register_kprobe()` rejects them via `within_kprobe_blacklist()`
(`kernel/kprobes.c`).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: [Logic / kprobe blacklist gap] [Breakpoint exception helpers
were probeable; probing them recurses into the same handler.] Category
is closest to a hang/deadlock-class failure, not UAF.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: `NOKPROBE_SYMBOL()` is the standard way to
blacklist. x86 does the same with `NOKPROBE_SYMBOL(do_int3)`. RISC-V
already uses `__kprobes` on `kprobe_breakpoint_handler()` itself.
- Minimal: three annotation lines, no control-flow change.
- Regression risk: very low. Blacklisting only refuses probes on those
symbols; normal breakpoint/BUG/kgdb handling is unchanged.
- `linux/kprobes.h` is already included in `traps.c`. With
`CONFIG_KPROBES=n`, `NOKPROBE_SYMBOL` is a no-op.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `handle_break()` created by `f0bddf50586da` (“riscv: entry: Convert to
generic entry”, in v6.4-rc1). That commit **removed**
`NOKPROBE_SYMBOL(do_trap_break)` when splitting `do_trap_break()` into
a noinstr wrapper plus a C `handle_break()`.
- Wrappers `probe_*_handler()` added by `9f564b92cf6d0` (“riscv: Only
consider swbp/ss handlers for correct privileged mode”, in v6.6-rc6).
- Both are ancestors of this 6.12 tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: tag. The dropped blacklist is from `f0bddf50586da`.
Earlier, `2349a3b26e29b` (“riscv: add do_page_fault and do_trap_break
into the kprobes blacklist”, 2021) added
`NOKPROBE_SYMBOL(do_trap_break)` with **Cc: stable** and Fixes:
`c22b0bcb1dd02` (“riscv: Add kprobes supported”). This patch restores
that protection after the generic-entry split.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Recent `traps.c` churn (irq enable in exception handling,
misaligned traps) does not retarget these three functions. Not part of a
multi-patch series (standalone v1→v2 style-only). No extra prerequisite
beyond code already in 6.12.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Rui Qi is not the RISC-V maintainer. One other RISC-V commit in
this tree (`8b76013038478`, stacktrace). Reviewer Nam Cao has
substantial RISC-V kprobes work. Maintainer Paul Walmsley queued the
patch.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None. Uses existing `NOKPROBE_SYMBOL`. Standalone. `git apply
--check` of the three-line hunk on this tree succeeded (exit 0).
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c <msgid>` failed: commit is not in this checkout (`Cannot
find a commit matching …`).
- lore.kernel.org fetches returned HTTP 403.
- Recovered from LKML/patchew/openwall:
- v1: 2026-08-04, msgid
`20260804064343.1865283-1-qirui.001@bytedance.com`
- v2: 2026-08-06, msgid
`20260806043807.2583001-1-qirui.001@bytedance.com` (applied version)
- v2 changelog: drop blank line before `NOKPROBE_SYMBOL()`; add Nam Cao
Reviewed-by. No technical redesign.
- Paul Walmsley: “Thanks, queued for v7.3.” No NAK.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: v1 CC included Paul Walmsley, Palmer Dabbelt, Alexandre Ghiti,
Thomas Gleixner, Nam Cao, linux-riscv, linux-kernel. Nam Cao Reviewed-by
on v2. RISC-V maintainer applied it.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No bugzilla/syzbot link. Concrete trigger is in-tree:
`tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc`
(first 256 kallsyms text symbols). Author describes a hang; that matches
the code path.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Single patch, not 2/N. No follow-up required from the v2
discussion.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search returned 403. No evidence this was
rejected for stable. The 2021 predecessor (`2349a3b26e29b`) was
explicitly Cc: stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `probe_single_step_handler`, `probe_breakpoint_handler`,
`handle_break`. Callers of `handle_break()` are only the two branches of
`do_trap_break()`.
**Step 5.2: TRACE CALLERS**
Record:
- Exception vector in `arch/riscv/kernel/entry.S` (`RISCV_PTR
do_trap_break`)
- `do_trap_break()` (noinstr / `__trap_section`) already blacklisted via
`__noinstr_text_*` in `populate_kprobe_blacklist()`
- `do_trap_break()` → `handle_break()` (not noinstr, not blacklisted
today)
- `handle_break()` → probe helpers → `kprobe_*_handler()` (`__kprobes`,
already blacklisted) or SIGTRAP/BUG/kgdb
Context: breakpoint exception, including kernel ebreak from kprobes.
**Step 5.3: TRACE CALLEES**
Record: `user_mode()`, `uprobe_*` / `kprobe_*` handlers,
`force_sig_fault`, `notify_die`, `report_bug`, `handle_cfi_failure`,
`die()`. No allocations or new locks in the patch (annotations only).
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Reachable from userspace tracing when `CONFIG_KPROBES` is on:
write to `kprobe_events` or equivalent (typically CAP_SYS_ADMIN /
CAP_PERFMON). Also reachable from the ftrace kprobe selftest. Not a
default-defconfig path (`CONFIG_KPROBES` is optional, RISC-V defconfig
does not set it), but distro/debug kernels enable it.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same pattern on x86 (`NOKPROBE_SYMBOL(do_int3)`), s390, powerpc,
loongarch kprobe handlers. RISC-V `kprobe_breakpoint_handler` already
uses `__kprobes`. The missing piece is the C trampoline
`handle_break()`, which is what generic-entry introduced.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. `arch/riscv/kernel/traps.c` lines 269–305 define the three
functions with no `NOKPROBE_SYMBOL`. `HAVE_KPROBES` is selected for
RISC-V when `!XIP_KERNEL`. Bug introduced when
`NOKPROBE_SYMBOL(do_trap_break)` was dropped in v6.4 (`f0bddf50586da`);
wrappers present since v6.6. Present throughout 6.12.y.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean apply. Local `do_trap_break()` has extra
`local_irq_enable/disable` from `32b14e757404c`, below the insertion
points, so it does not conflict. `git apply --check` succeeded.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No `NOKPROBE_SYMBOL` in `traps.c` now. `do_trap_break` is still
noinstr-blacklisted, which is not enough because it calls out to
`handle_break()`.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: [arch/riscv kprobes/traps] [IMPORTANT for RISC-V tracing;
PERIPHERAL relative to all architectures]. Not core mm/scheduler, but a
hang in the arch breakpoint path.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: RISC-V traps/kprobes are mature in 6.12 (kprobes since 5.13).
This is a long-standing hole, not a brand-new feature bug.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: RISC-V kernels with `CONFIG_KPROBES` (and not XIP). Tracing
users, ftrace kprobe selftests, distro kernels that enable kprobes. Not
every 6.12 user.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Plant a kprobe on `handle_break` (or the static helpers if they
have kallsyms entries), then any kernel/user breakpoint that enters
`handle_break()`. The selftest can do that if `handle_break` is among
the first 256 text symbols (address-order, so platform-dependent).
Explicit `perf probe` / `kprobe_events` on that symbol is a reliable
trigger. Needs tracing privilege, not an unprivileged local DoS on
typical configs.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: [Recursive breakpoint exception → hang / unresponsive system]
[CRITICAL for those who hit it]. Not data corruption. Not an
unprivileged security bug on typical kprobe policy.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: HIGH for RISC-V kprobe users (prevents hang; restores
blacklist that stable already shipped once).
- Risk: VERY LOW (3 annotation lines, no runtime logic change).
- Ratio: strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real hang: recursive ebreak in the breakpoint path.
- In-tree selftest is a plausible trigger; any probe on `handle_break`
is a hard trigger.
- Restores protection that `2349a3b26e29b` put on `do_trap_break` (Cc:
stable) and that `f0bddf50586da` dropped.
- Matches other architectures’ nokprobe on low-level BP handlers.
- 3 lines, obviously correct, reviewed by Nam Cao, queued by Paul
Walmsley.
- Buggy code is in this 6.12 tree; patch applies cleanly.
AGAINST:
- Not on by default in RISC-V defconfig (`CONFIG_KPROBES` optional).
- Needs privileged tracing to trigger.
- No Fixes:/Cc: stable on this commit (not a negative per the review
rules).
- Arch-specific, so only RISC-V 6.12 users benefit.
UNRESOLVED:
- Exact Nam Cao review email body (lore 403). v2 only changed whitespace
and added Reviewed-by.
- Whether `handle_break` is in the first 256 kallsyms on a typical 6.12
RISC-V vmlinux (unverified; hang if probed is verified from code
regardless).
- `b4 dig` could not run against a SHA not in this checkout.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — standard `NOKPROBE_SYMBOL`;
maintainer queued; reviewer Ack.
2. Fixes a real bug that affects users? **PASS** — hang when kprobes
lands on `handle_break`.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
system hang / unresponsive.
4. Small and contained? **PASS** — +3 lines, one file.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — `git apply --check` clean on
6.12.111.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/build/docs exception. It is a normal
hang fix.
**Step 9.4: MAKE YOUR DECISION**
This belongs on 6.12.y. It restores a kprobe blacklist that this tree
lost in the generic-entry split, with essentially no behavioral change
except refusing probes that can wedge the machine.
Detailed explanation:
The problem is that RISC-V kprobes implement software breakpoints with
ebreak. `do_trap_break()` is noinstr (already blacklisted), but it
immediately calls `handle_break()`, which is ordinary C text. If a
kprobe is installed on `handle_break()`, the first instruction is
ebreak, so the exception path traps again before
`kprobe_breakpoint_handler()` can run. That recurses until the system
stops responding. Marking the three symbols `NOKPROBE_SYMBOL` puts them
on the same blacklist `register_kprobe()` already consults. Stable users
who enable kprobes (tracing, selftests, distro debug kernels) are the
ones who hit this; the cost of the backport is three annotations.
Verification:
- [Phase 1] Parsed tags: Reviewed-by Nam Cao; Link msgid
20260806043807.2583001-1; Paul Walmsley SOB; no Fixes/syzbot
- [Phase 2] Diff: +3 `NOKPROBE_SYMBOL` lines in
`arch/riscv/kernel/traps.c`; no control-flow change
- [Phase 2] Confirmed `traps.c` already `#include <linux/kprobes.h>`
- [Phase 2] Confirmed `register_kprobe()` rejects
`within_kprobe_blacklist()` addresses (`kernel/kprobes.c` ~1593)
- [Phase 2] Confirmed `NOKPROBE_SYMBOL` writes `_kprobe_blacklist`
(`include/asm-generic/kprobes.h`)
- [Phase 3] `git describe HEAD` / `make kernelversion`:
p-6.12-3-gc504cf0baa3d8, 6.12.111
- [Phase 3] blame: `handle_break` from `f0bddf50586da` (v6.4-rc1);
wrappers from `9f564b92cf6d0` (v6.6-rc6)
- [Phase 3] `git show f0bddf50586da`: removed
`NOKPROBE_SYMBOL(do_trap_break)` while splitting the function
- [Phase 3] `2349a3b26e29b` originally blacklisted `do_trap_break` with
Cc: stable
- [Phase 3] `git merge-base --is-ancestor` both introducing commits are
in HEAD
- [Phase 4] b4 dig: no matching commit in this tree (UNVERIFIED via b4)
- [Phase 4] v1/v2 recovered from lkml.iu.edu / openwall / patchew; v2 is
style-only + Reviewed-by
- [Phase 4] Paul Walmsley: queued for v7.3 (patchew)
- [Phase 4] lore.kernel.org and stable@ search: HTTP 403 (UNVERIFIED via
lore)
- [Phase 4] Nam Cao review body: UNVERIFIED (openwall msg id collision);
Reviewed-by on v2 is verified
- [Phase 5] Callers: `entry.S` → `do_trap_break` → `handle_break`;
`do_trap_break` is `__trap_section`/`noinstr`
- [Phase 5] `kprobe_breakpoint_handler` already `__kprobes` in
`arch/riscv/kernel/probes/kprobes.c`
- [Phase 5] Selftest `multiple_kprobes.tc` confirmed to take first 256
kallsyms text symbols
- [Phase 5] x86 comparison: `NOKPROBE_SYMBOL(do_int3)` in
`arch/x86/kernel/traps.c:826`
- [Phase 6] Current `traps.c` has no `NOKPROBE_SYMBOL`; buggy helpers
present at lines 269–305
- [Phase 6] `git apply --check` of the three-line hunk: exit 0
- [Phase 7] `arch/riscv/Kconfig`: `select HAVE_KPROBES if !XIP_KERNEL`
- [Phase 8] RISC-V defconfig does not set `CONFIG_KPROBES` (trigger is
config-specific)
- UNVERIFIED: whether `handle_break` is in the first 256 kallsyms on a
typical 6.12 RISC-V build (does not change the hang if that symbol is
probed)
**YES**
arch/riscv/kernel/traps.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 47afea4ff1a8d..e7e45cbb08999 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -272,6 +272,7 @@ static bool probe_single_step_handler(struct pt_regs *regs)
return user ? uprobe_single_step_handler(regs) : kprobe_single_step_handler(regs);
}
+NOKPROBE_SYMBOL(probe_single_step_handler);
static bool probe_breakpoint_handler(struct pt_regs *regs)
{
@@ -279,6 +280,7 @@ static bool probe_breakpoint_handler(struct pt_regs *regs)
return user ? uprobe_breakpoint_handler(regs) : kprobe_breakpoint_handler(regs);
}
+NOKPROBE_SYMBOL(probe_breakpoint_handler);
void handle_break(struct pt_regs *regs)
{
@@ -303,6 +305,7 @@ void handle_break(struct pt_regs *regs)
else
die(regs, "Kernel BUG");
}
+NOKPROBE_SYMBOL(handle_break);
asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
{
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 6.18-6.1] gpio: sifive: add missing MODULE_DEVICE_TABLE()
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-6.6] riscv: kprobes: Prevent probes in breakpoint handlers Sasha Levin
@ 2026-10-19 13:50 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_MOVSX in RV32 JIT Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:50 UTC (permalink / raw)
To: patches, stable
Cc: Pengpeng Hou, Bartosz Golaszewski, Sasha Levin, linusw, brgl, pjw,
samuel.holland, linux-gpio, linux-riscv, linux-kernel
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ Upstream commit 8fe6fa0f223f44b8b869319d1b9c383749aa147b ]
The driver has an OF match table wired to .of_match_table, but does
not export the table with MODULE_DEVICE_TABLE().
Add the missing MODULE_DEVICE_TABLE(of, ...) entry so module alias
information is generated for OF based module autoloading.
This is a source-level fix. It does not claim dynamic hardware
reproduction; the evidence is the driver-owned match table, its use by
the platform driver, and the missing module alias publication.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260704122230.75964-1-pengpeng@iscas.ac.cn
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have the local-tree identity, the one-line diff, and the mailing-list
thread, including the GPIO maintainer asking for a `Fixes:`/`Cc: stable`
resend. Compiling the nine-phase verdict next.
## Phase 1: Commit message forensics
**Step 1.1: Subject line**
- Record: `[gpio] [add] add missing MODULE_DEVICE_TABLE() so OF module
aliases are generated`
**Step 1.2: Tags**
- Record:
- `Fixes:` — none (expected)
- `Reported-by:` — none
- `Tested-by:` — none
- `Reviewed-by:` — none on the applied commit
- `Acked-by:` — none
- `Link: https://patch.msgid.link/20260704122230.75964-1-
pengpeng@iscas.ac.cn`
- `Cc: stable@vger.kernel.org` — none (expected)
- `Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>` (author)
- `Signed-off-by: Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com>` (GPIO maintainer, committer)
- Notable: no syzbot, no user crash report. Maintainer SOB is a
quality signal.
**Step 1.3: Body**
- Record: **Bug:** `sifive_gpio_match[]` is wired to `.of_match_table`
but not published via `MODULE_DEVICE_TABLE()`, so modpost does not
emit OF aliases. **Symptom:** `gpio-sifive.ko` does not autoload from
DT compatible strings (`sifive,gpio0`, `sifive,fu540-c000-gpio`).
**Version info:** none in the message. **Root cause:** missing module-
alias publication, not a runtime logic error in probe. The “source-
level fix / no dynamic hardware reproduction” wording is extra
justification, not a different bug.
**Step 1.4: Hidden bug fix?**
- Record: Not hidden. This is an explicit autoload fix. “Add missing
MODULE_DEVICE_TABLE” is a standard class of real functional bugs for
`tristate` OF drivers.
## Phase 2: Diff analysis
**Step 2.1: Inventory**
- Record: `drivers/gpio/gpio-sifive.c` — **+1 / -0**. One insertion
after `sifive_gpio_match[]`. No functions changed. **Scope:** single-
file surgical fix.
**Step 2.2: Code flow**
- Record: **Before:** OF match table exists and is used by
`platform_driver.driver.of_match_table`, so a *already loaded* driver
still binds. No `__mod_device_table__*` alias is emitted, so kmod/udev
cannot load the module from DT. **After:** `MODULE_DEVICE_TABLE(of,
sifive_gpio_match)` creates a used alias to that table;
`scripts/mod/file2alias.c` (`do_of_entry`) emits
`of:N*T*Csifive,gpio0` / `sifive,fu540-c000-gpio` aliases. **Path
affected:** build-time modpost / userspace autoload only. Probe and
IRQ setup are unchanged.
**Step 2.3: Bug mechanism**
- Record: **Category:** hardware enablement / missing module alias
(logic/correctness at the module-loading boundary). **Mechanism:**
`CONFIG_GPIO_SIFIVE=m` never autoloads; GPIO controller stays unbound
unless `modprobe` is done by hand. Same class as device-ID additions:
existing driver, existing hardware, missing match publication.
**Step 2.4: Fix quality**
- Record: Obviously correct one-liner; this is the documented way to
export OF aliases. No locking, no API, no data-structure change.
**Regression risk:** negligible. For `=y` it is a no-op at runtime. No
new userspace ABI beyond standard `modules.alias` entries.
## Phase 3: Git history
**Step 3.1: Blame**
- Record: Match table introduced in `96868dce644d0` (“gpio/sifive: Add
GPIO driver for SiFive SoCs”, 2019; in `v5.5-rc4`). Originally `bool`
+ `builtin_platform_driver()`, so `MODULE_DEVICE_TABLE` was not
required. Bug became real in `6b4c76ded35826` (“gpio: sifive: Allow
building the driver as a module”, 2023-07-25) which switched Kconfig
to `tristate` and `module_platform_driver()` **without** adding
`MODULE_DEVICE_TABLE`. That commit is in `v6.6-rc1` and later.
`of_match_table = sifive_gpio_match` confirmed via blame
(`6ae42529547a4f` dropped `of_match_ptr` in 2023).
**Step 3.2: Fixes: tag**
- Record: No `Fixes:` on the candidate. The implicit Fixes target is
`6b4c76ded35826`, which **is** an ancestor of this tree (`git merge-
base --is-ancestor` succeeded). GPIO maintainer Bartosz said the same
on list (Phase 4).
**Step 3.3: File history**
- Record: Recent `gpio-sifive.c` work is generic-chip API
(`8e1c8ccc1df8b`) and the modular conversion. No prerequisite series
for this one line. Standalone.
**Step 3.4: Author**
- Record: Pengpeng Hou is not the GPIO maintainer; same-day sibling
`975a1d61260cf` (“gpio: vf610: add missing MODULE_DEVICE_TABLE()”).
Samuel Holland (SiFive, author of the modular conversion) sent the
identical one-line change earlier (Oct 2025) as “Support module
autoloading”.
**Step 3.5: Dependencies**
- Record: Needs `sifive_gpio_match[]`, `module_platform_driver()`, and
`MODULE_DEVICE_TABLE(of, ...)`. All exist in this checkout. Applies
standalone.
## Phase 4: Mailing list / external
**Step 4.1: Original discussion**
- Record: `b4 dig -c 8fe6fa0f223f44` matched patch-id to:
- v1 (applied):
https://patch.msgid.link/20260704122230.75964-1-pengpeng@iscas.ac.cn
(2026-07-04, Pengpeng Hou)
- Same diff, earlier: https://patch.msgid.link/20251016003631.3912523-
1-samuel.holland@sifive.com (2025-10-15, Samuel Holland)
- Single revision of Pengpeng’s patch. Bartosz: “Applied, thanks!”
(2026-07-06). No NAK.
- On Samuel’s earlier post, Bartosz wrote it should have been part of
`6b4c76ded358` and asked him to **resend with `Fixes:` and `Cc:
stable`**. That resend did not land; Pengpeng’s later patch (without
those tags) was applied instead.
**Step 4.2: Recipients (`b4 dig -w`)**
- Record: Pengpeng Hou, Linus Walleij, Bartosz Golaszewski, Paul
Walmsley, Samuel Holland, `linux-gpio`, `linux-riscv`, `linux-kernel`.
GPIO maintainers were on To/Cc.
**Step 4.3: Bug report**
- Record: No syzbot/bugzilla. Evidence is source-level plus vendor
(SiFive) sending the same patch. No count of field reports.
**Step 4.4: Series**
- Record: Standalone 1/1. Sibling vf610 fix is a separate driver, not a
dependency.
**Step 4.5: Stable list**
- Record: lore.kernel.org via WebFetch returned 403. Stable-list search
**UNVERIFIED** by HTTP. Maintainer request for `Cc: stable` is from
`linux-gpio` mbox, not from `stable@`.
## Phase 5: Semantic analysis
**Step 5.1: Functions**
- Record: No functions modified. Added `MODULE_DEVICE_TABLE(of,
sifive_gpio_match)` after `sifive_gpio_match[]`. Related symbols:
`sifive_gpio_probe`, `sifive_gpio_driver`.
**Step 5.2: Callers**
- Record: `sifive_gpio_probe` is the platform `.probe`. Driver core
calls it when OF compatible matches **and the module is already
loaded**. Autoload is userspace (kmod) using aliases from
`MODULE_DEVICE_TABLE`. Not IRQ/hot-path.
**Step 5.3: Callees**
- Record: Unchanged. Probe still uses generic GPIO + irqchip
registration.
**Step 5.4: Reachability**
- Record: Reachable on SiFive FU540/FU740 and Canaan K210 DT
(`compatible = "sifive,gpio0"` / `"sifive,fu540-c000-gpio"`).
Userspace-visible: without aliases, GPIO never appears unless the
module is forced. Not a syscall crash path.
**Step 5.5: Similar patterns**
- Record: Same pattern in-tree: `gpio: lpc32xx: fix module autoloading`,
`gpio: modepin: Enable module autoloading`, `gpio: vf610: add missing
MODULE_DEVICE_TABLE()`, `gpio: cadence: Add missing
MODULE_DEVICE_TABLE`. Established GPIO-subsystem practice.
## Phase 6: Local tree (this checkout only)
**Step 6.1: Buggy code in this tree?**
- Record: Checkout is **Linus `origin/master`**, `git describe` =
`v7.3-rc4-27-gf0100363d8c37`, Makefile **7.3.0-rc4**. `gpio-sifive.c`,
`sifive_gpio_match[]`, `tristate GPIO_SIFIVE`, and
`module_platform_driver()` are all present. Modular conversion
`6b4c76ded35826` is an ancestor. The one-line alias export belongs on
this code. In-tree DT: `arch/riscv/boot/dts/sifive/fu540-c000.dtsi`,
`fu740-c000.dtsi`, `arch/riscv/boot/dts/canaan/k210.dtsi`. Defconfigs
(`arch/riscv/configs/defconfig`, K210 defconfigs) set
`CONFIG_GPIO_SIFIVE=y`, so *default* RISC-V configs do not hit
autoload; `=m` (the reason the driver was made modular: multiplatform
image size) does.
**Step 6.2: Backport difficulty**
- Record: Clean apply. Only needs the `of_device_id` table name
`sifive_gpio_match`. No conflict with later generic-chip changes.
**Step 6.3: Related fixes already here**
- Record: No earlier alternate autoload fix. This is the first
`MODULE_DEVICE_TABLE` on this file.
## Phase 7: Subsystem context
**Step 7.1**
- Record: **Subsystem:** GPIO (`drivers/gpio/`). **Criticality:**
IMPORTANT for SiFive/K210 boards (GPIO is a board-level dependency),
PERIPHERAL vs core mm/net. Not staging.
**Step 7.2**
- Record: GPIO is actively maintained (Bartosz). This driver is mature
(since v5.5); the modular hole is from v6.6, not new experimental
code.
## Phase 8: Impact and risk
**Step 8.1: Who is affected**
- Record: Driver-specific, config-specific: `CONFIG_GPIO_SIFIVE=m` on DT
platforms with those compatibles. Not universal.
**Step 8.2: Trigger**
- Record: Boot / device enumeration with the module not preloaded.
Common for multiplatform modular kernels (the stated goal of
`6b4c76ded358`). Unprivileged users do not trigger a crash; the
controller simply never binds. Not a race.
**Step 8.3: Failure mode**
- Record: GPIO chip (and its irqchip) never registers if the module is
not loaded. Dependent LEDs, resets, keys, hog lines fail. **Severity:
MEDIUM** functionally (hardware dead until `modprobe`), not panic/UAF.
For those boards that is user-visible breakage, not cosmetic.
**Step 8.4: Risk-benefit**
- Record: **Benefit:** high for `=m` SiFive/K210 users; restores the
modular conversion’s purpose. **Risk:** very low (1 line, build-time
alias only). **Ratio:** strongly favorable. Matches the device-ID /
hardware-enablement exception.
## Phase 9: Synthesis
**Step 9.1: Evidence**
- **For:** Real autoload bug; 1-line obviously correct; GPIO maintainer
asked for `Fixes:` + `Cc: stable` on the identical diff; SiFive
engineer sent that diff; driver is `tristate` since v6.6; DT hardware
exists; zero runtime regression surface; same pattern already used
across GPIO.
- **Against:** Not a crash/security/corruption issue; in-tree defconfigs
use `=y`; no `Reported-by`; Pengpeng’s applied patch omitted the
`Fixes:`/`Cc: stable` Bartosz asked for.
- **Unresolved:** Stable-list archive (lore HTTP 403). No field bugzilla
count.
**Step 9.2: Stable rules**
1. Obviously correct and tested? **PASS** — canonical
`MODULE_DEVICE_TABLE(of, …)`; maintainer applied it.
2. Real bug affecting users? **PASS** — `=m` never autoloads; modular
conversion is pointless without it.
3. Important (crash/security/corruption/deadlock)? **PASS** as hardware-
enablement (GPIO controller never binds), same bar as new device IDs
/ missing aliases — not a panic, but the device does not work.
4. Small and contained? **PASS** — +1 line, one file.
5. No new features/APIs? **PASS** — aliases for existing compatibles.
6. Can apply to this tree? **PASS** — table, tristate Kconfig, and
`module_platform_driver()` are here.
**Step 9.3: Exception category**
- Record: Closest to **device ID / hardware enablement**: publishing
existing OF IDs so the existing driver autoloads. Not a new driver or
API.
**Step 9.4: Decision**
This tree has the SiFive GPIO driver as a module-capable OF platform
driver with a match table that was never exported. That is a real,
contained autoload bug. The GPIO maintainer already treated the
identical change as stable material. It should be backported here.
### What the commit solves for this tree
Without `MODULE_DEVICE_TABLE(of, sifive_gpio_match)`, `modpost` never
writes OF aliases, so `gpio-sifive.ko` will not load from
`"sifive,gpio0"` / `"sifive,fu540-c000-gpio"`. On `CONFIG_GPIO_SIFIVE=m`
the GPIO (and irq) controller never appears unless someone `modprobe`s
it. That undercuts `6b4c76ded358` (“Allow building the driver as a
module”) on multiplatform kernels. Built-in `=y` is unaffected; the one-
liner is still correct and harmless.
### Risk vs benefit
Benefit is restoring autoload for real FU540/FU740/K210 hardware when
the driver is modular. Risk is a single build-time alias with no
probe/locking/API change.
### Concerns
No `Fixes:` on the applied commit (should be `6b4c76ded35826`); that
does not block backport. In-tree defconfigs use `=y`, so default images
already work; the users who need this are modular/multiplatform configs,
which is exactly who the tristate change was for.
Verification:
- [Phase 1] Parsed tags: Link to msgid
`20260704122230.75964-1-pengpeng@iscas.ac.cn`; SOB Pengpeng Hou and
Bartosz Golaszewski; no Fixes/Reported-by/Cc: stable
- [Phase 2] Diff: +1 line `MODULE_DEVICE_TABLE(of, sifive_gpio_match)`
in `drivers/gpio/gpio-sifive.c`; probe unchanged
- [Phase 2] Confirmed `MODULE_DEVICE_TABLE` in `include/linux/module.h`
and OF alias emission via `scripts/mod/file2alias.c` `do_of_entry`
- [Phase 3] `git blame`: match table from `96868dce644d0` (v5.5-rc4);
modular bug from `6b4c76ded35826` (in v6.6-rc1); `git merge-base --is-
ancestor 6b4c76ded35826 HEAD` succeeded
- [Phase 3] `git show 6b4c76ded35826`: bool→tristate +
`builtin_platform_driver` → `module_platform_driver` without
MODULE_DEVICE_TABLE
- [Phase 3] Author log: sibling vf610 commit `975a1d61260cf`
- [Phase 4] `b4 dig -c 8fe6fa0f223f44`: Pengpeng v1 applied; same patch-
id as Samuel Holland Oct 2025
- [Phase 4] `b4 dig -a`: single Pengpeng revision; `b4 dig -w`: GPIO
maintainers + linux-gpio/linux-riscv
- [Phase 4] mbox: Bartosz asked Samuel for Fixes: + Cc: stable; later
“Applied, thanks!” on Pengpeng’s patch
- [Phase 4] WebFetch lore.kernel.org: 403 — UNVERIFIED via HTTP; thread
recovered with b4 mbox
- [Phase 5] Callers: platform probe + OF match table; autoload is
userspace/kmod, not a kernel hot path
- [Phase 5] Similar GPIO autoload fixes: `11baa36d31732`,
`a5135526426df`, `e6382fcf98907`
- [Phase 6] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37; `make
kernelversion` = 7.3.0-rc4; detached `origin/master`
- [Phase 6] Kconfig `GPIO_SIFIVE` is `tristate`; DT nodes present;
defconfigs use `=y`
- [Phase 8] Failure mode: module not autoloaded → GPIO controller
absent; severity MEDIUM functional / hardware-enablement
- UNVERIFIED: whether this exact commit was discussed on
`stable@vger.kernel.org` (lore HTTP 403)
- UNVERIFIED: how many distro configs set `CONFIG_GPIO_SIFIVE=m`
**YES**
drivers/gpio/gpio-sifive.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c
index 94ef2efbd14f5..e9a992cd4b9cd 100644
--- a/drivers/gpio/gpio-sifive.c
+++ b/drivers/gpio/gpio-sifive.c
@@ -260,6 +260,7 @@ static const struct of_device_id sifive_gpio_match[] = {
{ .compatible = "sifive,fu540-c000-gpio" },
{ },
};
+MODULE_DEVICE_TABLE(of, sifive_gpio_match);
static struct platform_driver sifive_gpio_driver = {
.probe = sifive_gpio_probe,
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-6.1] gpio: sifive: add missing MODULE_DEVICE_TABLE() Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_MOVSX in RV32 JIT Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Atish Patra, Sashiko AI, Charlie Jenkins, Paul Walmsley,
Sasha Levin, atish.patra, will, mark.rutland, palmer, aou,
linux-riscv, linux-arm-kernel, linux-perf-users, linux-kernel
From: Atish Patra <atishp@meta.com>
[ Upstream commit e24a1418e90beac2ef4384bc9b0b5a10f19b806e ]
Sashiko pointed out various UAF and memory leak issues around
pmu_sbi_device_probe() error paths.
If the probe fails, here are list of cleanups needed.
a. Already registered pmu must be freed
b. per cpu IRQ must be released
c. pmu_ctr_list data structure must be freed
d. cpu hotplug state must be cleaned up only if added.
Fix the resource cleanup by reorganizing the code around probe failure.
Reported-by: Sashiko AI <sashiko-bot@kernel.org>
Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
Signed-off-by: Atish Patra <atishp@meta.com>
Link: https://patch.msgid.link/20260807-counter_delegation-v9-1-58658104e487@meta.com
Signed-off-by: Paul Walmsley <pjw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This tree is **6.12.111** (`pending-6.12`). The buggy probe cleanup is
present here, the patch applies, and it is a real UAF/leak/crash fix — a
YES for this tree.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[RISC-V perf / SBI PMU] [fix] [resource cleanup on driver probe
failure]`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Reported-by: Sashiko AI <sashiko-bot@kernel.org>` — static-analysis
bot, not a user oops, but it named concrete UAF/leak paths
- `Reviewed-by: Charlie Jenkins <thecharlesjenkins@gmail.com>` — RISC-V
reviewer
- `Signed-off-by: Atish Patra <atishp@meta.com>` — original SBI PMU
driver author
- `Link: https://patch.msgid.link/20260807-counter_delegation-v9-1-
58658104e487@meta.com` — **v9 01/20** of the counter-delegation series
- `Signed-off-by: Paul Walmsley <pjw@kernel.org>` — RISC-V maintainer
- No `Fixes:` tag (expected)
- Ignore pipeline `Signed-off-by: Sasha Levin` / `[Upstream commit ...]`
— none on the real commit `e24a1418e90be`
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `pmu_sbi_device_probe()` error paths leak and leave live
references to freed objects
- **Needed cleanups:** (a) unregister an already-registered PMU, (b)
release the per-CPU IRQ, (c) free `pmu_ctr_list`, (d) remove the CPU-
hotplug instance only if it was added
- **Symptom:** UAF and memory leaks if probe fails after partial setup
- **Root cause:** probe does `goto out_unregister` / `out_free` without
matching teardown
- **Version info:** none in the message; code dates to 2022–2024
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. It is an explicit error-path UAF/leak fix.
“Reorganizing probe failure” is the usual `goto` cleanup pattern, not a
refactor-for-its-own-sake.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `drivers/perf/riscv_pmu_sbi.c` — **+27 / −6** (33 insertions, 6
deletions)
- Functions: `pmu_sbi_setup_irqs()`, `riscv_pmu_destroy()`,
`pmu_sbi_device_probe()`
- Scope: single-file surgical error-path fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
1. **`pmu_sbi_setup_irqs()`**
- Before: domain/mapping/request failures return immediately.
`riscv_pmu_use_irq` can stay **true** even though no IRQ was
installed. Mapping leaked if `request_percpu_irq()` failed.
- After: those paths `goto err`, dispose a created mapping, set
`riscv_pmu_use_irq = false`.
2. **`riscv_pmu_destroy()`**
- Before: always `cpuhp_state_remove_instance()` even when the
instance was never added.
- After: only if `!hlist_unhashed(&pmu->node)`.
3. **`pmu_sbi_device_probe()`**
- Before: `riscv_pm_pmu_register` / `perf_pmu_register` failures jump
to `out_unregister` (destroy + `kfree(pmu)` only). Snapshot-alloc
and cpuhp-add failures also skip `perf_pmu_unregister`. IRQ,
`hw_events`, and `pmu_ctr_list` never freed.
- After: `irq_requested` tracks a successful IRQ request. Failures
before PMU register go to `out_destroy`. Failures after register go
to `out_unregister` which now calls `perf_pmu_unregister`. Then
IRQ/percpu/`pmu_ctr_list`/`pmu` are freed.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Error-path resource leak + UAF + NULL deref**, with a logic
fix on the IRQ fallback path.
Verified mechanisms in **this** tree:
| Bug | Mechanism |
|---|---|
| **UAF of registered PMU** | `perf_pmu_register()` then
`pmu_sbi_snapshot_alloc()` or `cpuhp_state_add_instance()` fails →
`kfree(pmu)` while the PMU stays in perf core |
| **NULL deref / list corruption** | `riscv_pmu_destroy()` →
`cpuhp_state_remove_instance()` → `hlist_del()` → `WRITE_ONCE(*pprev,
next)` with `pprev == NULL` on a `kzalloc`’d node |
| **IRQ + cookie UAF** | successful `request_percpu_irq(..., hw_events)`
then later probe fail frees `pmu`/`hw_events` without `free_percpu_irq`
|
| **Leaks** | `alloc_percpu` `hw_events` and `kcalloc` `pmu_ctr_list`
only freed on the new `out_free` |
| **Wrong IRQ flag on success path** | IRQ setup failure is **non-
fatal**; probe continues with `PERF_PMU_CAP_NO_INTERRUPT` but
`riscv_pmu_use_irq` stayed true, so `pmu_sbi_starting_cpu()` can
`enable_percpu_irq(0)` |
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct and minimal. `out_unregister` is only reached
after a successful `perf_pmu_register`. `out_destroy` does not
unregister. `hlist_unhashed` matches `cpuhp` (node is hashed only after
successful add). IRQ free happens before `free_percpu(hw_events)`.
Regression risk: **low**. Remaining gaps (sysctl not unregistered;
`sbi_pmu_snapshot_available` static key not disabled) are pre-existing
and not introduced here. They do not make this patch unsafe.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- IRQ error returns: `4905ec2fb7e642` (Atish Patra, 2022-02-18) —
sscofpmf
- Destroy / `out_unregister`: `e9a023f2b73ac3` (Eric Lin, 2022-07-05) —
PM notifier
- Snapshot + moving `cpuhp_state_add_instance` **after** register:
`a8625217a054ca` (Atish Patra, 2024-04-20) — **this is when the
registered-PMU UAF became real**
- Original `kfree(pmu)`-only `out_free`: `e9991434596f53` (2022-02-18) —
driver introduction
All of these are ancestors of this 6.12 tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Buggy code is still in this checkout (see Phase
6).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record (this tree, `git log --oneline -20 --
drivers/perf/riscv_pmu_sbi.c`): overflow-IRQ NULL check, bitmap cmask,
errno/firmware-event fixes. None of those replace this cleanup. `git log
--oneline e24a1418e90be..origin/master -- drivers/perf/riscv_pmu_sbi.c`
only shows later overflow-mask/bitmap work; they do not revert or redo
this cleanup.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Atish Patra wrote the SBI PMU driver (`e9991434596f53`) and the
snapshot code. This is a maintainer-area fix, not drive-by.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Msgid is `counter_delegation-v9-1`. Patches 2–20 add
Smcsrind/Ssccfg/Smcdeleg and a new PMU path. They are **features**, not
prerequisites. This hunk only uses `hlist_unhashed`,
`perf_pmu_unregister`, `free_percpu_irq`, `irq_dispose_mapping`,
`free_percpu`, `pmu_ctr_list` — all already in 6.12. **Standalone.**
`git show e24a1418e90be | git apply --check` succeeded (offsets only).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c e24a1418e90be`: matched patch-id; lore URL `https://patch.m
sgid.link/20260807-counter_delegation-v9-1-58658104e487@meta.com`
- `b4 dig -a`: cleanup first appeared as **v7 01/22** (2026-06-22), then
**v9 01/20** (committed)
- WebFetch of lore returned **403** (Anubis). Thread was recovered via
`b4 dig -m /tmp/riscv-pmu-cleanup.mbox`
- No NAK on this patch. Paul Walmsley queued the first ten patches
(including this one) for `riscv/for-next`
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: Charlie Jenkins `Reviewed-by`. Paul Walmsley applied it.
Recipients are the RISC-V list / maintainers (from msgid and SOBs). No
`Cc: stable` in review.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: Reporter is Sashiko, not syzbot. v9 review of **this** patch
restates remaining **pre-existing** issues (snapshot disable without CPU
pin, static key, sysctl leak, init-time cpuhp leak). It does **not** NAK
the cleanup. The UAF it describes of a registered-then-freed PMU is
exactly what `perf_pmu_unregister` addresses.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Rest of v9 is new ISA / delegation code. Not needed for this
cleanup. Later origin/master commits on this file do not change these
error labels.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable WebFetch also 403. **UNVERIFIED** whether
stable@ already discussed this. Absence of `Cc: stable` is expected for
this review queue.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `pmu_sbi_setup_irqs`, `riscv_pmu_destroy`,
`pmu_sbi_device_probe`. Related: `pmu_sbi_starting_cpu`,
`riscv_pmu_alloc`, `pmu_sbi_get_ctrinfo`.
**Step 5.2: TRACE CALLERS**
Record:
- `pmu_sbi_device_probe` — `.probe` of `pmu_sbi_driver`
- Called from `pmu_sbi_devinit()` (`device_initcall`) via
`platform_device_register_simple(RISCV_PMU_SBI_PDEV_NAME, ...)`
- `pmu_sbi_starting_cpu` / `pmu_sbi_dying_cpu` read `riscv_pmu_use_irq`
(the flag this patch clears on IRQ setup failure)
**Step 5.3: TRACE CALLEES**
Record: `riscv_pmu_alloc()` does `kzalloc` + `alloc_percpu_gfp` (this
tree, `drivers/perf/riscv_pmu.c`). `pmu_sbi_get_ctrinfo()` `kcalloc`s
`pmu_ctr_list`. `cpuhp_state_remove_instance()` always `hlist_del()`s.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Boot/init on RISC-V with SBI PMU (`CONFIG_RISCV_PMU_SBI`
**default y**). Trigger is probe failure after partial success:
`snapshot_alloc` ENOMEM, `perf_pmu_register` failure,
`cpuhp_state_add_instance` failure, or `cpu_pm_register_notifier`
failure. After a successful `perf_pmu_register` and a later fail,
userspace `perf` can touch a PMU whose `struct riscv_pmu` is already
`kfree`d — **userspace-reachable UAF**.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same file’s `pmu_sbi_devinit()` still leaks
`cpuhp_setup_state_multi` if `platform_driver_register` fails. Pre-
existing, out of this patch’s scope.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** This checkout is 6.12.111; `e24a1418e90be` is **not**
an ancestor (`git merge-base --is-ancestor` exit 1).
Current probe error path (`drivers/perf/riscv_pmu_sbi.c`):
```1462:1468:drivers/perf/riscv_pmu_sbi.c
out_unregister:
riscv_pmu_destroy(pmu);
out_free:
kfree(pmu);
return ret;
```
`riscv_pmu_destroy()` still unconditionally removes the cpuhp instance.
`pmu_sbi_setup_irqs()` still returns without clearing
`riscv_pmu_use_irq` or disposing a mapping.
Bug introduced: leaks since v5.17-era driver; UAF of registered PMU
since snapshot/cpuhp reorder in `a8625217a054ca` (in this tree).
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply** (`git apply --check` — all 6 hunks succeeded
with −54 line offset). Context differs (`bitmap_copy` vs mainline
`pmu->cmask = cmask`) because 6.12 already has `143668c424772` (counter
mask as bitmap). No rework required.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No equivalent cleanup. Bitmap and overflow-IRQ fixes in this
tree are independent.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: `drivers/perf` / RISC-V SBI PMU. **IMPORTANT** for RISC-V
(default-on perf), not core-mm/VFS. Not staging.
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Mature driver (2022) with ongoing RISC-V perf fixes. This is a
long-standing error-path hole, not churn in brand-new code.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: WHO IS AFFECTED**
Record: RISC-V systems with `CONFIG_RISCV_PMU_SBI` (default y) and SBI
PMU (QEMU virt, most recent boards). Driver-specific, not universal.
**Step 8.2: TRIGGER CONDITIONS**
Record:
- Common path: probe succeeds — no crash
- Realistic fail: `pmu_sbi_snapshot_alloc()` ENOMEM (page alloc
GFP_ATOMIC per CPU) **after** `perf_pmu_register`
- IRQ mapping fail with SSCOF/T-Head/Andes: probe **continues**,
`riscv_pmu_use_irq` wrongly stays true
- Unprivileged user cannot force probe, but **can** open the registered
`"cpu"` PMU in the failure window
**Step 8.3: FAILURE MODE SEVERITY**
Record:
- Registered PMU then `kfree(pmu)` → **UAF** → HIGH
- `hlist_del` on unhashed node → **oops** → HIGH
- IRQ cookie UAF → HIGH
- One-time leaks if probe dies before register → MEDIUM
- `enable_percpu_irq(0)` on fallback success path → MEDIUM–HIGH
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- **Benefit:** high for RISC-V 6.12 — prevents oops/UAF on probe fail
and a wrong IRQ flag on a continued probe
- **Risk:** low — ~27 net lines, error path + one flag clear, applies
cleanly
- **Ratio:** favor backport
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: EVIDENCE**
**FOR:**
- Real UAF: perf-registered PMU freed without unregister (snapshot/cpuhp
fail after `perf_pmu_register`)
- Real oops: `cpuhp_state_remove_instance` → `hlist_del` with NULL
`pprev`
- Real IRQ leak/UAF and `pmu_ctr_list`/`hw_events` leaks
- `riscv_pmu_use_irq` left true on non-fatal IRQ setup failure (success-
path bug)
- Small, obviously correct, reviewed by Charlie Jenkins, authored by the
driver owner
- Buggy code and helpers exist in 6.12; patch applies cleanly
- Standalone despite being 01/20 of a feature series
**AGAINST:**
- Probe-fail is uncommon (except IRQ-setup fallback, which is not fatal
and is common on some platforms)
- Incomplete: sysctl, snapshot static key, init-time cpuhp still leak
(pre-existing)
- RISC-V only
- Reported by an AI bot, not a production oops
**UNRESOLVED:** stable@ thread (lore 403); whether Sashiko had a
concrete reproducer beyond code review.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — reviewed, applied by RISC-V
maintainer, logic matches the four listed holes
2. Fixes a real bug that affects users? **PASS** — UAF/oops/leaks in the
default RISC-V PMU driver
3. Important issue? **PASS** — UAF and NULL deref are HIGH; not a style
cleanup
4. Small and contained? **PASS** — one file, +27/−6
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — `git apply --check` clean
**Step 9.3: EXCEPTION CATEGORIES**
Record: None. Ordinary bugfix.
**Step 9.4: DECISION**
This 6.12 tree has the buggy probe path. The fix is small, applies, and
closes UAF/oops/leak holes in a default-on RISC-V driver. Remaining
cleanup gaps are not a reason to withhold the part that is correct.
---
## What this means for 6.12 users
On RISC-V with SBI PMU, a failed probe after `perf_pmu_register()`
currently frees `struct riscv_pmu` while perf still holds it, and
`riscv_pmu_destroy()` oopses by deleting an unhashed cpuhp node. The
same path leaks the per-CPU IRQ cookie, `hw_events`, and `pmu_ctr_list`.
IRQ setup failure is treated as non-fatal but leaves `riscv_pmu_use_irq`
set, so hotplug can enable IRQ 0. The patch only rewires those gotos and
frees; it does not pull in counter-delegation.
Risk is low relative to leaving a registered-PMU UAF in a long-term
tree.
---
## Verification
- **[Phase 1]** Parsed tags: Sashiko Reported-by, Charlie Jenkins
Reviewed-by, Atish Patra + Paul Walmsley SOBs, msgid v9 01/20; no
Fixes
- **[Phase 2]** Diff: +27/−6 in `riscv_pmu_sbi.c`; IRQ err goto,
`hlist_unhashed` guard, `perf_pmu_unregister`,
`free_percpu_irq`/`free_percpu`/`kfree(pmu_ctr_list)`
- **[Phase 2]** Read 6.12 `pmu_sbi_device_probe` lines 1367–1468:
destroy + `kfree(pmu)` only
- **[Phase 2]** Read `kernel/cpu.c` `__cpuhp_state_remove_instance`:
always `hlist_del(node)`
- **[Phase 2]** Read `include/linux/list.h` `__hlist_del`:
`WRITE_ONCE(*pprev, next)` NULL-derefs if never hashed
- **[Phase 2]** Read `__cpuhp_state_add_instance_cpuslocked`:
`hlist_add_head` only on success
- **[Phase 3]** `git blame` IRQ path `4905ec2fb7e642` (2022); destroy
`e9a023f2b73ac3` (2022); snapshot/cpuhp order `a8625217a054ca` (2024,
in this tree)
- **[Phase 3]** `git merge-base --is-ancestor e24a1418e90be HEAD` → not
in this tree; `e9a023f2b73ac3` / `a8625217a054ca` / `e9991434596f53` →
in this tree
- **[Phase 3]** Follow-ups on origin/master do not redo this cleanup
- **[Phase 4]** `b4 dig -c e24a1418e90be` → patch.msgid.link v9-1; `-a`
shows v7 first, v9 applied
- **[Phase 4]** `b4 dig -m`: 31-message mbox; Sashiko comments are pre-
existing leftovers; Paul queued first ten patches; no NAK
- **[Phase 4]** WebFetch lore/stable: 403 — UNVERIFIED stable-list
discussion
- **[Phase 5]** Probe from `device_initcall(pmu_sbi_devinit)`;
`riscv_pmu_alloc` allocates `hw_events`; `pmu_sbi_get_ctrinfo`
allocates `pmu_ctr_list`
- **[Phase 5]** `pmu_sbi_starting_cpu` uses `riscv_pmu_use_irq` /
`riscv_pmu_irq`
- **[Phase 6]** `git describe HEAD` → `p-6.12-4-gbf6fcdf761abd`; `make
kernelversion` → **6.12.111**
- **[Phase 6]** `git apply --check` of `e24a1418e90be`: all hunks OK
- **[Phase 7]** `CONFIG_RISCV_PMU_SBI` default y in
`drivers/perf/Kconfig`
- **[Phase 8]** Failure mode: UAF of registered PMU + cpuhp oops → HIGH
- **UNVERIFIED:** live user oops; stable@ nomination history
**YES**
drivers/perf/riscv_pmu_sbi.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 25f3a45dd7869..10f64b7b60c53 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -1258,22 +1258,29 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
DOMAIN_BUS_ANY);
if (!domain) {
pr_err("Failed to find INTC IRQ root domain\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
riscv_pmu_irq = irq_create_mapping(domain, riscv_pmu_irq_num);
if (!riscv_pmu_irq) {
pr_err("Failed to map PMU interrupt for node\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
if (ret) {
pr_err("registering percpu irq failed [%d]\n", ret);
- return ret;
+ irq_dispose_mapping(riscv_pmu_irq);
+ riscv_pmu_irq = 0;
+ goto err;
}
return 0;
+err:
+ riscv_pmu_use_irq = false;
+ return ret;
}
#ifdef CONFIG_CPU_PM
@@ -1340,7 +1347,8 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
}
}
riscv_pm_pmu_unregister(pmu);
- cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
+ if (!hlist_unhashed(&pmu->node))
+ cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
}
static void pmu_sbi_event_init(struct perf_event *event)
@@ -1462,6 +1470,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
struct riscv_pmu *pmu = NULL;
int ret = -ENODEV;
int num_counters;
+ bool irq_requested = false;
pr_info("SBI PMU extension is available\n");
pmu = riscv_pmu_alloc();
@@ -1490,6 +1499,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
}
+ irq_requested = (ret == 0);
pmu->pmu.attr_groups = riscv_pmu_attr_groups;
pmu->pmu.parent = &pdev->dev;
@@ -1508,11 +1518,11 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
ret = riscv_pm_pmu_register(pmu);
if (ret)
- goto out_unregister;
+ goto out_destroy;
ret = perf_pmu_register(&pmu->pmu, "cpu", PERF_TYPE_RAW);
if (ret)
- goto out_unregister;
+ goto out_destroy;
/* SBI PMU Snapsphot is only available in SBI v2.0 */
if (sbi_v2_available) {
@@ -1553,9 +1563,20 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
return 0;
out_unregister:
+ perf_pmu_unregister(&pmu->pmu);
+
+out_destroy:
riscv_pmu_destroy(pmu);
+ if (irq_requested) {
+ free_percpu_irq(riscv_pmu_irq, pmu->hw_events);
+ irq_dispose_mapping(riscv_pmu_irq);
+ riscv_pmu_irq = 0;
+ }
out_free:
+ free_percpu(pmu->hw_events);
+ kfree(pmu_ctr_list);
+ pmu_ctr_list = NULL;
kfree(pmu);
return ret;
}
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 6.18-5.10] riscv, bpf: Add support for BPF_MOVSX in RV32 JIT
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] RISC-V: perf: fix resource cleanup on driver probe failure Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Kuan-Wei Chiu, Pu Lehui, Kumar Kartikeya Dwivedi, Sasha Levin,
ast, daniel, andrii, eddyz87, luke.r.nels, xi.wang, pjw, palmer,
aou, bpf, linux-riscv, linux-kernel
From: Kuan-Wei Chiu <visitorckw@gmail.com>
[ Upstream commit c6a08afdfe3a81b1a54e921921e9481dd6c78f8a ]
The current rv32 bpf jit compiler incorrectly treats BPF_MOVSX as a
standard zero-extended move operation. The bpf instruction set allows
sign-extension moves by reusing the BPF_MOV opcode with the instruction
offset set to 8, 16, or 32.
Update the bpf_jit_emit_insn() function to check the offset field for
both ALU and ALU64 MOV operations. If the offset is non-zero, emit the
correct slli and srai instructions to perform the sign extension.
Before this patch:
[ 19.549705] test_bpf: #82 ALU_MOVSX | BPF_B jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
[ 19.551354] test_bpf: #83 ALU_MOVSX | BPF_H jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
[ 19.552576] test_bpf: #84 ALU64_MOVSX | BPF_B jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
[ 19.553542] test_bpf: #85 ALU64_MOVSX | BPF_H jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
[ 19.554807] test_bpf: #86 ALU64_MOVSX | BPF_W jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
After this patch:
[ 17.931172] test_bpf: #82 ALU_MOVSX | BPF_B jited:1 125 PASS
[ 17.932198] test_bpf: #83 ALU_MOVSX | BPF_H jited:1 124 PASS
[ 17.933039] test_bpf: #84 ALU64_MOVSX | BPF_B jited:1 124 PASS
[ 17.933918] test_bpf: #85 ALU64_MOVSX | BPF_H jited:1 124 PASS
[ 17.934751] test_bpf: #86 ALU64_MOVSX | BPF_W jited:1 122 PASS
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Reviewed-by: Pu Lehui <pulehui@huawei.com>
Link: https://lore.kernel.org/bpf/20260714002451.4091139-3-visitorckw@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This is a real RV32 eBPF JIT miscompilation of an existing CPU-v4
instruction, not a new userspace API. On this 7.3-rc4 tree the RV32 JIT
and BPF_MOVSX ISA are both present, the patch is small and tested, and
it should be included.
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: [riscv, bpf] [Add support] [RV32 JIT was compiling BPF_MOVSX as
a plain zero-extending MOV; emit slli/srai sign-extend when insn->off is
8/16/32]
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- Reviewed-by: Pu Lehui <pulehui@huawei.com> (RISC-V BPF JIT reviewer;
also authored RV64 MOVSX in 694896ad3ca79)
- Link: https://lore.kernel.org/bpf/20260714002451.4091139-3-
visitorckw@gmail.com
- Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com> (author)
- Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> (BPF
maintainer, applied to bpf-next)
- No Fixes:, no Reported-by, no Cc: stable, no syzbot (absence expected)
- Ignore pipeline SOBs/Upstream markers: none present on the real commit
c6a08afdfe3a8
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- Bug: RV32 JIT treats BPF_MOVSX as a normal zero-extended move. BPF
reuses BPF_MOV with off=8/16/32 for sign-extending moves.
- Symptom: test_bpf cases #82–#86 fail with `jited:1 ret 2 != 1` (JIT
ran, produced the wrong return).
- After: those five tests PASS.
- Root cause: `bpf_jit_emit_insn()` did not inspect `insn->off` on
ALU/ALU64 MOV|X, so it fell through into `emit_alu_r64`/`emit_alu_r32`
BPF_MOV (plain copy).
- No version range in the message. ISA support dates to v6.6-era
(8100928c88148, 2023).
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Yes. The subject says “Add support”, but the body is explicit
miscompilation. Cover letter for the series: the JIT “ignor[es] the
instruction offset field and treat[s] them as unsigned or zero-
extended.” v1 was titled “Fix support…”. v2 added Fixes: tags; v3
“Remove the Fixes: tag and update title” for bpf-next process, not
because it stopped being a bug. Unlike patch 3/3 (atomics), which *does*
fall back to the interpreter, MOVSX is a supported opcode that emits the
wrong code.
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `arch/riscv/net/bpf_jit_comp32.c` (+32 / −0)
- Function: `bpf_jit_emit_insn()` only
- Scope: single-file surgical JIT codegen
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- Hunk 1 (`BPF_ALU64 | BPF_MOV | BPF_X`): before, always fell through to
`emit_alu_r64()` which copies lo/hi. After, if `off != 0`, sign-extend
lo (slli/srai 24 for byte, 16 for half, or copy lo for word) then
`srai hi, lo, 31` to fill the upper 32 bits of the RV32 register pair.
- Hunk 2 (`BPF_ALU | BPF_MOV | BPF_X`): after the existing `imm == 1`
zext special case, if `off != 0` sign-extend lo for off 8 or 16, then
`bpf_put_reg32()` (which still zero-extends hi unless
`verifier_zext`).
- Normal `off == 0` MOV is unchanged (`fallthrough`).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: [Logic / correctness — JIT miscompilation]
- Broken: BPF_MOVSX shares the MOV opcode; offset was ignored, so sign-
extend became a full register copy. test_bpf then compares against the
sign-extended expected value and fails (`ret 2`).
- Fix: emit the same slli/srai pattern other 32-bit JITs use (see arm32
`emit_a32_movsx_r64`).
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct relative to the ISA and to RV64 (`switch
(insn->off)` at bpf_jit_comp64.c:1408). Minimal. Regression risk is low:
only the previously-wrong `off != 0` path changes. ALU32 does not handle
off==32, which matches the ISA (MOVSX32 is 8 or 16 only). ALU64’s `else`
treats any other non-zero off as word sign-extend (off==32); the
verifier should not emit other values. No API/data-structure change.
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record: The MOV|X fallthrough and `emit_alu_r64` BPF_MOV copy were
introduced in 5f316b65e99f1 (“riscv, bpf: Add RV32G eBPF JIT”, 2020,
v5.6). That was correct until BPF_MOVSX existed. ISA commit
8100928c88148 (“bpf: Support new sign-extension mov insns”,
v6.5-rc2-583, in 6.6). RV64 JIT got MOVSX in 694896ad3ca79 (2023). RV32
was left emitting the old MOV path until this commit.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: on the landed commit. v2 of the series had Fixes:
tags; they were dropped in v3 when the series was retitled for bpf-next.
The semantically “buggy” point is 8100928c88148 (MOVSX added, RV32 JIT
not updated). That commit is an ancestor of this tree.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Same-day series on the same file:
- 2e0fa2389c50f — BPF_SDIV/SMOD (patch 1/3)
- c6a08afdfe3a8 — this commit (patch 2/3)
- a1b37972efc0b — 32-bit atomics (patch 3/3)
MOVSX does not use the SDIV `emit_alu_r32()` signature change and does
not use the atomic helper. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Kuan-Wei Chiu’s only RV32 JIT work in this tree is this 3-patch
series. Reviewer Pu Lehui maintains RISC-V BPF JIT (RV64 MOVSX, later
kfunc sign-extend fix f2aaa62159109). Applied by Kartikeya. Strong
maintainer path.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Uses `bpf_get_reg64`/`bpf_put_reg64`/`bpf_get_reg32`/`bpf_put_re
g32`/`rv_slli`/`rv_srai`/`rv_addi` — all from the original 2020 JIT. No
new helpers. Can apply standalone.
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- b4 dig:
https://patch.msgid.link/20260714002451.4091139-3-visitorckw@gmail.com
- Series: bpf-next v1→v4, “signed operations and 32-bit atomics”
- v1 (2026-04-29): “Fix support for BPF_SDIV and BPF_SMOD”
- v2: “Add missing Fixes tags”
- v3: “Remove the Fixes: tag and update title”
- v4 (applied): this version
- No NAKs. Pu Lehui Reviewed-by on this patch; Tested-by on the series
(test_bpf failures drop).
- No reviewer asked for Cc: stable.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: To/Cc included bpf@vger, linux-riscv, ast, daniel, andrii,
eddyz87, memxor, palmer, aou, pulehui, yonghong.song (original MOVSX ISA
author), alex@ghiti.fr. Appropriate lists. Applied by Kartikeya to bpf-
next.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No external bugzilla/syzbot. Evidence is in-tree
`lib/test_bpf.c` ALU_MOVSX tests (from daabb2b098e04, cpuv4 tests).
Failure is `jited:1` with wrong R0.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: 3/3 series. 1/3 is the same class of bug (SDIV/SMOD as
unsigned). 3/3 is a feature (atomics already interpreter-fallback). This
patch does not depend on either.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org returned 403 to WebFetch. b4 mbox of the matched
thread has no stable@ discussion. UNVERIFIED: no independent
confirmation from lore.kernel.org/stable/.
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `bpf_jit_emit_insn()` (modified). Helpers used, not modified:
`bpf_get_reg64`, `bpf_put_reg64`, `bpf_get_reg32`, `bpf_put_reg32`,
`emit`.
**Step 5.2: TRACE CALLERS**
Record: `build_body()` in `arch/riscv/net/bpf_jit_core.c` calls
`bpf_jit_emit_insn()` for every instruction when a program is JIT-
compiled. That is the eBPF load/attach path (tracing, networking,
cgroup, seccomp, etc.), not init-only.
**Step 5.3: TRACE CALLEES**
Record: Emits RISC-V ALU (slli/srai/addi) and the existing stacked-
register get/put. No allocation, no locking.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: userspace bpf(2) / `BPF_PROG_LOAD` → verifier (accepts MOVSX
since 8100928c88148) → `bpf_int_jit_compile` → `build_body` →
`bpf_jit_emit_insn`. RISC-V selects `HAVE_EBPF_JIT if MMU`. JIT is used
when enabled; tests ran with `jited:1`. Reachable from program load.
Typically CAP_BPF/CAP_SYS_ADMIN; not a syzbot-style unprivileged UAF,
but verifier/JIT mismatch is still a sandbox correctness issue.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: RV64 already handled off 8/16/32 (694896ad3ca79). arm32:
fc832653fa0db then c6f48506ba30c. LoongArch had a later “Fix sign-
extension mov” (772cbe948fb07). Same bug class: MOV|X with nonzero off
must sign-extend.
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- Local tree: v7.3-rc4-27-gf0100363d8c37, `VERSION=7 PATCHLEVEL=3
SUBLEVEL=0 EXTRAVERSION=-rc4`.
- RV32 JIT file exists; MOVSX macros exist in `include/linux/filter.h`;
tests exist in `lib/test_bpf.c`.
- Commit c6a08afdfe3a8 *is* an ancestor of HEAD (landed in 7.3 via `bpf-
next-7.3`, merge 5a8cd539ac19f). Not in v7.2.
- Without this change, the 2020 MOV fallthrough is still the codegen for
MOVSX. The bug is in this lineage from 6.6 through 7.2.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean apply on this tree. Surrounding MOV cases and get/put
helpers match the patch. Expected difficulty: clean apply.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: This is the RV32 MOVSX fix. No earlier substitute on
bpf_jit_comp32.c. RV64 already had support. No competing fix.
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM**
Record: [arch/riscv BPF JIT] [IMPORTANT for RV32 + BPF users; PERIPHERAL
vs core mm/net — 32-bit RISC-V is a real but smaller population]
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active enough (atomics, arena, CFI, kfunc sign-extend) but the
MOV path itself was untouched since 2020. Long-standing gap, not a
brand-new subsystem.
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: WHO IS AFFECTED**
Record: RV32 kernels with eBPF JIT (HAVE_EBPF_JIT && MMU) running
programs that use CPU-v4 sign-extending moves (clang casts to
s8/s16/s32). Not universal; not staging.
**Step 8.2: TRIGGER CONDITIONS**
Record: Loading/attaching a BPF program that contains MOVSX, with JIT
on. Common for cpu v4 compiles. Privileged load in default configs. Not
a timing race. test_bpf reproduces it every run.
**Step 8.3: FAILURE MODE SEVERITY**
Record: [Wrong JIT results / verifier-vs-JIT mismatch] [HIGH]
- Not an oops/deadlock.
- JIT returns different register values than the interpreter and than
the verifier’s sign-extended ranges (test: expected 1, got 2).
- If the verifier pruned a bounds check on the assumption that MOVSX
ran, runtime can see a non-sign-extended value. That is BPF sandbox
incorrectness, not a cosmetic test fail.
**Step 8.4: RISK-BENEFIT RATIO**
Record: Benefit high for RV32+BPF (correct JIT, closes verifier
mismatch). Risk very low (32 lines, one switch, existing emit helpers,
test_bpf before/after in the message, RISC-V BPF reviewer Tested-by).
Ratio favors taking it.
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Concrete miscompilation: JIT runs and produces the wrong value
(`jited:1 ret 2 != 1`).
- BPF_MOVSX has been in the ISA/verifier/interpreter since ~6.6; RV32
JIT never honored `insn->off`.
- Interpreter is correct; only the JIT is wrong — classic “supported
opcode, wrong codegen.”
- 32-line, single-function, no new APIs.
- Reviewed and tested by Pu Lehui; applied by BPF maintainer.
- Independent of the other two series patches.
- Helpers and MOV cases exist in this tree since 5.6.
AGAINST:
- Subject/process treated it as bpf-next “Add support”; Fixes: tags were
deliberately removed in v3.
- RV32 is a smaller user base than RV64.
- Failure is wrong results, not a panic.
- Series patch 3/3 is a genuine feature (do not bundle it).
UNRESOLVED:
- Could not fetch lore.kernel.org/stable/ (HTTP 403). Thread mbox had no
stable discussion.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — slli/srai matches the ISA;
test_bpf #82–#86; reviewer Tested-by.
2. Fixes a real bug that affects users? **PASS** — JIT’d MOVSX is wrong
on RV32; userspace can load such programs.
3. Important issue? **PASS** — verifier/JIT mismatch on sign extension
is sandbox/correctness, not a style issue. Severity HIGH, not a dead-
code WARN.
4. Small and contained? **PASS** — +32 lines, one file, one function.
5. No new features or APIs? **PASS** — does not add a new opcode to BPF;
it compiles an opcode the verifier already accepts. (Title is “Add
support”; semantically it is fixing ignored `off`.)
6. Can apply to the local tree? **PASS** — file, helpers, and MOV cases
are here.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/build/docs exception. Ordinary
correctness fix.
**Step 9.4: DECISION**
This tree is 7.3-rc4: it has the RV32 JIT and BPF_MOVSX. The bug is
“MOV|X ignores off,” which is user-visible wrong BPF execution and a
verifier/JIT disagreement. The patch is small, obviously correct,
tested, and self-contained. bpf-next dropping Fixes: is process, not a
finding that the codegen was fine. It should be backported to this tree.
### What it solves for stable users
RV32 eBPF JIT compiled sign-extending moves as ordinary copies. Any
JIT’d program using BPF_MOVSX (cpu v4 / compiler casts) gets wrong
register values. That breaks test_bpf and can disagree with verifier
range tracking.
### Risk vs benefit
Benefit: correct JIT and closed verifier mismatch on a real ISA
instruction. Risk: very low, localized ALU emit.
### Concerns
Do not pull series 3/3 (atomics feature). 1/3 (SDIV/SMOD) is the same
miscompilation class but is not required for this patch. No backport
rework needed on this tree.
Verification:
- [Phase 1] Tags: Reviewed-by Pu Lehui, Link lore/bpf, SOB author +
Kartikeya; no Fixes/syzbot/Cc:stable
- [Phase 1] Body: test_bpf #82–#86 `jited:1 ret 2 != 1` before, PASS
after
- [Phase 2] Diff: +32 in `bpf_jit_emit_insn()`, two MOV|X cases,
slli/srai sign-extend
- [Phase 2] Confirmed `emit_alu_r64` BPF_MOV is lo/hi copy;
`emit_alu_r32` BPF_MOV is lo copy (pre-fix path)
- [Phase 3] blame: MOV fallthrough from 5f316b65e99f1 (v5.6); ISA
8100928c88148 (~6.6); RV64 694896ad3ca79
- [Phase 3] `git merge-base --is-ancestor c6a08afdfe3a8 HEAD` yes; not
ancestor of v7.2; is ancestor of v7.3-rc1
- [Phase 3] Series patches 2e0fa2389c50f / c6a08afdfe3a8 /
a1b37972efc0b; this one independent
- [Phase 4] `b4 dig -c c6a08afdfe3a8`: v4 2/3, msgid
20260714002451.4091139-3
- [Phase 4] `b4 dig -a`: v1–v4; v3 removed Fixes: and retitled
- [Phase 4] `b4 dig -m`: 7 messages; Pu Lehui R-b/T-b; no NAK; no stable
Cc
- [Phase 4] WebFetch lore: 403 — UNVERIFIED via HTTP; thread recovered
via b4 mbox
- [Phase 5] Caller: `build_body()` → every JIT’d insn; `HAVE_EBPF_JIT if
MMU`
- [Phase 5] Tests in lib/test_bpf.c ALU_MOVSX / ALU64_MOVSX
- [Phase 6] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37; `make
kernelversion` = 7.3.0-rc4
- [Phase 6] bpf_jit_comp32.c and BPF_MOVSX64_REG present; helpers from
original JIT
- [Phase 8] Failure: wrong JIT output / verifier mismatch, HIGH; not a
panic
- UNVERIFIED: stable@ mailing list archive (HTTP 403)
**YES**
arch/riscv/net/bpf_jit_comp32.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
index 89153946a4e46..39e2b0b907dc3 100644
--- a/arch/riscv/net/bpf_jit_comp32.c
+++ b/arch/riscv/net/bpf_jit_comp32.c
@@ -972,6 +972,24 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
switch (code) {
case BPF_ALU64 | BPF_MOV | BPF_X:
+ if (insn->off != 0) {
+ const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
+ const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
+
+ if (insn->off == 8) {
+ emit(rv_slli(lo(rd), lo(rs), 24), ctx);
+ emit(rv_srai(lo(rd), lo(rd), 24), ctx);
+ } else if (insn->off == 16) {
+ emit(rv_slli(lo(rd), lo(rs), 16), ctx);
+ emit(rv_srai(lo(rd), lo(rd), 16), ctx);
+ } else {
+ emit(rv_addi(lo(rd), lo(rs), 0), ctx);
+ }
+ emit(rv_srai(hi(rd), lo(rd), 31), ctx);
+ bpf_put_reg64(dst, rd, ctx);
+ break;
+ }
+ fallthrough;
case BPF_ALU64 | BPF_ADD | BPF_X:
case BPF_ALU64 | BPF_ADD | BPF_K:
@@ -1022,6 +1040,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
emit_zext64(dst, ctx);
break;
}
+ if (insn->off != 0) {
+ const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
+ const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
+
+ if (insn->off == 8) {
+ emit(rv_slli(lo(rd), lo(rs), 24), ctx);
+ emit(rv_srai(lo(rd), lo(rd), 24), ctx);
+ } else if (insn->off == 16) {
+ emit(rv_slli(lo(rd), lo(rs), 16), ctx);
+ emit(rv_srai(lo(rd), lo(rd), 16), ctx);
+ }
+ bpf_put_reg32(dst, rd, ctx);
+ break;
+ }
fallthrough;
case BPF_ALU | BPF_ADD | BPF_X:
--
2.53.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 6+ messages in thread