Skip to content

Commit 7b56fbd

Browse files
committed
Merge tag 'x86-urgent-2020-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Thomas Gleixner: "Three fixes all related to #DB: - Handle the BTF bit correctly so it doesn't get lost due to a kernel #DB - Only clear and set the virtual DR6 value used by ptrace on user space triggered #DB. A kernel #DB must leave it alone to ensure data consistency for ptrace. - Make the bitmasking of the virtual DR6 storage correct so it does not lose DR_STEP" * tag 'x86-urgent-2020-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/debug: Fix DR_STEP vs ptrace_get_debugreg(6) x86/debug: Only clear/set ->virtual_dr6 for userspace #DB x86/debug: Fix BTF handling
2 parents 4312e0e + cb05143 commit 7b56fbd

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

arch/x86/kernel/traps.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -793,19 +793,6 @@ static __always_inline unsigned long debug_read_clear_dr6(void)
793793
set_debugreg(DR6_RESERVED, 6);
794794
dr6 ^= DR6_RESERVED; /* Flip to positive polarity */
795795

796-
/*
797-
* Clear the virtual DR6 value, ptrace routines will set bits here for
798-
* things we want signals for.
799-
*/
800-
current->thread.virtual_dr6 = 0;
801-
802-
/*
803-
* The SDM says "The processor clears the BTF flag when it
804-
* generates a debug exception." Clear TIF_BLOCKSTEP to keep
805-
* TIF_BLOCKSTEP in sync with the hardware BTF flag.
806-
*/
807-
clear_thread_flag(TIF_BLOCKSTEP);
808-
809796
return dr6;
810797
}
811798

@@ -873,6 +860,20 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
873860
*/
874861
WARN_ON_ONCE(user_mode(regs));
875862

863+
if (test_thread_flag(TIF_BLOCKSTEP)) {
864+
/*
865+
* The SDM says "The processor clears the BTF flag when it
866+
* generates a debug exception." but PTRACE_BLOCKSTEP requested
867+
* it for userspace, but we just took a kernel #DB, so re-set
868+
* BTF.
869+
*/
870+
unsigned long debugctl;
871+
872+
rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
873+
debugctl |= DEBUGCTLMSR_BTF;
874+
wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
875+
}
876+
876877
/*
877878
* Catch SYSENTER with TF set and clear DR_STEP. If this hit a
878879
* watchpoint at the same time then that will still be handled.
@@ -935,6 +936,22 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
935936
irqentry_enter_from_user_mode(regs);
936937
instrumentation_begin();
937938

939+
/*
940+
* Start the virtual/ptrace DR6 value with just the DR_STEP mask
941+
* of the real DR6. ptrace_triggered() will set the DR_TRAPn bits.
942+
*
943+
* Userspace expects DR_STEP to be visible in ptrace_get_debugreg(6)
944+
* even if it is not the result of PTRACE_SINGLESTEP.
945+
*/
946+
current->thread.virtual_dr6 = (dr6 & DR_STEP);
947+
948+
/*
949+
* The SDM says "The processor clears the BTF flag when it
950+
* generates a debug exception." Clear TIF_BLOCKSTEP to keep
951+
* TIF_BLOCKSTEP in sync with the hardware BTF flag.
952+
*/
953+
clear_thread_flag(TIF_BLOCKSTEP);
954+
938955
/*
939956
* If dr6 has no reason to give us about the origin of this trap,
940957
* then it's very likely the result of an icebp/int01 trap.

0 commit comments

Comments
 (0)