x86/speculation/swapgs: Exclude ATOMs from speculation through SWAPGS [Linux 3.16.72]

This Linux kernel change "x86/speculation/swapgs: Exclude ATOMs from speculation through SWAPGS" is included in the Linux 3.16.72 release. This change is authored by Thomas Gleixner <tglx [at] linutronix.de> on Wed Jul 17 21:18:59 2019 +0200. The commit for this change in Linux stable tree is 822ef68 (patch) which is from upstream commit f36cf38. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream f36cf38.

x86/speculation/swapgs: Exclude ATOMs from speculation through SWAPGS

commit f36cf386e3fec258a341d446915862eded3e13d8 upstream.

Intel provided the following information:

 On all current Atom processors, instructions that use a segment register
 value (e.g. a load or store) will not speculatively execute before the
 last writer of that segment retires. Thus they will not use a
 speculatively written segment value.

That means on ATOMs there is no speculation through SWAPGS, so the SWAPGS
entry paths can be excluded from the extra LFENCE if PTI is disabled.

Create a separate bug flag for the through SWAPGS speculation and mark all
out-of-order ATOMs and AMD/HYGON CPUs as not affected. The in-order ATOMs
are excluded from the whole mitigation mess anyway.

Reported-by: Andrew Cooper <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Reviewed-by: Tyler Hicks <[email protected]>
Reviewed-by: Josh Poimboeuf <[email protected]>
[bwh: Backported to 3.16:
 - There's no whitelist entry (or any support) for Hygon CPUs
 - Use the next available X86_BUG number
 - Adjust context, indentation]
Signed-off-by: Ben Hutchings <[email protected]>

There are 61 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 arch/x86/include/asm/cpufeatures.h |  1 +
 arch/x86/kernel/cpu/bugs.c         | 18 ++++------------
 arch/x86/kernel/cpu/common.c       | 42 ++++++++++++++++++++++++--------------
 3 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 4e79d30..ba48ab8 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -278,5 +278,6 @@
 #define X86_BUG_L1TF       X86_BUG(9) /* CPU is affected by L1 Terminal Fault */
 #define X86_BUG_MDS        X86_BUG(10) /* CPU is affected by Microarchitectural data sampling */
 #define X86_BUG_MSBDS_ONLY X86_BUG(11) /* CPU is only affected by the  MSDBS variant of BUG_MDS */
+#define X86_BUG_SWAPGS     X86_BUG(12) /* CPU is affected by speculation through SWAPGS */

 #endif /* _ASM_X86_CPUFEATURES_H */
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index ce32b75..f9e23ee 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -328,18 +328,6 @@ enum spectre_v1_mitigation {
    [SPECTRE_V1_MITIGATION_AUTO] = "Mitigation: usercopy/swapgs barriers and __user pointer sanitization",
 };

-static bool is_swapgs_serializing(void)
-{
-   /*
-    * Technically, swapgs isn't serializing on AMD (despite it previously
-    * being documented as such in the APM).  But according to AMD, %gs is
-    * updated non-speculatively, and the issuing of %gs-relative memory
-    * operands will be blocked until the %gs update completes, which is
-    * good enough for our purposes.
-    */
-   return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
-}
-
 /*
  * Does SMAP provide full mitigation against speculative kernel access to
  * userspace?
@@ -390,9 +378,11 @@ static void __init spectre_v1_select_mitigation(void)
             * PTI as the CR3 write in the Meltdown mitigation
             * is serializing.
             *
-            * If neither is there, mitigate with an LFENCE.
+            * If neither is there, mitigate with an LFENCE to
+            * stop speculation through swapgs.
             */
-           if (!is_swapgs_serializing() && !boot_cpu_has(X86_FEATURE_KAISER))
+           if (boot_cpu_has_bug(X86_BUG_SWAPGS) &&
+               !boot_cpu_has(X86_FEATURE_KAISER))
                setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_USER);

            /*
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 9d4638d..337fcac 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -813,6 +813,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #define NO_L1TF        BIT(3)
 #define NO_MDS     BIT(4)
 #define MSBDS_ONLY BIT(5)
+#define NO_SWAPGS  BIT(6)

 #define VULNWL(_vendor, _family, _model, _whitelist)   \
    { X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
@@ -836,29 +837,37 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
    VULNWL_INTEL(ATOM_BONNELL,      NO_SPECULATION),
    VULNWL_INTEL(ATOM_BONNELL_MID,      NO_SPECULATION),

-   VULNWL_INTEL(ATOM_SILVERMONT,       NO_SSB | NO_L1TF | MSBDS_ONLY),
-   VULNWL_INTEL(ATOM_SILVERMONT_X,     NO_SSB | NO_L1TF | MSBDS_ONLY),
-   VULNWL_INTEL(ATOM_SILVERMONT_MID,   NO_SSB | NO_L1TF | MSBDS_ONLY),
-   VULNWL_INTEL(ATOM_AIRMONT,      NO_SSB | NO_L1TF | MSBDS_ONLY),
-   VULNWL_INTEL(XEON_PHI_KNL,      NO_SSB | NO_L1TF | MSBDS_ONLY),
-   VULNWL_INTEL(XEON_PHI_KNM,      NO_SSB | NO_L1TF | MSBDS_ONLY),
+   VULNWL_INTEL(ATOM_SILVERMONT,       NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+   VULNWL_INTEL(ATOM_SILVERMONT_X,     NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+   VULNWL_INTEL(ATOM_SILVERMONT_MID,   NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+   VULNWL_INTEL(ATOM_AIRMONT,      NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+   VULNWL_INTEL(XEON_PHI_KNL,      NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+   VULNWL_INTEL(XEON_PHI_KNM,      NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),

    VULNWL_INTEL(CORE_YONAH,        NO_SSB),

-   VULNWL_INTEL(ATOM_AIRMONT_MID,      NO_L1TF | MSBDS_ONLY),
+   VULNWL_INTEL(ATOM_AIRMONT_MID,      NO_L1TF | MSBDS_ONLY | NO_SWAPGS),

-   VULNWL_INTEL(ATOM_GOLDMONT,     NO_MDS | NO_L1TF),
-   VULNWL_INTEL(ATOM_GOLDMONT_X,       NO_MDS | NO_L1TF),
-   VULNWL_INTEL(ATOM_GOLDMONT_PLUS,    NO_MDS | NO_L1TF),
+   VULNWL_INTEL(ATOM_GOLDMONT,     NO_MDS | NO_L1TF | NO_SWAPGS),
+   VULNWL_INTEL(ATOM_GOLDMONT_X,       NO_MDS | NO_L1TF | NO_SWAPGS),
+   VULNWL_INTEL(ATOM_GOLDMONT_PLUS,    NO_MDS | NO_L1TF | NO_SWAPGS),
+
+   /*
+    * Technically, swapgs isn't serializing on AMD (despite it previously
+    * being documented as such in the APM).  But according to AMD, %gs is
+    * updated non-speculatively, and the issuing of %gs-relative memory
+    * operands will be blocked until the %gs update completes, which is
+    * good enough for our purposes.
+    */

    /* AMD Family 0xf - 0x12 */
-   VULNWL_AMD(0x0f,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-   VULNWL_AMD(0x10,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-   VULNWL_AMD(0x11,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
-   VULNWL_AMD(0x12,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+   VULNWL_AMD(0x0f,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+   VULNWL_AMD(0x10,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+   VULNWL_AMD(0x11,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+   VULNWL_AMD(0x12,    NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),

    /* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
-   VULNWL_AMD(X86_FAMILY_ANY,  NO_MELTDOWN | NO_L1TF | NO_MDS),
+   VULNWL_AMD(X86_FAMILY_ANY,  NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
    {}
 };

@@ -895,6 +904,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
            setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
    }

+   if (!cpu_matches(NO_SWAPGS))
+       setup_force_cpu_bug(X86_BUG_SWAPGS);
+
    if (cpu_matches(NO_MELTDOWN))
        return;

Leave a Reply

Your email address will not be published. Required fields are marked *