]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/speculation/l1tf: Add sysfs reporting for l1tf
authorAndi Kleen <ak@linux.intel.com>
Wed, 13 Jun 2018 22:48:26 +0000 (15:48 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 3 Oct 2018 03:10:01 +0000 (04:10 +0100)
commit 17dbca119312b4e8173d4e25ff64262119fcef38 upstream.

L1TF core kernel workarounds are cheap and normally always enabled, However
they still should be reported in sysfs if the system is vulnerable or
mitigated. Add the necessary CPU feature/bug bits.

- Extend the existing checks for Meltdowns to determine if the system is
  vulnerable. All CPUs which are not vulnerable to Meltdown are also not
  vulnerable to L1TF

- Check for 32bit non PAE and emit a warning as there is no practical way
  for mitigation due to the limited physical address bits

- If the system has more than MAX_PA/2 physical memory the invert page
  workarounds don't protect the system against the L1TF attack anymore,
  because an inverted physical address will also point to valid
  memory. Print a warning in this case and report that the system is
  vulnerable.

Add a function which returns the PFN limit for the L1TF mitigation, which
will be used in follow up patches for sanity and range checks.

[ tglx: Renamed the CPU feature bit to L1TF_PTEINV ]
[ dwmw2: Backport to 4.9 (cpufeatures.h, E820) ]

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.16:
 - Assign the next available bits from feature word 7 and bug word 0
 - CONFIG_PGTABLE_LEVELS is not defined; use other config symbols in the
   condition
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/processor.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
drivers/base/cpu.c
include/linux/cpu.h

index 6e04149e14df16dceb954f64a2d97142b68918b5..f3c8dc4083af88fe361bb0143cd477c62394b957 100644 (file)
 #define X86_FEATURE_MSR_SPEC_CTRL (7*32+19) /* "" MSR SPEC_CTRL is implemented */
 #define X86_FEATURE_SSBD       (7*32+20) /* Speculative Store Bypass Disable */
 #define X86_FEATURE_ZEN                (7*32+21) /* "" CPU is AMD family 0x17 (Zen) */
+#define X86_FEATURE_L1TF_PTEINV        (7*32+22) /* "" L1TF workaround PTE inversion */
 
 #define X86_FEATURE_RETPOLINE  (7*32+29) /* "" Generic Retpoline mitigation for Spectre variant 2 */
 #define X86_FEATURE_RETPOLINE_AMD (7*32+30) /* "" AMD Retpoline mitigation for Spectre variant 2 */
 #define X86_BUG_SPECTRE_V1     X86_BUG(6) /* CPU is affected by Spectre variant 1 attack with conditional branches */
 #define X86_BUG_SPECTRE_V2     X86_BUG(7) /* CPU is affected by Spectre variant 2 attack with indirect branches */
 #define X86_BUG_SPEC_STORE_BYPASS X86_BUG(8) /* CPU is affected by speculative store bypass attack */
+#define X86_BUG_L1TF           X86_BUG(9) /* CPU is affected by L1 Terminal Fault */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
index 801b59a7e97d994a698727773e55b4ffd84131a0..4553fe64567102a60d919d4bbbd0025a50217dd1 100644 (file)
@@ -165,6 +165,11 @@ extern const struct seq_operations cpuinfo_op;
 extern void cpu_detect(struct cpuinfo_x86 *c);
 extern void fpu_detect(struct cpuinfo_x86 *c);
 
+static inline unsigned long l1tf_pfn_limit(void)
+{
+       return BIT(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1;
+}
+
 extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
 extern void identify_secondary_cpu(struct cpuinfo_x86 *);
index 974a55eb62e40996669e9739de5b566dec2b3333..64e4530bf9649d5de1ddf52e055304aa963cfca1 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/intel-family.h>
+#include <asm/e820.h>
 
 static void __init spectre_v2_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
+static void __init l1tf_select_mitigation(void);
 
 /*
  * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any
@@ -138,6 +140,8 @@ void __init check_bugs(void)
         */
        ssb_select_mitigation();
 
+       l1tf_select_mitigation();
+
 #ifdef CONFIG_X86_32
        /*
         * Check whether we are able to run this kernel safely on SMP.
@@ -266,6 +270,32 @@ static void x86_amd_ssb_disable(void)
                wrmsrl(MSR_AMD64_LS_CFG, msrval);
 }
 
+static void __init l1tf_select_mitigation(void)
+{
+       u64 half_pa;
+
+       if (!boot_cpu_has_bug(X86_BUG_L1TF))
+               return;
+
+#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
+       pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n");
+       return;
+#endif
+
+       /*
+        * This is extremely unlikely to happen because almost all
+        * systems have far more MAX_PA/2 than RAM can be fit into
+        * DIMM slots.
+        */
+       half_pa = (u64)l1tf_pfn_limit() << PAGE_SHIFT;
+       if (e820_any_mapped(half_pa, ULLONG_MAX - half_pa, E820_RAM)) {
+               pr_warn("System has more than MAX_PA/2 memory. L1TF mitigation not effective.\n");
+               return;
+       }
+
+       setup_force_cpu_cap(X86_FEATURE_L1TF_PTEINV);
+}
+
 #ifdef RETPOLINE
 static bool spectre_v2_bad_module;
 
@@ -718,6 +748,11 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_SPEC_STORE_BYPASS:
                return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
 
+       case X86_BUG_L1TF:
+               if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))
+                       return sprintf(buf, "Mitigation: Page Table Inversion\n");
+               break;
+
        default:
                break;
        }
@@ -744,4 +779,9 @@ ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_SPEC_STORE_BYPASS);
 }
+
+ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_L1TF);
+}
 #endif
index 01c7438130e9902a0e01573bfe3097890e5a875e..895085cedf30b0149d79b1ee301aaaff3cffe6a8 100644 (file)
@@ -842,6 +842,21 @@ static const __initconst struct x86_cpu_id cpu_no_spec_store_bypass[] = {
        {}
 };
 
+static const __initconst struct x86_cpu_id cpu_no_l1tf[] = {
+       /* in addition to cpu_no_speculation */
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT1     },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_SILVERMONT2     },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_AIRMONT         },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_MERRIFIELD      },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_MOOREFIELD      },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_GOLDMONT        },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_DENVERTON       },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_ATOM_GEMINI_LAKE     },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNL         },
+       { X86_VENDOR_INTEL,     6,      INTEL_FAM6_XEON_PHI_KNM         },
+       {}
+};
+
 static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
 {
        u64 ia32_cap = 0;
@@ -867,6 +882,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
                return;
 
        setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+
+       if (x86_match_cpu(cpu_no_l1tf))
+               return;
+
+       setup_force_cpu_bug(X86_BUG_L1TF);
 }
 
 /*
index ba68d18ac4e9a7b967832959bb6133d80b29fcb6..c55acc37fef2d53816e81518a4003ac819bcb70a 100644 (file)
@@ -444,16 +444,24 @@ ssize_t __weak cpu_show_spec_store_bypass(struct device *dev,
        return sprintf(buf, "Not affected\n");
 }
 
+ssize_t __weak cpu_show_l1tf(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "Not affected\n");
+}
+
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
 static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
 static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL);
+static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
        &dev_attr_spectre_v1.attr,
        &dev_attr_spectre_v2.attr,
        &dev_attr_spec_store_bypass.attr,
+       &dev_attr_l1tf.attr,
        NULL
 };
 
index fabc2bb5d42583f347ab629bbb5a927ebfe9583c..ac169482c507964de33d22b8e65d7ef7307b93fe 100644 (file)
@@ -47,6 +47,8 @@ extern ssize_t cpu_show_spectre_v2(struct device *dev,
                                   struct device_attribute *attr, char *buf);
 extern ssize_t cpu_show_spec_store_bypass(struct device *dev,
                                          struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_l1tf(struct device *dev,
+                            struct device_attribute *attr, char *buf);
 
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);