From 2820d227ad4ee70805d693d698437cc3e88d6c3d Mon Sep 17 00:00:00 2001 From: Pu Lehui Date: Sun, 2 Aug 2026 09:49:29 +0000 Subject: [PATCH 1/3] riscv: ftrace: Fix ftrace_modify_call failure on kprobed functions We are frequently hitting the following splat during the riscv bpf selftests: 00000000026dc75a: expected (7c3ff297) but got (00100073) ------------[ ftrace bug ]------------ ftrace failed to modify [] bpf_kfunc_common_test+0x4/0x20 [bpf_testmod] actual: e7:82:c2:ce Updating ftrace call site to call a different ftrace function ftrace record flags: 80100002 (2) expected tramp: ffffffff80043904 ------------[ cut here ]------------ WARNING: kernel/trace/ftrace.c:2278 at ftrace_bug+0x46e/0x4b0, CPU#1: test_progs/98 ... [] ftrace_bug+0x46e/0x4b0 [] ftrace_replace_code+0x16e/0x170 [] ftrace_modify_all_code+0x12e/0x1b8 [] arch_ftrace_update_code+0x14/0x28 [] ftrace_startup+0x14c/0x2a0 [] ftrace_startup_subops+0x584/0x1050 [] register_ftrace_graph+0x4e6/0x1018 [] register_fprobe_ips+0xc66/0x12f8 [] bpf_kprobe_multi_link_attach+0x5d8/0xe68 [] __sys_bpf+0x3d5a/0x47f0 [] __riscv_sys_bpf+0xae/0x168 [] syscall_handler+0x60/0x100 [] do_trap_ecall_u+0x174/0x208 [] handle_exception+0x16c/0x178 After debugging, it can be triggered by similar commands below: ``` echo do_nanosleep > set_ftrace_filter echo function > current_tracer echo 'p do_nanosleep' > kprobe_events echo 1 > events/kprobes/enable echo 'f do_nanosleep' > dynamic_events echo 1 > events/fprobes/enable ``` The reason is that attaching a kprobe to an ftrace-traced function entry replaces its initial auipc insn with ebreak. When ftrace_modify_call later runs, it expects auipc insn, so verification fails and triggers ftrace_bug. The expected auipc logic remains conceptually unchanged, and kprobe single-stepping ensures normal execution. Therefore, if the first insn is ebreak, bypassing the check to continue patching the jalr insn is safe and avoids ftrace failures. Fixes: b2137c3b6d7a ("riscv: ftrace: prepare ftrace for atomic code patching") Signed-off-by: Pu Lehui Link: https://patch.msgid.link/20260802094929.3978390-1-pulehui@huaweicloud.com [pjw@kernel.org: fixed reproducer in commit message] Signed-off-by: Paul Walmsley --- arch/riscv/kernel/ftrace.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index b430edfb83f4..be8b68514417 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef CONFIG_DYNAMIC_FTRACE void ftrace_arch_code_modify_prepare(void) @@ -63,7 +64,9 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE)) return -EFAULT; - if (replaced[0] != call[0]) { + /* Bypass the check if the auipc insn is a kprobe breakpoint */ + if (replaced[0] != call[0] && + !(riscv_insn_is_ebreak(replaced[0]) || riscv_insn_is_c_ebreak(replaced[0]))) { pr_err("%p: expected (%08x) but got (%08x)\n", (void *)source, call[0], replaced[0]); return -EINVAL; From 994dad686e755477e2b2700cca4e6e1a90a58bdc Mon Sep 17 00:00:00 2001 From: Rui Qi Date: Tue, 21 Jul 2026 23:05:09 +0800 Subject: [PATCH 2/3] riscv: hwprobe: Register unaligned probes before usermode The hwprobe vDSO data is populated by the first riscv_hwprobe syscall. Some values, such as MISALIGNED_VECTOR_PERF, may depend on the async vector unaligned access speed probe registered by check_unaligned_access_all_cpus(). That initcall currently runs at late_initcall level. However, rootfs_initcall enables usermode helpers before late initcalls run, so an early helper can execute userspace and call riscv_hwprobe first. In that case complete_hwprobe_vdso_data() consumes the initial pending_boot_probes reference, populates the vDSO cache, and marks it ready before the later async probe is registered. The eventual probe result then cannot update the already-ready cache. Move check_unaligned_access_all_cpus() to fs_initcall_sync. This still runs after clocksource_done_booting(), so the ktime_get_mono_fast_ns() benchmark uses a stable clocksource, but it runs before rootfs_initcall enables usermode helpers. Any async hwprobe probe is therefore registered before userspace can trigger the one-time vDSO cache population. Cc: stable@vger.kernel.org Fixes: 6455c6c11827 ("riscv: Clean up & optimize unaligned scalar access probe") Signed-off-by: Rui Qi Reviewed-by: Nam Cao Link: https://patch.msgid.link/20260721150511.1607105-1-qirui.001@bytedance.com Signed-off-by: Paul Walmsley --- arch/riscv/kernel/unaligned_access_speed.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c index 5a5aa22124e7..36201613d2ca 100644 --- a/arch/riscv/kernel/unaligned_access_speed.c +++ b/arch/riscv/kernel/unaligned_access_speed.c @@ -411,4 +411,10 @@ static int __init check_unaligned_access_all_cpus(void) return 0; } -late_initcall(check_unaligned_access_all_cpus); +/* + * Run after clocksource_done_booting() so measure_cycles() uses a stable + * clocksource, but before rootfs_initcall() enables usermode helpers. Those + * helpers can reach hwprobe and populate the vDSO cache, so async hwprobe + * probes must be registered first. + */ +fs_initcall_sync(check_unaligned_access_all_cpus); From 5d588c684833e678a0008eb69c33190f01a65f4b Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 13 Apr 2026 01:07:38 +0000 Subject: [PATCH 3/3] riscv: lib: Fix ZBB strnlen reading past count boundary The ZBB-optimized strnlen loop loads one word ahead before checking the aligned boundary: REG_L t1, SZREG(t0) // load next word addi t0, t0, SZREG // advance orc.b t1, t1 bgeu t0, t4, 4f // boundary check AFTER load where t4 = (s + count) & -SZREG. When s is aligned and count is a multiple of SZREG, t4 equals s + count and the loop loads a full word starting at exactly s + count. If s + count falls on a page boundary with the next page unmapped, this faults. Fix by computing the aligned boundary from the last valid byte (s + count - 1) instead of s + count. This makes the loop stop at the word containing the last valid byte rather than potentially loading the word after it. The count == 0 case is already handled by the beqz early exit. Also add a pre-loop guard (bgeu t0, t4) for the case where all valid bytes fit within the first word. With the adjusted boundary, t4 can equal t0, and entering the loop with stale register state from the first-word processing would produce incorrect results. The final minu clamp ensures the result is still correct when the last loaded word extends past s + count - 1 within the same aligned word. Fixes: 5ba15d419fab ("riscv: lib: add strnlen() implementation") Signed-off-by: Michael Neuling Assisted-by: Claude Opus4.6 High Thinking Link: https://patch.msgid.link/20260413010738.1622423-1-mikey@neuling.org Signed-off-by: Paul Walmsley --- arch/riscv/lib/strnlen.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/riscv/lib/strnlen.S b/arch/riscv/lib/strnlen.S index 53afa7b5b314..a8911605c248 100644 --- a/arch/riscv/lib/strnlen.S +++ b/arch/riscv/lib/strnlen.S @@ -83,8 +83,13 @@ strnlen_zbb: sub t3, t3, t2 slli t2, t2, 3 - /* Aligned boundary. */ + /* + * Aligned boundary. Use the address of the last valid byte + * (s + count - 1) to avoid loading a word past the count + * boundary in the loop below. count == 0 is handled above. + */ add t4, a0, a1 + addi t4, t4, -1 andi t4, t4, -SZREG /* Get the first word. */ @@ -120,6 +125,9 @@ strnlen_zbb: bgtu t3, a0, 2f + /* All remaining bytes are in the first word, no loop needed. */ + bgeu t0, t4, 2f + /* Prepare for the word comparison loop. */ addi t2, t0, SZREG li t3, -1