Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86 Mitigation for SpectreV4, based on SSBD. The fo...



details:   https://anonhg.NetBSD.org/src/rev/f6a9b7f44a55
branches:  trunk
changeset: 322884:f6a9b7f44a55
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue May 22 07:11:53 2018 +0000

description:
Mitigation for SpectreV4, based on SSBD. The following sysctl branches
are added:

        machdep.spectre_v4.mitigated = {0/1} user-settable
        machdep.spectre_v4.affected = {0/1} set by the kernel

The mitigation is not enabled by default yet. It is not tested either,
because no microcode update has been published yet.

On current CPUs a microcode/bios update must be applied for SSBD to be
available. The user can then set mitigated=1. Even with an update applied
the kernel will set affected=1.

On future CPUs, where the problem will presumably be fixed by default,
the CPU will report SSB_NO, and the kernel will set affected=0. In this
case we also have mitigated=0, but the mitigation is not needed.

For now the feature is system-wide. Perhaps we will want a more
fine-grained, per-process approach in the future.

diffstat:

 sys/arch/x86/include/specialreg.h |   12 +-
 sys/arch/x86/x86/spectre.c        |  149 +++++++++++++++++++++++++++++++++++++-
 sys/arch/x86/x86/x86_machdep.c    |   29 ++++++-
 3 files changed, 181 insertions(+), 9 deletions(-)

diffs (275 lines):

diff -r 9d8ef0e0d5c1 -r f6a9b7f44a55 sys/arch/x86/include/specialreg.h
--- a/sys/arch/x86/include/specialreg.h Tue May 22 06:31:05 2018 +0000
+++ b/sys/arch/x86/include/specialreg.h Tue May 22 07:11:53 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: specialreg.h,v 1.120 2018/03/30 19:49:49 maxv Exp $    */
+/*     $NetBSD: specialreg.h,v 1.121 2018/05/22 07:11:53 maxv Exp $    */
 
 /*-
  * Copyright (c) 1991 The Regents of the University of California.
@@ -405,11 +405,11 @@
 #define CPUID_SEF_IBRS         __BIT(26) /* IBRS / IBPB Speculation Control */
 #define CPUID_SEF_STIBP                __BIT(27) /* STIBP Speculation Control */
 #define CPUID_SEF_ARCH_CAP     __BIT(29) /* IA32_ARCH_CAPABILITIES */
+#define CPUID_SEF_SSBD         __BIT(31) /* Speculative Store Bypass Disable */
 
-#define CPUID_SEF_FLAGS2       "\20" \
-                               "\3" "AVX512_4VNNIW" "\4" "AVX512_4FMAPS" \
-                                       "\33" "IBRS"    "\34" "STIBP"   \
-                       "\36" "ARCH_CAP"
+#define CPUID_SEF_FLAGS2       \
+       "\20" "\3" "AVX512_4VNNIW" "\4" "AVX512_4FMAPS" \
+       "\33" "IBRS" "\34" "STIBP" "\36" "ARCH_CAP" "\38" "SSBD"
 
 /*
  * CPUID Processor extended state Enumeration Fn0000000d
@@ -643,6 +643,7 @@
 #define MSR_IA32_SPEC_CTRL     0x048
 #define        IA32_SPEC_CTRL_IBRS     0x01
 #define        IA32_SPEC_CTRL_STIBP    0x02
+#define        IA32_SPEC_CTRL_SSBD     0x04
 #define MSR_IA32_PRED_CMD      0x049
 #define        IA32_PRED_CMD_IBPB      0x01
 #define MSR_BIOS_UPDT_TRIG     0x079
@@ -660,6 +661,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES 0x10a
 #define        IA32_ARCH_RDCL_NO       0x01
 #define        IA32_ARCH_IBRS_ALL      0x02
+#define        IA32_ARCH_SSB_NO        0x10
 #define MSR_BBL_CR_ADDR                0x116   /* PII+ only */
 #define MSR_BBL_CR_DECC                0x118   /* PII+ only */
 #define MSR_BBL_CR_CTL         0x119   /* PII+ only */
diff -r 9d8ef0e0d5c1 -r f6a9b7f44a55 sys/arch/x86/x86/spectre.c
--- a/sys/arch/x86/x86/spectre.c        Tue May 22 06:31:05 2018 +0000
+++ b/sys/arch/x86/x86/spectre.c        Tue May 22 07:11:53 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: spectre.c,v 1.11 2018/05/22 06:31:05 maxv Exp $        */
+/*     $NetBSD: spectre.c,v 1.12 2018/05/22 07:11:53 maxv Exp $        */
 
 /*
  * Copyright (c) 2018 NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.11 2018/05/22 06:31:05 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.12 2018/05/22 07:11:53 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -347,6 +347,140 @@
 
 /* -------------------------------------------------------------------------- */
 
+bool spec_v4_mitigation_enabled __read_mostly = false;
+bool spec_v4_affected __read_mostly = true;
+
+int sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS);
+
+static bool ssbd_needed(void)
+{
+       uint64_t msr;
+
+       if (cpu_info_primary.ci_feat_val[7] & CPUID_SEF_ARCH_CAP) {
+               msr = rdmsr(MSR_IA32_ARCH_CAPABILITIES);
+               if (msr & IA32_ARCH_SSB_NO) {
+                       /*
+                        * The processor indicates it is not vulnerable to the
+                        * Speculative Store Bypass (SpectreV4) flaw.
+                        */
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static bool ssbd_supported(void)
+{
+       u_int descs[4];
+
+       if (cpu_vendor == CPUVENDOR_INTEL) {
+               if (cpuid_level >= 7) {
+                       x86_cpuid(7, descs);
+                       if (descs[3] & CPUID_SEF_SSBD) {
+                               /* descs[3] = %edx */
+                               return true;
+                       }
+               }
+       }
+       return false;
+}
+
+static void
+mitigation_v4_apply_cpu(bool enabled)
+{
+       uint64_t msr;
+
+       msr = rdmsr(MSR_IA32_SPEC_CTRL);
+
+       if (enabled) {
+               msr |= IA32_SPEC_CTRL_SSBD;
+       } else {
+               msr &= ~IA32_SPEC_CTRL_SSBD;
+       }
+
+       wrmsr(MSR_IA32_SPEC_CTRL, msr);
+}
+
+static void
+mitigation_v4_change_cpu(void *arg1, void *arg2)
+{
+       bool enabled = (bool)arg1;
+
+       mitigation_v4_apply_cpu(enabled);
+}
+
+static int mitigation_v4_change(bool enabled)
+{
+       struct cpu_info *ci = NULL;
+       CPU_INFO_ITERATOR cii;
+       uint64_t xc;
+
+       if (!ssbd_supported()) {
+                       printf("[!] No mitigation available\n");
+                       return EOPNOTSUPP;
+       }
+
+       mutex_enter(&cpu_lock);
+
+       /*
+        * We expect all the CPUs to be online.
+        */
+       for (CPU_INFO_FOREACH(cii, ci)) {
+               struct schedstate_percpu *spc = &ci->ci_schedstate;
+               if (spc->spc_flags & SPCF_OFFLINE) {
+                       printf("[!] cpu%d offline, SpectreV4 not changed\n",
+                           cpu_index(ci));
+                       mutex_exit(&cpu_lock);
+                       return EOPNOTSUPP;
+               }
+       }
+
+       printf("[+] %s SpectreV4 Mitigation...",
+           enabled ? "Enabling" : "Disabling");
+       xc = xc_broadcast(0, mitigation_v4_change_cpu,
+           (void *)enabled, NULL);
+       xc_wait(xc);
+       printf(" done!\n");
+       spec_v4_mitigation_enabled = enabled;
+       mutex_exit(&cpu_lock);
+
+       return 0;
+}
+
+int
+sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node;
+       int error;
+       bool val;
+
+       val = *(bool *)rnode->sysctl_data;
+
+       node = *rnode;
+       node.sysctl_data = &val;
+
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error != 0 || newp == NULL)
+               return error;
+
+       if (val == 0) {
+               if (!spec_v4_mitigation_enabled)
+                       error = 0;
+               else
+                       error = mitigation_v4_change(false);
+       } else {
+               if (spec_v4_mitigation_enabled)
+                       error = 0;
+               else
+                       error = mitigation_v4_change(true);
+       }
+
+       return error;
+}
+
+/* -------------------------------------------------------------------------- */
+
 void speculation_barrier(struct lwp *, struct lwp *);
 
 void
@@ -393,4 +527,15 @@
        if (mitigation_v2_method != MITIGATION_NONE) {
                mitigation_v2_apply_cpu(ci, true);
        }
+
+       /*
+        * Spectre V4.
+        */
+       if (ssbd_needed()) {
+               if (ci == &cpu_info_primary) {
+                       spec_v4_affected = true;
+               }
+               /* mitigation_v4_apply_cpu(true); */
+               /* spec_v4_mitigation_enabled = true; */
+       }
 }
diff -r 9d8ef0e0d5c1 -r f6a9b7f44a55 sys/arch/x86/x86/x86_machdep.c
--- a/sys/arch/x86/x86/x86_machdep.c    Tue May 22 06:31:05 2018 +0000
+++ b/sys/arch/x86/x86/x86_machdep.c    Tue May 22 07:11:53 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: x86_machdep.c,v 1.112 2018/05/22 06:31:05 maxv Exp $   */
+/*     $NetBSD: x86_machdep.c,v 1.113 2018/05/22 07:11:53 maxv Exp $   */
 
 /*-
  * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi,
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.112 2018/05/22 06:31:05 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.113 2018/05/22 07:11:53 maxv Exp $");
 
 #include "opt_modular.h"
 #include "opt_physmem.h"
@@ -1273,8 +1273,11 @@
 
 #ifndef XEN
        int sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS);
+       int sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS);
        extern bool spec_v2_mitigation_enabled;
+       extern bool spec_v4_mitigation_enabled;
        extern char spec_v2_mitigation_name[];
+       extern bool spec_v4_affected;
        const struct sysctlnode *spec_rnode;
 
        /* SpectreV1 */
@@ -1312,6 +1315,28 @@
                       NULL, 0,
                       spec_v2_mitigation_name, 0,
                       CTL_CREATE, CTL_EOL);
+
+       /* SpectreV4 */
+       spec_rnode = NULL;
+       sysctl_createv(clog, 0, NULL, &spec_rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "spectre_v4", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_MACHDEP, CTL_CREATE);
+       sysctl_createv(clog, 0, &spec_rnode, NULL,
+                      CTLFLAG_READWRITE,
+                      CTLTYPE_BOOL, "mitigated",
+                      SYSCTL_DESCR("Whether Spectre Variant 4 is mitigated"),
+                      sysctl_machdep_spectreV4_mitigated, 0,
+                      &spec_v4_mitigation_enabled, 0,
+                      CTL_CREATE, CTL_EOL);
+       sysctl_createv(clog, 0, &spec_rnode, NULL,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_BOOL, "affected",
+                      SYSCTL_DESCR("Whether the CPU is affected by SpectreV4"),
+                      NULL, 0,
+                  &spec_v4_affected, 0,
+                      CTL_CREATE, CTL_EOL);
 #endif
 
        /* None of these can ever change once the system has booted */



Home | Main Index | Thread Index | Old Index