Thread (7 messages) 7 messages, 2 authors, 2d ago

[RFC v2 3/3] arm64: kprobes: Save and restore saved_irqflag in prev_kprobe

From: Pu Hu <hidden>
Date: 2026-07-09 14:22:31
Also in: lkml
Subsystem: arm64 port (aarch64 architecture), the rest · Maintainers: Catalin Marinas, Will Deacon, Linus Torvalds

From: Pu Hu <redacted>

When a kprobe is reentered from KPROBE_HIT_SS state (allowed by the
previous patch), setup_singlestep() for the nested kprobe calls
kprobes_save_local_irqflag(), overwriting kcb->saved_irqflag with the
currently masked DAIF value. The outer kprobe's original DAIF state is
lost.

When the nested kprobe completes, restore_previous_kprobe() brings back
the outer kprobe's kp and status, but saved_irqflag still contains the
nested kprobe's value. When the outer kprobe's single-step eventually
finishes, kprobes_restore_local_irqflag() applies the wrong DAIF mask,
leaving interrupts permanently disabled.

Fix this by extending struct prev_kprobe with a saved_irqflag field, and
saving/restoring it alongside kp and status. This ensures the outer
kprobe's original interrupt state is preserved across reentry.

Signed-off-by: Pu Hu <redacted>
Signed-off-by: Hongyan Xia <redacted>
---
 arch/arm64/include/asm/kprobes.h   |  6 ++++++
 arch/arm64/kernel/probes/kprobes.c | 15 +++++++++++++++
 2 files changed, 21 insertions(+)
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index f2782560647b..35ce2c94040e 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -26,6 +26,12 @@
 struct prev_kprobe {
 	struct kprobe *kp;
 	unsigned int status;
+
+	/*
+	 * The original DAIF state of the outer kprobe, saved here before
+	 * a nested kprobe overwrites kcb->saved_irqflag during reentry.
+	 */
+	unsigned long saved_irqflag;
 };
 
 /* per-cpu kprobe control block */
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index 2ca5916eca2f..4e0efad5caf2 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -174,12 +174,27 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
 {
 	kcb->prev_kprobe.kp = kprobe_running();
 	kcb->prev_kprobe.status = kcb->kprobe_status;
+
+	/*
+	 * Save the outer kprobe's original DAIF flags before the nested
+	 * kprobe calls kprobes_save_local_irqflag() and overwrites
+	 * kcb->saved_irqflag. Without this, the outer kprobe will restore
+	 * the wrong DAIF state and leave interrupts permanently masked.
+	 */
+	kcb->prev_kprobe.saved_irqflag = kcb->saved_irqflag;
 }
 
 static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
 {
 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
 	kcb->kprobe_status = kcb->prev_kprobe.status;
+
+	/*
+	 * Restore the outer kprobe's saved_irqflag so that when its
+	 * single-step completes, kprobes_restore_local_irqflag() uses
+	 * the correct original DAIF value.
+	 */
+	kcb->saved_irqflag = kcb->prev_kprobe.saved_irqflag;
 }
 
 static void __kprobes set_current_kprobe(struct kprobe *p)
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help