Skip to content

Commit

Permalink
x86/cpu: Call verify_cpu() after having entered long mode too
Browse files Browse the repository at this point in the history
When we get loaded by a 64-bit bootloader, kernel entry point is
startup_64 in head_64.S. We don't trust any and all bootloaders because
some will fiddle with CPU configuration so we go ahead and massage each
CPU into sanity again.

For example, some dell BIOSes have this XD disable feature which set
IA32_MISC_ENABLE[34] and disable NX. This might be some dumb workaround
for other OSes but Linux sure doesn't need it.

A similar thing is present in the Surface 3 firmware - see
https://bugzilla.kernel.org/show_bug.cgi?id=106051 - which sets this bit
only on the BSP:

  # rdmsr -a 0x1a0
  400850089
  850089
  850089
  850089

I know, right?!

There's not even an off switch in there.

So fix all those cases by sanitizing the 64-bit entry point too. For
that, make verify_cpu() callable in 64-bit mode also.

Requested-and-debugged-by: "H. Peter Anvin" <hpa@zytor.com>
Reported-and-tested-by: Bastien Nocera <bugzilla@hadess.net>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/1446739076-21303-1-git-send-email-bp@alien8.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Borislav Petkov authored and Thomas Gleixner committed Nov 7, 2015
1 parent 68accac commit 04633df
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 5 deletions.
8 changes: 8 additions & 0 deletions arch/x86/kernel/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ startup_64:
* tables and then reload them.
*/

/* Sanitize CPU configuration */
call verify_cpu

/*
* Compute the delta between the address I am compiled to run at and the
* address I am actually running at.
Expand Down Expand Up @@ -174,6 +177,9 @@ ENTRY(secondary_startup_64)
* after the boot processor executes this code.
*/

/* Sanitize CPU configuration */
call verify_cpu

movq $(init_level4_pgt - __START_KERNEL_map), %rax
1:

Expand Down Expand Up @@ -288,6 +294,8 @@ ENTRY(secondary_startup_64)
pushq %rax # target address in negative space
lretq

#include "verify_cpu.S"

#ifdef CONFIG_HOTPLUG_CPU
/*
* Boot CPU0 entry point. It's called from play_dead(). Everything has been set
Expand Down
12 changes: 7 additions & 5 deletions arch/x86/kernel/verify_cpu.S
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
#include <asm/msr-index.h>

verify_cpu:
pushfl # Save caller passed flags
pushl $0 # Kill any dangerous flags
popfl
pushf # Save caller passed flags
push $0 # Kill any dangerous flags
popf

#ifndef __x86_64__
pushfl # standard way to check for cpuid
popl %eax
movl %eax,%ebx
Expand All @@ -48,6 +49,7 @@ verify_cpu:
popl %eax
cmpl %eax,%ebx
jz verify_cpu_no_longmode # cpu has no cpuid
#endif

movl $0x0,%eax # See if cpuid 1 is implemented
cpuid
Expand Down Expand Up @@ -130,10 +132,10 @@ verify_cpu_sse_test:
jmp verify_cpu_sse_test # try again

verify_cpu_no_longmode:
popfl # Restore caller passed flags
popf # Restore caller passed flags
movl $1,%eax
ret
verify_cpu_sse_ok:
popfl # Restore caller passed flags
popf # Restore caller passed flags
xorl %eax, %eax
ret

0 comments on commit 04633df

Please sign in to comment.