x86, cpu: Clear XD_DISABLED flag on Intel to regain NX
authorKees Cook <kees.cook@canonical.com>
Wed, 10 Nov 2010 18:35:52 +0000 (10:35 -0800)
committerH. Peter Anvin <hpa@linux.intel.com>
Wed, 10 Nov 2010 23:42:54 +0000 (15:42 -0800)
Intel CPUs have an additional MSR bit to indicate if the BIOS was
configured to disable the NX cpu feature. This bit was traditionally
used for operating systems that did not understand how to handle the
NX bit. Since Linux understands this, this BIOS flag should be ignored
by default.

In a review[1] of reported hardware being used by Ubuntu bug reporters,
almost 10% of systems had an incorrectly configured BIOS, leaving their
systems unable to use the NX features of their CPU.

This change will clear the MSR_IA32_MISC_ENABLE_XD_DISABLE bit so that NX
cannot be inappropriately controlled by the BIOS on Intel CPUs. If, under
very strange hardware configurations, NX actually needs to be disabled,
"noexec=off" can be used to restore the prior behavior.

[1] http://www.outflux.net/blog/archives/2010/02/18/data-mining-for-nx-bit/

Signed-off-by: Kees Cook <kees.cook@canonical.com>
LKML-Reference: <1289414154-7829-3-git-send-email-kees.cook@canonical.com>
Acked-by: Pekka Enberg <penberg@kernel.org>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
arch/x86/kernel/verify_cpu.S

index 56a8c2a..ccb4136 100644 (file)
@@ -7,6 +7,7 @@
  *     Copyright (c) 2007  Andi Kleen (ak@suse.de)
  *     Copyright (c) 2007  Eric Biederman (ebiederm@xmission.com)
  *     Copyright (c) 2007  Vivek Goyal (vgoyal@in.ibm.com)
+ *     Copyright (c) 2010  Kees Cook (kees.cook@canonical.com)
  *
  *     This source code is licensed under the GNU General Public License,
  *     Version 2.  See the file COPYING for more details.
  *     This is a common code for verification whether CPU supports
  *     long mode and SSE or not. It is not called directly instead this
  *     file is included at various places and compiled in that context.
- *     Following are the current usage.
+ *     This file is expected to run in 32bit code.  Currently:
  *
- *     This file is included by both 16bit and 32bit code.
+ *     arch/x86_64/boot/compressed/head_64.S: Boot cpu verification
+ *     arch/x86_64/kernel/trampoline_64.S: secondary processor verfication
  *
- *     arch/x86_64/boot/setup.S : Boot cpu verification (16bit)
- *     arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit)
- *     arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit)
- *     arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit)
- *
- *     verify_cpu, returns the status of cpu check in register %eax.
+ *     verify_cpu, returns the status of longmode and SSE in register %eax.
  *             0: Success    1: Failure
  *
+ *     On Intel, the XD_DISABLE flag will be cleared as a side-effect.
+ *
  *     The caller needs to check for the error code and take the action
  *     appropriately. Either display a message or halt.
  */
@@ -62,8 +61,41 @@ verify_cpu:
        cmpl    $0x444d4163,%ecx
        jnz     verify_cpu_noamd
        mov     $1,%di                  # cpu is from AMD
+       jmp     verify_cpu_check
 
 verify_cpu_noamd:
+       cmpl    $0x756e6547,%ebx        # GenuineIntel?
+       jnz     verify_cpu_check
+       cmpl    $0x49656e69,%edx
+       jnz     verify_cpu_check
+       cmpl    $0x6c65746e,%ecx
+       jnz     verify_cpu_check
+
+       # only call IA32_MISC_ENABLE when:
+       # family > 6 || (family == 6 && model >= 0xd)
+       movl    $0x1, %eax              # check CPU family and model
+       cpuid
+       movl    %eax, %ecx
+
+       andl    $0x0ff00f00, %eax       # mask family and extended family
+       shrl    $8, %eax
+       cmpl    $6, %eax
+       ja      verify_cpu_clear_xd     # family > 6, ok
+       jb      verify_cpu_check        # family < 6, skip
+
+       andl    $0x000f00f0, %ecx       # mask model and extended model
+       shrl    $4, %ecx
+       cmpl    $0xd, %ecx
+       jb      verify_cpu_check        # family == 6, model < 0xd, skip
+
+verify_cpu_clear_xd:
+       movl    $MSR_IA32_MISC_ENABLE, %ecx
+       rdmsr
+       btrl    $2, %edx                # clear MSR_IA32_MISC_ENABLE_XD_DISABLE
+       jnc     verify_cpu_check        # only write MSR if bit was changed
+       wrmsr
+
+verify_cpu_check:
        movl    $0x1,%eax               # Does the cpu have what it takes
        cpuid
        andl    $REQUIRED_MASK0,%edx