Commit 5b0e5084 authored by Jan Beulich's avatar Jan Beulich Committed by Ingo Molnar
Browse files

x86: prevent unconditional writes to DebugCtl MSR



Otherwise, enabling (or better, subsequent disabling) of single
stepping would cause a kernel oops on CPUs not having this MSR.

The patch could have been added a conditional to the MSR write in
user_disable_single_step(), but centralizing the updates seems safer
and (looking forward) better manageable.

Signed-off-by: default avatarJan Beulich <jbeulich@novell.com>
Cc: Markus Metzger <markus.t.metzger@intel.com>

Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent f6940101
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -410,13 +410,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
static void __kprobes clear_btf(void)
{
	if (test_thread_flag(TIF_DEBUGCTLMSR))
		wrmsrl(MSR_IA32_DEBUGCTLMSR, 0);
		update_debugctlmsr(0);
}

static void __kprobes restore_btf(void)
{
	if (test_thread_flag(TIF_DEBUGCTLMSR))
		wrmsrl(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr);
		update_debugctlmsr(current->thread.debugctlmsr);
}

static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+2 −2
Original line number Diff line number Diff line
@@ -564,12 +564,12 @@ __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
		/* we clear debugctl to make sure DS
		 * is not in use when we change it */
		debugctl = 0;
		wrmsrl(MSR_IA32_DEBUGCTLMSR, 0);
		update_debugctlmsr(0);
		wrmsr(MSR_IA32_DS_AREA, next->ds_area_msr, 0);
	}

	if (next->debugctlmsr != debugctl)
		wrmsr(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr, 0);
		update_debugctlmsr(next->debugctlmsr);

	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
		set_debugreg(next->debugreg0, 0);
+2 −2
Original line number Diff line number Diff line
@@ -563,12 +563,12 @@ static inline void __switch_to_xtra(struct task_struct *prev_p,
		/* we clear debugctl to make sure DS
		 * is not in use when we change it */
		debugctl = 0;
		wrmsrl(MSR_IA32_DEBUGCTLMSR, 0);
		update_debugctlmsr(0);
		wrmsrl(MSR_IA32_DS_AREA, next->ds_area_msr);
	}

	if (next->debugctlmsr != debugctl)
		wrmsrl(MSR_IA32_DEBUGCTLMSR, next->debugctlmsr);
		update_debugctlmsr(next->debugctlmsr);

	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
		loaddebug(next, 0);
+1 −1
Original line number Diff line number Diff line
@@ -148,7 +148,7 @@ static void write_debugctlmsr(struct task_struct *child, unsigned long val)
	if (child != current)
		return;

	wrmsrl(MSR_IA32_DEBUGCTLMSR, val);
	update_debugctlmsr(val);
}

/*
+9 −0
Original line number Diff line number Diff line
@@ -741,6 +741,15 @@ extern void switch_to_new_gdt(void);
extern void cpu_init(void);
extern void init_gdt(int cpu);

static inline void update_debugctlmsr(unsigned long debugctlmsr)
{
#ifndef CONFIG_X86_DEBUGCTLMSR
	if (boot_cpu_data.x86 < 6)
		return;
#endif
	wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
}

/*
 * from system description table in BIOS. Mostly for MCA use, but
 * others may find it useful: