x86: prevent unconditional writes to DebugCtl MSR
authorJan Beulich <jbeulich@novell.com>
Mon, 10 Mar 2008 13:11:17 +0000 (13:11 +0000)
committerIngo Molnar <mingo@elte.hu>
Thu, 17 Apr 2008 15:40:58 +0000 (17:40 +0200)
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: Jan Beulich <jbeulich@novell.com>
Cc: Markus Metzger <markus.t.metzger@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/kprobes.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/step.c
include/asm-x86/processor.h

index 34a591283f5d9e5fb602e8e5f93e3dd5a1a1615e..1e3de7db9ad5f393a9256a58b9c59e28d52f79cf 100644 (file)
@@ -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)
index 9230ce060d09e8de1971ce7ba35a4310b7a83d49..ec05fb750dfc31a185cd12245520a361d85ad061 100644 (file)
@@ -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);
index 1ffce14cff6e054cc20eac43cc834da5ef7509b7..4f40272474dd36f72f8156fb4639a79a020b4491 100644 (file)
@@ -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);
index 071ff4798236736f9d961050954589a4adb54fe4..92c20fee6781b5f5d419335e68eee8361b7f960d 100644 (file)
@@ -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);
 }
 
 /*
index cc0268395ea2e0203c9b2683dcada5187b15ead3..40227c9bf51b6a9da932d3efff8fddf40618c7ff 100644 (file)
@@ -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: