[PATCH v1 4/4] LoongArch: kprobes: Fix handling of fatal unrecoverable recursions

From: Tiezhu Yang

Date: Tue May 12 2026 - 04:21:02 EST


KPROBE_HIT_SS and KPROBE_REENTER are two types of fatal recursions
that can not be safely recovered in kprobes.

KPROBE_HIT_SS means that a kprobe is hit during single-stepping.
At this point, the architecture-specific single-step context is
already active. Nested single-stepping would corrupt the state,
as the kprobe control block (kcb) and hardware registers cannot
safely store multiple levels of stepping state.

KPROBE_REENTER means that a third-level recursion occurs when a
probe is hit while the system is already handling a nested probe
(second-level). The kcb only provides a single slot (prev_kprobe)
to backup the state. When a third probe is hit, there is no more
space to save the state without corrupting the first-level backup.

Kprobes work by replacing instructions with breakpoints. In order
to execute the original instruction and continue, it must be moved
to a temporary "single-step" slot. Since there is no backup space
left to set up this slot safely, the CPU would be forced to return
to the same original breakpoint address, triggering an endless loop.

Currently, the code only prints a warning and returns. This leads
to an infinite re-entry loop as the CPU repeatedly hits the same
trap and a "stuck" CPU core because preemption was disabled at the
start of the handler and never re-enabled in this early return path.

Fix the logic by:
1. Merging KPROBE_HIT_SS and KPROBE_REENTER cases, as both represent
fatal recursions that cannot be safely recovered.
2. Balancing the preemption count with preempt_enable_no_resched() to
maintain preemption balance before the system halts.
3. Replacing WARN_ON_ONCE() with BUG() to terminate the system. This
aligns LoongArch with other architectures (x86, arm64, riscv) and
prevents stack overflow while providing diagnostic information.

Fixes: 6d4cc40fb5f5 ("LoongArch: Add kprobes support")
Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx>
---
arch/loongarch/kernel/kprobes.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/loongarch/kernel/kprobes.c b/arch/loongarch/kernel/kprobes.c
index 8e1b7a87c897..e6395a9dbaec 100644
--- a/arch/loongarch/kernel/kprobes.c
+++ b/arch/loongarch/kernel/kprobes.c
@@ -186,16 +186,17 @@ static bool reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
switch (kcb->kprobe_status) {
- case KPROBE_HIT_SS:
case KPROBE_HIT_SSDONE:
case KPROBE_HIT_ACTIVE:
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs, kcb, 1);
break;
+ case KPROBE_HIT_SS:
case KPROBE_REENTER:
+ preempt_enable_no_resched();
pr_warn("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
- WARN_ON_ONCE(1);
+ BUG();
break;
default:
WARN_ON(1);
--
2.42.0