]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature
authorKonrad Rzeszutek Wilk <konrad@kernel.org>
Thu, 4 Jan 2018 16:20:00 +0000 (11:20 -0500)
committerKirtikar Kashyap <kirtikar.kashyap@oracle.com>
Fri, 12 Jan 2018 18:19:56 +0000 (10:19 -0800)
There are 2 ways to control IBPB and IBRS

1. At boot time
        noibrs kernel boot parameter will disable IBRS usage
        noibpb kernel boot parameter will disable IBPB usage
Otherwise if the above parameters are not specified, the system
will enable ibrs and ibpb usage if the cpu supports it.

2. At run time
        echo 0 > /proc/sys/kernel/ibrs_enabled will turn off IBRS
        echo 1 > /proc/sys/kernel/ibrs_enabled will turn on IBRS in kernel
        echo 2 > /proc/sys/kernel/ibrs_enabled will turn on IBRS in both userspace and kernel

Orabug: 27344012
CVE: CVE-2017-5715

Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
[Backport: This completes the scaffolding work done in the earlier
 patch which had the same title]

Reviewed-by: John Haxby <john.haxby@oracle.com>
Signed-off-by: Kirtikar Kashyap <kirtikar.kashyap@oracle.com>
arch/x86/include/asm/mwait.h
arch/x86/include/asm/spec_ctrl.h
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/smpboot.c
arch/x86/kvm/vmx.c
kernel/sysctl.c

index c4b6a15065d29de5a47c1ecbdb8a9a2521042f23..72f8fcd65ec17bc49d8fedb212d8b55317e7d07c 100644 (file)
@@ -59,14 +59,14 @@ static inline void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
                        mb();
                }
 
-               if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               if (ibrs_inuse)
                        native_wrmsrl(MSR_IA32_SPEC_CTRL, 0);
 
                __monitor((void *)&current_thread_info()->flags, 0, 0);
                if (!need_resched())
                        __mwait(eax, ecx);
 
-               if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               if (ibrs_inuse)
                        native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
        }
        current_clr_polling();
index 9bf0e8e996429243ecca6f7ba7c25d802215d1f5..ba1c51058b62ce2969af995fad1f7161d3ae7421 100644 (file)
@@ -9,6 +9,7 @@
 #ifdef __ASSEMBLY__
 
 .extern use_ibrs
+.extern use_ibpb
 
 #define __ASM_ENABLE_IBRS                      \
        pushq %rax;                             \
@@ -168,7 +169,10 @@ ALTERNATIVE "", __stringify(__ASM_ENABLE_IBRS), X86_FEATURE_SPEC_CTRL
 .endm
 
 .macro DISABLE_IBRS
-ALTERNATIVE "", __stringify(__ASM_DISABLE_IBRS), X86_FEATURE_SPEC_CTRL
+       testl   $1, use_ibrs
+       jz      9f
+       __ASM_DISABLE_IBRS
+9:
 .endm
 
 .macro SET_IBPB
index bcb5303de9026377a8c92a6dcabe650c93dbe021..3d8b1170b3ab0ed7542234594d97a61da312a32f 100644 (file)
@@ -497,9 +497,15 @@ static void init_intel(struct cpuinfo_x86 *c)
        if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) {
                printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n");
                set_ibrs_supported();
+               set_ibpb_supported();
+               if (ibrs_inuse)
+                       sysctl_ibrs_enabled = 1;
+               if (ibpb_inuse)
+                       sysctl_ibpb_enabled = 1;
        }
-       else
+       else {
                printk_once(KERN_INFO "FEATURE SPEC_CTRL Not Present\n");
+       }
 }
 
 #ifdef CONFIG_X86_32
index 9495f5efdf87434b6e10623b4c10ec21ba9e8020..c530af21ccfc0d661d8ac91d8b6fb3d3260c2af4 100644 (file)
@@ -1505,14 +1505,14 @@ void native_play_dead(void)
        play_dead_common();
        tboot_shutdown(TB_SHUTDOWN_WFS);
 
-       if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+       if (ibrs_inuse)
                native_wrmsrl(MSR_IA32_SPEC_CTRL, 0);
 
        mwait_play_dead();      /* Only returns on failure */
        if (cpuidle_play_dead())
                hlt_play_dead();
 
-       if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+       if (ibrs_inuse)
                native_wrmsrl(MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
 }
 
index d21ca86058b34ba643ecaabcd93041bb6c07580a..68c6ad376acb564a7702d21ccd0a7ce831221ed7 100644 (file)
@@ -1922,7 +1922,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
                per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
                vmcs_load(vmx->loaded_vmcs->vmcs);
-               if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               if (ibpb_inuse)
                        native_wrmsrl(MSR_IA32_PRED_CMD, FEATURE_SET_IBPB);
        }
 
index 8cdc4d55abd78866e203d596a9a048e964364c83..60726ece3bf2da223cbf6a520e38949098b8d9ee 100644 (file)
@@ -69,6 +69,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <asm/msr.h>
 
 #ifdef CONFIG_X86
 #include <asm/nmi.h>
@@ -195,6 +196,15 @@ static int proc_dostring_coredump(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp, loff_t *ppos);
 #endif
 
+#ifdef CONFIG_X86
+int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos);
+int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos);
+int proc_dointvec_ibrs_dump(struct ctl_table *table, int write,
+                 void __user *buffer, size_t *lenp, loff_t *ppos);
+#endif
+
 #ifdef CONFIG_MAGIC_SYSRQ
 /* Note: sysrq code uses it's own private copy */
 static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
@@ -231,6 +241,12 @@ extern struct ctl_table epoll_table[];
 int sysctl_legacy_va_layout;
 #endif
 
+u32 sysctl_ibrs_dump = 0;
+u32 sysctl_ibrs_enabled = 0;
+EXPORT_SYMBOL(sysctl_ibrs_enabled);
+u32 sysctl_ibpb_enabled = 0;
+EXPORT_SYMBOL(sysctl_ibpb_enabled);
+
 /* The default sysctl tables: */
 
 static struct ctl_table sysctl_base_table[] = {
@@ -1171,6 +1187,35 @@ static struct ctl_table kern_table[] = {
                .extra1         = &zero,
                .extra2         = &one,
        },
+#endif
+#ifdef CONFIG_X86
+       {
+               .procname       = "ibrs_enabled",
+               .data           = &sysctl_ibrs_enabled,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ibrs_ctrl,
+               .extra1         = &zero,
+               .extra2         = &two,
+       },
+       {
+               .procname       = "ibpb_enabled",
+               .data           = &sysctl_ibpb_enabled,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ibpb_ctrl,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+       {
+               .procname       = "ibrs_dump",
+               .data           = &sysctl_ibrs_dump,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ibrs_dump,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
 #endif
        { }
 };
@@ -2795,6 +2840,84 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
        }
 }
 
+#ifdef CONFIG_X86
+int proc_dointvec_ibrs_dump(struct ctl_table *table, int write,
+       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+       unsigned int cpu;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       printk("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled);
+       printk("use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb);
+       for_each_online_cpu(cpu) {
+              u64 val;
+
+              if (boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+                      rdmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, &val);
+              else
+                      val = 0;
+              printk("read cpu %d ibrs val %lu\n", cpu, (unsigned long) val);
+       }
+       return ret;
+}
+
+int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write,
+       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+       unsigned int cpu;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled);
+       pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb);
+       if (sysctl_ibrs_enabled == 0) {
+               /* always set IBRS off */
+               set_ibrs_disabled();
+               if (ibrs_supported) {
+                       for_each_online_cpu(cpu)
+                               wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, 0x0);
+               }
+       } else if (sysctl_ibrs_enabled == 2) {
+               /* always set IBRS on, even in user space */
+               clear_ibrs_disabled();
+               if (ibrs_supported) {
+                       for_each_online_cpu(cpu)
+                               wrmsrl_on_cpu(cpu, MSR_IA32_SPEC_CTRL, FEATURE_ENABLE_IBRS);
+               } else {
+                       sysctl_ibrs_enabled = 0;
+               }
+       } else if (sysctl_ibrs_enabled == 1) {
+               /* use IBRS in kernel */
+               clear_ibrs_disabled();
+               if (!ibrs_inuse)
+                       /* platform don't support ibrs */
+                       sysctl_ibrs_enabled = 0;
+       }
+       pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb);
+       return ret;
+}
+
+int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write,
+       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+       pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled);
+       pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb);
+       if (sysctl_ibpb_enabled == 0)
+               set_ibpb_disabled();
+       else if (sysctl_ibpb_enabled == 1) {
+               clear_ibpb_disabled();
+               if (!ibpb_inuse)
+                       /* platform don't support ibpb */
+                       sysctl_ibpb_enabled = 0;
+       }
+       pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb);
+       return ret;
+}
+#endif
 #else /* CONFIG_PROC_SYSCTL */
 
 int proc_dostring(struct ctl_table *table, int write,