From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Pu Hu <hupu@transsion.com>
Cc: "ada.coupriediaz@arm.com" <ada.coupriediaz@arm.com>,
"catalin.marinas@arm.com" <catalin.marinas@arm.com>,
"davem@davemloft.net" <davem@davemloft.net>,
Hongyan Xia <hongyan.xia@transsion.com>,
Jiazi Li <jiazi.li@transsion.com>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"linux-trace-kernel@vger.kernel.org"
<linux-trace-kernel@vger.kernel.org>,
"naveen@kernel.org" <naveen@kernel.org>,
"will@kernel.org" <will@kernel.org>,
"yang@os.amperecomputing.com" <yang@os.amperecomputing.com>
Subject: Re: [RFC v3 2/2] arm64: kprobes: Allow reentering kprobes while single-stepping
Date: Fri, 10 Jul 2026 18:38:57 +0900 [thread overview]
Message-ID: <20260710183857.176dc60026ea9fcbe4984b1d@kernel.org> (raw)
In-Reply-To: <20260710063242.228714-3-hupu@transsion.com>
On Fri, 10 Jul 2026 06:32:55 +0000
Pu Hu <hupu@transsion.com> wrote:
> From: Pu Hu <hupu@transsion.com>
>
> A kprobe can be hit while another kprobe is in KPROBE_HIT_SS state. This
> can happen when tracing or perf code runs from the debug exception path
> while the first kprobe is preparing or executing its out-of-line
> single-step instruction.
>
> Currently arm64 treats a kprobe hit in KPROBE_HIT_SS as unrecoverable,
> the same as a hit in KPROBE_REENTER. This is too strict. A hit in
> KPROBE_HIT_SS is still a one-level reentry and can be handled by saving
> the current kprobe state and setting up single-step for the new probe,
> just like reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
>
> The truly unrecoverable case is hitting another kprobe while already in
> KPROBE_REENTER, because the reentry save area has already been consumed.
>
> Move KPROBE_HIT_SS to the recoverable reentry cases and leave
> KPROBE_REENTER as the unrecoverable nested reentry case.
>
> This change also requires saving saved_irqflag in struct prev_kprobe.
> When a nested kprobe calls kprobes_save_local_irqflag(), it overwrites
> kcb->saved_irqflag with the currently masked DAIF value, losing the
> outer kprobe's original DAIF state. Without this fix, when the outer
> kprobe's single-step finishes, kprobes_restore_local_irqflag() applies
> the wrong DAIF mask and leaves interrupts permanently disabled.
>
> Extend struct prev_kprobe with a saved_irqflag field and save/restore it
> alongside kp and status. This ensures the outer kprobe's original
> interrupt state is preserved across reentry.
>
> This mirrors the x86 fix in commit 6a5022a56ac3
> ("kprobes/x86: Allow to handle reentered kprobe on single-stepping").
>
OK, this looks good to me.
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
for this series.
Will, Catalin, can you pick this series?
Thanks!
> Signed-off-by: Pu Hu <hupu@transsion.com>
> Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
> ---
> arch/arm64/include/asm/kprobes.h | 6 ++++++
> arch/arm64/kernel/probes/kprobes.c | 23 ++++++++++++++++++++++-
> 2 files changed, 28 insertions(+), 1 deletion(-)
>
> 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 798e4b091d1a..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)
> @@ -240,10 +255,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
> switch (kcb->kprobe_status) {
> case KPROBE_HIT_SSDONE:
> case KPROBE_HIT_ACTIVE:
> + case KPROBE_HIT_SS:
> + /*
> + * A probe can be hit while another kprobe is preparing or
> + * executing its XOL single-step instruction. This is still a
> + * recoverable one-level reentry, so handle it in the same way as
> + * reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
> + */
> kprobes_inc_nmissed_count(p);
> setup_singlestep(p, regs, kcb, 1);
> break;
> - case KPROBE_HIT_SS:
> case KPROBE_REENTER:
> pr_warn("Failed to recover from reentered kprobes.\n");
> dump_kprobe(p);
> --
> 2.43.0
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
WARNING: multiple messages have this Message-ID (diff)
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Pu Hu <hupu@transsion.com>
Cc: Hongyan Xia <hongyan.xia@transsion.com>,
Jiazi Li <jiazi.li@transsion.com>,
"catalin.marinas@arm.com" <catalin.marinas@arm.com>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"naveen@kernel.org" <naveen@kernel.org>,
"yang@os.amperecomputing.com" <yang@os.amperecomputing.com>,
"will@kernel.org" <will@kernel.org>,
"davem@davemloft.net" <davem@davemloft.net>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>,
"linux-trace-kernel@vger.kernel.org"
<linux-trace-kernel@vger.kernel.org>
Subject: Re: [RFC v3 2/2] arm64: kprobes: Allow reentering kprobes while single-stepping
Date: Fri, 10 Jul 2026 18:38:57 +0900 [thread overview]
Message-ID: <20260710183857.176dc60026ea9fcbe4984b1d@kernel.org> (raw)
In-Reply-To: <20260710063242.228714-3-hupu@transsion.com>
On Fri, 10 Jul 2026 06:32:55 +0000
Pu Hu <hupu@transsion.com> wrote:
> From: Pu Hu <hupu@transsion.com>
>
> A kprobe can be hit while another kprobe is in KPROBE_HIT_SS state. This
> can happen when tracing or perf code runs from the debug exception path
> while the first kprobe is preparing or executing its out-of-line
> single-step instruction.
>
> Currently arm64 treats a kprobe hit in KPROBE_HIT_SS as unrecoverable,
> the same as a hit in KPROBE_REENTER. This is too strict. A hit in
> KPROBE_HIT_SS is still a one-level reentry and can be handled by saving
> the current kprobe state and setting up single-step for the new probe,
> just like reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
>
> The truly unrecoverable case is hitting another kprobe while already in
> KPROBE_REENTER, because the reentry save area has already been consumed.
>
> Move KPROBE_HIT_SS to the recoverable reentry cases and leave
> KPROBE_REENTER as the unrecoverable nested reentry case.
>
> This change also requires saving saved_irqflag in struct prev_kprobe.
> When a nested kprobe calls kprobes_save_local_irqflag(), it overwrites
> kcb->saved_irqflag with the currently masked DAIF value, losing the
> outer kprobe's original DAIF state. Without this fix, when the outer
> kprobe's single-step finishes, kprobes_restore_local_irqflag() applies
> the wrong DAIF mask and leaves interrupts permanently disabled.
>
> Extend struct prev_kprobe with a saved_irqflag field and save/restore it
> alongside kp and status. This ensures the outer kprobe's original
> interrupt state is preserved across reentry.
>
> This mirrors the x86 fix in commit 6a5022a56ac3
> ("kprobes/x86: Allow to handle reentered kprobe on single-stepping").
>
OK, this looks good to me.
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
for this series.
Will, Catalin, can you pick this series?
Thanks!
> Signed-off-by: Pu Hu <hupu@transsion.com>
> Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
> ---
> arch/arm64/include/asm/kprobes.h | 6 ++++++
> arch/arm64/kernel/probes/kprobes.c | 23 ++++++++++++++++++++++-
> 2 files changed, 28 insertions(+), 1 deletion(-)
>
> 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 798e4b091d1a..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)
> @@ -240,10 +255,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
> switch (kcb->kprobe_status) {
> case KPROBE_HIT_SSDONE:
> case KPROBE_HIT_ACTIVE:
> + case KPROBE_HIT_SS:
> + /*
> + * A probe can be hit while another kprobe is preparing or
> + * executing its XOL single-step instruction. This is still a
> + * recoverable one-level reentry, so handle it in the same way as
> + * reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
> + */
> kprobes_inc_nmissed_count(p);
> setup_singlestep(p, regs, kcb, 1);
> break;
> - case KPROBE_HIT_SS:
> case KPROBE_REENTER:
> pr_warn("Failed to recover from reentered kprobes.\n");
> dump_kprobe(p);
> --
> 2.43.0
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
next prev parent reply other threads:[~2026-07-10 9:39 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 6:32 [RFC v3 0/2] rm64: kprobes: Fix single-step fault and reentry handling Pu Hu
2026-07-10 6:32 ` Pu Hu
2026-07-10 6:32 ` [RFC v3 1/2] arm64: kprobes: Only handle faults originating from XOL slot Pu Hu
2026-07-10 6:32 ` [RFC v3 2/2] arm64: kprobes: Allow reentering kprobes while single-stepping Pu Hu
2026-07-10 9:38 ` Masami Hiramatsu [this message]
2026-07-10 9:38 ` Masami Hiramatsu
2026-07-15 13:56 ` Pu Hu
2026-07-15 13:56 ` Pu Hu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260710183857.176dc60026ea9fcbe4984b1d@kernel.org \
--to=mhiramat@kernel.org \
--cc=ada.coupriediaz@arm.com \
--cc=catalin.marinas@arm.com \
--cc=davem@davemloft.net \
--cc=hongyan.xia@transsion.com \
--cc=hupu@transsion.com \
--cc=jiazi.li@transsion.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=naveen@kernel.org \
--cc=will@kernel.org \
--cc=yang@os.amperecomputing.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.