Linux-RISC-V Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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

end of thread, other threads:[~2026-10-19 14:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [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 ` [PATCH AUTOSEL 6.18-6.6] riscv: kprobes: Prevent probes in breakpoint handlers Sasha Levin
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 ` [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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox