x86/fpu: Default eagerfpu if FPU and FXSR are enabled
authorBen Hutchings <ben@decadent.org.uk>
Sun, 24 Jun 2018 23:25:48 +0000 (00:25 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 25 Sep 2018 22:47:21 +0000 (23:47 +0100)
This is a limited version of commit 58122bf1d856 "x86/fpu: Default
eagerfpu=on on all CPUs".  That commit revealed bugs in the use of
eagerfpu together with math emulation or without the FXSR feature.
Although those bugs have been fixed upstream, the fixes do not seem to
be practical to backport to 3.16.

The security issue that motivates using eagerfpu (CVE-2018-3665) is an
information leak through speculative execution, and most CPUs lacking
the FXSR feature also don't implement speculative execution.  The
exceptions I am aware of are the Intel Pentium Pro and AMD K6 family,
which will remain vulnerable to this issue.

Move the eagerfpu variable and associated initialisation into
fpu_init(), since xstate_enable_boot_cpu() won't be called at all if
XSAVE is disabled.

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: x86@kernel.org
arch/x86/kernel/i387.c
arch/x86/kernel/xsave.c

index 99df035d7cb18f3812761f03116c3970881612dc..60ea04f36653f9fecfb939e3a7bb277defa58574 100644 (file)
@@ -159,6 +159,19 @@ static void init_thread_xstate(void)
                xstate_size = sizeof(struct i387_fsave_struct);
 }
 
+static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
+static int __init eager_fpu_setup(char *s)
+{
+       if (!strcmp(s, "on"))
+               eagerfpu = ENABLE;
+       else if (!strcmp(s, "off"))
+               eagerfpu = DISABLE;
+       else if (!strcmp(s, "auto"))
+               eagerfpu = AUTO;
+       return 1;
+}
+__setup("eagerfpu=", eager_fpu_setup);
+
 /*
  * Called at bootup to set up the initial FPU state that is later cloned
  * into all processes.
@@ -197,6 +210,17 @@ void fpu_init(void)
        if (xstate_size == 0)
                init_thread_xstate();
 
+       /*
+        * We should always enable eagerfpu, but it doesn't work properly
+        * here without fpu and fxsr.
+        */
+       if (eagerfpu == AUTO)
+               eagerfpu = (boot_cpu_has(X86_FEATURE_FPU) &&
+                           boot_cpu_has(X86_FEATURE_FXSR)) ?
+                       ENABLE : DISABLE;
+       if (eagerfpu == ENABLE)
+               setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
+
        mxcsr_feature_mask_init();
        xsave_init();
        eager_fpu_init();
index cfc2dbffa16c67e914b8de7e90debb728f6943fc..44d28b6071a519dce3fe57ee6a10f13a15a6fc0a 100644 (file)
@@ -509,19 +509,6 @@ static void __init setup_init_fpu_buf(void)
        xsave_state(init_xstate_buf, -1);
 }
 
-static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
-static int __init eager_fpu_setup(char *s)
-{
-       if (!strcmp(s, "on"))
-               eagerfpu = ENABLE;
-       else if (!strcmp(s, "off"))
-               eagerfpu = DISABLE;
-       else if (!strcmp(s, "auto"))
-               eagerfpu = AUTO;
-       return 1;
-}
-__setup("eagerfpu=", eager_fpu_setup);
-
 /*
  * Enable and initialize the xsave feature.
  */
@@ -560,17 +547,11 @@ static void __init xstate_enable_boot_cpu(void)
        prepare_fx_sw_frame();
        setup_init_fpu_buf();
 
-       /* Auto enable eagerfpu for xsaveopt */
-       if (cpu_has_xsaveopt && eagerfpu != DISABLE)
-               eagerfpu = ENABLE;
-
        if (pcntxt_mask & XSTATE_EAGER) {
-               if (eagerfpu == DISABLE) {
+               if (!boot_cpu_has(X86_FEATURE_EAGER_FPU)) {
                        pr_err("eagerfpu not present, disabling some xstate features: 0x%llx\n",
                                        pcntxt_mask & XSTATE_EAGER);
                        pcntxt_mask &= ~XSTATE_EAGER;
-               } else {
-                       eagerfpu = ENABLE;
                }
        }
 
@@ -613,9 +594,6 @@ void eager_fpu_init(void)
        clear_used_math();
        current_thread_info()->status = 0;
 
-       if (eagerfpu == ENABLE)
-               setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
-
        if (!cpu_has_eager_fpu) {
                stts();
                return;