Skip to content

Commit

Permalink
x86/nmi: Protect NMI entry against instrumentation
Browse files Browse the repository at this point in the history
Mark all functions in the fragile code parts noinstr or force inlining so
they can't be instrumented.

Also make the hardware latency tracer invocation explicit outside of
non-instrumentable section.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Andy Lutomirski <luto@kernel.org>
Link: https://lkml.kernel.org/r/20200505135314.716186134@linutronix.de
  • Loading branch information
Thomas Gleixner committed Jun 11, 2020
1 parent 6271fef commit f051f69
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 14 deletions.
8 changes: 4 additions & 4 deletions arch/x86/include/asm/desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ static inline void native_load_gdt(const struct desc_ptr *dtr)
asm volatile("lgdt %0"::"m" (*dtr));
}

static inline void native_load_idt(const struct desc_ptr *dtr)
static __always_inline void native_load_idt(const struct desc_ptr *dtr)
{
asm volatile("lidt %0"::"m" (*dtr));
}
Expand Down Expand Up @@ -392,15 +392,15 @@ extern unsigned long system_vectors[];

#ifdef CONFIG_X86_64
DECLARE_PER_CPU(u32, debug_idt_ctr);
static inline bool is_debug_idt_enabled(void)
static __always_inline bool is_debug_idt_enabled(void)
{
if (this_cpu_read(debug_idt_ctr))
return true;

return false;
}

static inline void load_debug_idt(void)
static __always_inline void load_debug_idt(void)
{
load_idt((const struct desc_ptr *)&debug_idt_descr);
}
Expand All @@ -422,7 +422,7 @@ static inline void load_debug_idt(void)
* that doesn't need to disable interrupts, as nothing should be
* bothering the CPU then.
*/
static inline void load_current_idt(void)
static __always_inline void load_current_idt(void)
{
if (is_debug_idt_enabled())
load_debug_idt();
Expand Down
6 changes: 2 additions & 4 deletions arch/x86/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1709,21 +1709,19 @@ void syscall_init(void)
DEFINE_PER_CPU(int, debug_stack_usage);
DEFINE_PER_CPU(u32, debug_idt_ctr);

void debug_stack_set_zero(void)
noinstr void debug_stack_set_zero(void)
{
this_cpu_inc(debug_idt_ctr);
load_current_idt();
}
NOKPROBE_SYMBOL(debug_stack_set_zero);

void debug_stack_reset(void)
noinstr void debug_stack_reset(void)
{
if (WARN_ON(!this_cpu_read(debug_idt_ctr)))
return;
if (this_cpu_dec_return(debug_idt_ctr) == 0)
load_current_idt();
}
NOKPROBE_SYMBOL(debug_stack_reset);

#else /* CONFIG_X86_64 */

Expand Down
15 changes: 9 additions & 6 deletions arch/x86/kernel/nmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ NOKPROBE_SYMBOL(unknown_nmi_error);
static DEFINE_PER_CPU(bool, swallow_nmi);
static DEFINE_PER_CPU(unsigned long, last_nmi_rip);

static void default_do_nmi(struct pt_regs *regs)
static noinstr void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
int handled;
Expand All @@ -329,6 +329,8 @@ static void default_do_nmi(struct pt_regs *regs)

__this_cpu_write(last_nmi_rip, regs->ip);

instrumentation_begin();

handled = nmi_handle(NMI_LOCAL, regs);
__this_cpu_add(nmi_stats.normal, handled);
if (handled) {
Expand All @@ -342,7 +344,7 @@ static void default_do_nmi(struct pt_regs *regs)
*/
if (handled > 1)
__this_cpu_write(swallow_nmi, true);
return;
goto out;
}

/*
Expand Down Expand Up @@ -374,7 +376,7 @@ static void default_do_nmi(struct pt_regs *regs)
#endif
__this_cpu_add(nmi_stats.external, 1);
raw_spin_unlock(&nmi_reason_lock);
return;
goto out;
}
raw_spin_unlock(&nmi_reason_lock);

Expand Down Expand Up @@ -412,8 +414,10 @@ static void default_do_nmi(struct pt_regs *regs)
__this_cpu_add(nmi_stats.swallow, 1);
else
unknown_nmi_error(reason, regs);

out:
instrumentation_end();
}
NOKPROBE_SYMBOL(default_do_nmi);

/*
* NMIs can page fault or hit breakpoints which will cause it to lose
Expand Down Expand Up @@ -485,7 +489,7 @@ static DEFINE_PER_CPU(unsigned long, nmi_cr2);
*/
static DEFINE_PER_CPU(int, update_debug_stack);

static bool notrace is_debug_stack(unsigned long addr)
static noinstr bool is_debug_stack(unsigned long addr)
{
struct cea_exception_stacks *cs = __this_cpu_read(cea_exception_stacks);
unsigned long top = CEA_ESTACK_TOP(cs, DB);
Expand All @@ -500,7 +504,6 @@ static bool notrace is_debug_stack(unsigned long addr)
*/
return addr >= bot && addr < top;
}
NOKPROBE_SYMBOL(is_debug_stack);
#endif

DEFINE_IDTENTRY_NMI(exc_nmi)
Expand Down

0 comments on commit f051f69

Please sign in to comment.