Linux Perf Users
 help / color / mirror / Atom feed
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: sashiko-reviews@lists.linux.dev
Cc: sashiko-bot@kernel.org, linux-trace-kernel@vger.kernel.org,
	linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v13 02/12] x86/hw_breakpoints: Make DR7 updates NMI safe
Date: Sun, 30 Aug 2026 14:35:09 +0900	[thread overview]
Message-ID: <20260830143509.12601f973b9eb2d5d716d489@kernel.org> (raw)
In-Reply-To: <20260822094107.349031F00A3A@smtp.kernel.org>

On Sat, 22 Aug 2026 09:41:06 +0000
sashiko-bot@kernel.org wrote:

> > -static __always_inline void local_db_restore(unsigned long dr7)
> > +static __always_inline void local_db_restore(unsigned long dr7,
> > +					     unsigned int dr7_seq)
> >  {
> > +	unsigned int seq;
> > +
> >  	/*
> >  	 * Ensure the compiler doesn't raise this statement into
> >  	 * the critical section; enabling breakpoints early would
> >  	 * not be good.
> >  	 */
> >  	barrier();
> > -	if (dr7)
> > +
> > +	do {
> > +		seq = this_cpu_read(cpu_dr7_seq);
> > +		if (seq == dr7_seq) {
> > +			if (!dr7)
> > +				return;
> > +		} else {
> > +			dr7 = this_cpu_read(cpu_dr7);
> > +			if (!dr7)
> > +				dr7 = DR7_FIXED_1;
> > +		}
> > +
> >  		set_debugreg(dr7, 7);
> > +		barrier();
> > +	} while (unlikely(seq != this_cpu_read(cpu_dr7_seq)));
> >  }
> 
> [Severity: High]
> If KVM intentionally clears the hardware DR7 state to isolate the guest from
> host breakpoints before VMENTER without modifying the host's cpu_dr7 shadow
> state:
> 
> arch/x86/kvm/x86.c:vcpu_enter_guest() {
>     ...
>     if (unlikely(vcpu->arch.switch_db_regs &&
>                  !(vcpu->arch.switch_db_regs & KVM_DEBUGREG_AUTO_SWITCH))) {
>         set_debugreg(DR7_FIXED_1, 7);
>     ...
>     } else if (unlikely(hw_breakpoint_active())) {
>         set_debugreg(DR7_FIXED_1, 7);
>     }
>     ...
> }
> 
> Could an NMI firing shortly after this permanently undo this isolation
> upon return?
> 
> If an NMI (such as a perf event) fires before vmlaunch/vmresume, exc_nmi
> calls local_db_save, saving dr7=0. If the NMI modifies a breakpoint,
> cpu_dr7_seq increments.
> 
> When exc_nmi calls local_db_restore, the sequence mismatch causes it to
> discard the saved dr7=0 state and instead unconditionally restore the host's
> active breakpoints (this_cpu_read(cpu_dr7)) to the hardware DR7. This could
> leak host hardware breakpoints into a KVM guest and cause unexpected #DB
> exceptions.

OK, this seems only happen when KGDB/KDB sets the watchpoint from
NMI context (right after KVM disables dr7 for transient to guest).
We can avoid this by early returning if dr7 == 0 in local_db_restore().
(But..., if user intensively set the dr7 in that timing, it will be
ignored.)

> 
> [ ... ]
> > diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
> > index 9bba1e2f03af7..8dba9cd04bfa5 100644
> > --- a/arch/x86/kernel/cpu/mce/core.c
> > +++ b/arch/x86/kernel/cpu/mce/core.c
> [ ... ]
> > @@ -2139,20 +2139,22 @@ static __always_inline void exc_machine_check_user(struct pt_regs *regs)
> >  DEFINE_IDTENTRY_MCE(exc_machine_check)
> >  {
> >  	unsigned long dr7;
> > +	unsigned int dr7_seq;
> >  
> > -	dr7 = local_db_save();
> > +	local_db_save(&dr7, &dr7_seq);
> >  	exc_machine_check_kernel(regs);
> > -	local_db_restore(dr7);
> > +	local_db_restore(dr7, dr7_seq);
> >  }
> >  
> >  /* The user mode variant. */
> >  DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
> >  {
> >  	unsigned long dr7;
> > +	unsigned int dr7_seq;
> >  
> > -	dr7 = local_db_save();
> > +	local_db_save(&dr7, &dr7_seq);
> >  	exc_machine_check_user(regs);
> > -	local_db_restore(dr7);
> > +	local_db_restore(dr7, dr7_seq);
> >  }
> 
> [Severity: High]
> This is a pre-existing issue, but does task migration during user-mode
> machine check exceptions corrupt hardware debug registers on the new CPU?
> 
> exc_machine_check_user invokes irqentry_exit_to_user_mode, which processes
> pending thread work (like TIF_NEED_RESCHED), enabling interrupts and allowing
> the task to be scheduled out and migrate to a new CPU:
> 
> CPU1
> exc_machine_check()
>     local_db_save(&dr7, &dr7_seq);
>     exc_machine_check_user(regs)
>         irqentry_exit_to_user_mode(regs)
>             // Task migrates to CPU2
> 
> CPU2
>     local_db_restore(dr7, dr7_seq);
> 
> When it resumes on the new CPU, local_db_restore is executed with the dr7
> and dr7_seq values saved from the old CPU. If the new CPU's cpu_dr7_seq
> matches the old CPU's saved dr7_seq, it would erroneously write the old CPU's
> hardware DR7 state to the new CPU's hardware DR7 register. Could this cause
> spurious #DB exceptions or break hardware breakpoints on the new CPU?

OK, this is another problem to be fixed in a bugfix patch. We should do
local_db_save/restore() inside exc_machine_check_user() before calling
irqentry_exit_to_user_mode().

Thank you,

-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

  reply	other threads:[~2026-08-30  5:35 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-22  9:22 [PATCH v13 00/12] tracing: wprobe: x86: Add wprobe for watchpoint Masami Hiramatsu (Google)
2026-08-22  9:22 ` [PATCH v13 01/12] kprobes: Protect kprobe_blacklist with RCU Masami Hiramatsu (Google)
2026-08-22  9:31   ` sashiko-bot
2026-08-22  9:22 ` [PATCH v13 02/12] x86/hw_breakpoints: Make DR7 updates NMI safe Masami Hiramatsu (Google)
2026-08-22  9:41   ` sashiko-bot
2026-08-30  5:35     ` Masami Hiramatsu [this message]
2026-08-22  9:22 ` [PATCH v13 03/12] x86/hw_breakpoints: Add arch_modify_local_hw_breakpoint_addr() API Masami Hiramatsu (Google)
2026-08-22  9:33   ` sashiko-bot
2026-08-22  9:23 ` [PATCH v13 04/12] HWBP: Add modify_local_hw_breakpoint_addr() API Masami Hiramatsu (Google)
2026-08-22  9:33   ` sashiko-bot
2026-08-22  9:24 ` [PATCH v13 05/12] tracing/wprobe: Add wprobe (watchpoint probe) trace event support Masami Hiramatsu (Google)
2026-08-22  9:49   ` sashiko-bot
2026-08-30  5:35     ` Masami Hiramatsu
2026-08-22  9:24 ` [PATCH v13 06/12] x86: hw_breakpoint: Add a kconfig to clarify when a breakpoint fires Masami Hiramatsu (Google)
2026-08-22  9:31   ` sashiko-bot
2026-08-22  9:24 ` [PATCH v13 07/12] selftests: tracing: Add a basic testcase for wprobe Masami Hiramatsu (Google)
2026-08-22  9:36   ` sashiko-bot
2026-08-30  5:35     ` Masami Hiramatsu
2026-08-22  9:24 ` [PATCH v13 08/12] selftests: tracing: Add syntax " Masami Hiramatsu (Google)
2026-08-22  9:35   ` sashiko-bot
2026-08-30  5:35     ` Masami Hiramatsu
2026-08-22  9:24 ` [PATCH v13 09/12] tracing/wprobe: Add set_wprobe and clear_wprobe event triggers Masami Hiramatsu (Google)
2026-08-22  9:42   ` sashiko-bot
2026-08-30  5:35     ` Masami Hiramatsu
2026-08-22  9:25 ` [PATCH v13 10/12] selftests: ftrace: Add wprobe trigger testcase Masami Hiramatsu (Google)
2026-08-22  9:39   ` sashiko-bot
2026-08-30  5:36     ` Masami Hiramatsu
2026-08-22  9:25 ` [PATCH v13 11/12] tracing/wprobe: Support BTF typecast in fetchargs Masami Hiramatsu (Google)
2026-08-22  9:40   ` sashiko-bot
2026-08-22  9:25 ` [PATCH v13 12/12] tracing/wprobe: Support BTF struct offset resolution in set_wprobe trigger Masami Hiramatsu (Google)
2026-08-22  9:51   ` sashiko-bot
2026-08-30  5:36     ` Masami Hiramatsu

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=20260830143509.12601f973b9eb2d5d716d489@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox