]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
x86/spec_ctrl: Provide the sysfs version of the ibrs_enabled
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Fri, 5 Jan 2018 03:37:27 +0000 (22:37 -0500)
committerKirtikar Kashyap <kirtikar.kashyap@oracle.com>
Fri, 12 Jan 2018 18:20:12 +0000 (10:20 -0800)
as well as the proc version.

This is rather important as customers are asking about the sysfs
now. But this may change in the future. See

https://lkml.org/lkml/2018/1/6/303

Orabug: 27344012
CVE: CVE-2017-5715

Reviewed-by: Todd Vierling <todd.vierling@oracle.com>
Acked-by: John Haxby <john.haxby@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Kirtikar Kashyap <kirtikar.kashyap@oracle.com>
arch/x86/include/asm/spec_ctrl.h
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/spec_ctrl.c [new file with mode: 0644]

index d4df538ce72da9480512d9b5b0596f75b799540e..5f7e27644a813672e86ad340cabff2e05c87bf88 100644 (file)
@@ -191,5 +191,14 @@ ALTERNATIVE "", __stringify(__ASM_DISABLE_IBRS_CLOBBER), X86_FEATURE_SPEC_CTRL
 ALTERNATIVE __stringify(__ASM_STUFF_RSB), "", X86_FEATURE_SMEP
 .endm
 
+#else
+enum {
+       IBRS_DISABLED,
+       /* in host kernel, disabled in guest and userland */
+       IBRS_ENABLED,
+       /* in host kernel and host userland, disabled in guest */
+       IBRS_ENABLED_USER,
+       IBRS_MAX = IBRS_ENABLED_USER,
+};
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_X86_SPEC_CTRL_H */
index 9bff68798836232d51544e21ee3e15409171db11..3a2f88bb33c148d87e4ff0700d67482b360ea4f9 100644 (file)
@@ -16,6 +16,7 @@ obj-y                 := intel_cacheinfo.o scattered.o topology.o
 obj-y                  += common.o
 obj-y                  += rdrand.o
 obj-y                  += match.o
+obj-y                  += spec_ctrl.o
 
 obj-$(CONFIG_PROC_FS)  += proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
diff --git a/arch/x86/kernel/cpu/spec_ctrl.c b/arch/x86/kernel/cpu/spec_ctrl.c
new file mode 100644 (file)
index 0000000..dcfc3c5
--- /dev/null
@@ -0,0 +1,106 @@
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/cpu.h>
+#include <asm/spec_ctrl.h>
+#include <asm/cpufeature.h>
+
+/*
+ * use_ibrs
+ * bit 0 = indicate if ibrs is currently in use
+ * bit 1 = indicate if system supports ibrs
+ * bit 2 = indicate if admin disables ibrs
+ */
+
+static ssize_t __enabled_read(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos, unsigned int *field)
+{
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", READ_ONCE(*field));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ibrs_enabled_read(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       return __enabled_read(file, user_buf, count, ppos, &sysctl_ibrs_enabled);
+}
+
+static void spec_ctrl_flush_all_cpus(u32 msr_nr, u64 val)
+{
+       int cpu;
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               wrmsrl_on_cpu(cpu, msr_nr, val);
+       put_online_cpus();
+}
+
+static ssize_t ibrs_enabled_write(struct file *file,
+                                  const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+        char buf[32];
+        ssize_t len;
+        unsigned int enable;
+
+        len = min(count, sizeof(buf) - 1);
+        if (copy_from_user(buf, user_buf, len))
+                return -EFAULT;
+
+        buf[len] = '\0';
+        if (kstrtouint(buf, 0, &enable))
+                return -EINVAL;
+
+        if (enable > IBRS_MAX)
+                return -EINVAL;
+
+       mutex_lock(&spec_ctrl_mutex);
+
+       if (enable == IBRS_DISABLED) {
+               /* disable IBRS usage */
+               set_ibrs_disabled();
+               if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED)
+                       spec_ctrl_flush_all_cpus(MSR_IA32_SPEC_CTRL, SPEC_CTRL_FEATURE_DISABLE_IBRS);
+       } else if (enable == IBRS_ENABLED) {
+               /* enable IBRS usage in kernel */
+               clear_ibrs_disabled();
+               if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED)
+                       set_ibrs_inuse();
+               else
+                       /* Platform don't support IBRS */
+                       enable = IBRS_DISABLED;
+       } else if (enable == IBRS_ENABLED_USER) {
+               /* enable IBRS usage in both userspace and kernel */
+               clear_ibrs_disabled();
+               /* don't change IBRS value once we set it to always on */
+               clear_ibrs_inuse();
+               if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED)
+                       spec_ctrl_flush_all_cpus(MSR_IA32_SPEC_CTRL, SPEC_CTRL_FEATURE_ENABLE_IBRS);
+               else
+                       /* Platform don't support IBRS */
+                       enable = IBRS_DISABLED;
+       }
+
+       WRITE_ONCE(sysctl_ibrs_enabled, enable);
+
+       mutex_unlock(&spec_ctrl_mutex);
+       return count;
+}
+
+static const struct file_operations fops_ibrs_enabled = {
+        .read = ibrs_enabled_read,
+        .write = ibrs_enabled_write,
+        .llseek = default_llseek,
+};
+
+static int __init debugfs_spec_ctrl(void)
+{
+        debugfs_create_file("ibrs_enabled", S_IRUSR | S_IWUSR,
+                            arch_debugfs_dir, NULL, &fops_ibrs_enabled);
+        return 0;
+}
+late_initcall(debugfs_spec_ctrl);