]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
x86/speculation/mds: Add debugfs for controlling MDS
authorKanth Ghatraju <kanth.ghatraju@oracle.com>
Thu, 28 Mar 2019 17:57:23 +0000 (13:57 -0400)
committerMihai Carabas <mihai.carabas@oracle.com>
Mon, 22 Apr 2019 18:16:18 +0000 (21:16 +0300)
Add debugfs entries for controlling mds_user_clear and mds_idle_clear static
keys which would enable the mitigation in the respective paths.

Orabug: 29526900
CVE: CVE-2018-12126
CVE: CVE-2018-12130
CVE: CVE-2018-12127

Signed-off-by: Kanth Ghatraju <kanth.ghatraju@oracle.com>
Reviewed-by: Mihai Carabas <mihai.carabas@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
arch/x86/include/asm/processor.h
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/bugs_64.c
arch/x86/kernel/cpu/mds_ctrl.c [new file with mode: 0644]

index fe7e5df41236891d39bf7c0bebc268abb3aa95c5..0c86d0aa513a58f8aba6e8e7168b19fdb8f2f0bc 100644 (file)
@@ -1021,6 +1021,13 @@ enum l1tf_mitigations {
 
 extern enum l1tf_mitigations l1tf_mitigation;
 
+extern void mds_idle_clear_enable(void);
+extern void mds_idle_clear_disable(void);
+extern void mds_user_clear_enable(void);
+extern void mds_user_clear_disable(void);
+extern bool mds_user_clear_enabled(void);
+extern bool mds_idle_clear_enabled(void);
+
 enum mds_mitigations {
        MDS_MITIGATION_OFF,
        MDS_MITIGATION_FULL,
index 3a2f88bb33c148d87e4ff0700d67482b360ea4f9..949e766ca7f7f2b81d69bc6d1faff991f3e0b593 100644 (file)
@@ -17,6 +17,7 @@ obj-y                 += common.o
 obj-y                  += rdrand.o
 obj-y                  += match.o
 obj-y                  += spec_ctrl.o
+obj-y                  += mds_ctrl.o
 
 obj-$(CONFIG_PROC_FS)  += proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
index 7babe5d1c4b2f97b3adbfe1691f0f416c23ce147..82c1506caf96a48f0405cf3a17d8755c6cd8356b 100644 (file)
@@ -1287,6 +1287,36 @@ static void __init l1tf_select_mitigation(void)
 #undef pr_fmt
 #define pr_fmt(fmt)    "MDS: " fmt
 
+bool mds_user_clear_enabled(void)
+{
+        return static_key_enabled(&mds_user_clear);
+}
+
+void mds_user_clear_enable(void)
+{
+       static_branch_enable(&mds_user_clear);
+}
+
+void mds_user_clear_disable(void)
+{
+       static_branch_disable(&mds_user_clear);
+}
+
+bool mds_idle_clear_enabled(void)
+{
+        return static_key_enabled(&mds_idle_clear);
+}
+
+void mds_idle_clear_enable(void)
+{
+       static_branch_enable(&mds_idle_clear);
+}
+
+void mds_idle_clear_disable(void)
+{
+       static_branch_disable(&mds_idle_clear);
+}
+
 /* Default mitigation for L1TF-affected CPUs */
 static enum mds_mitigations mds_mitigation __read_mostly = MDS_MITIGATION_FULL;
 
diff --git a/arch/x86/kernel/cpu/mds_ctrl.c b/arch/x86/kernel/cpu/mds_ctrl.c
new file mode 100644 (file)
index 0000000..604b379
--- /dev/null
@@ -0,0 +1,118 @@
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/cpu.h>
+#include <asm/nospec-branch.h>
+#include <asm/cpufeature.h>
+#include <asm/microcode.h>
+
+static ssize_t __enabled_read(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos, unsigned int *field)
+{
+       char buf[2] = {'0', '\n'};;
+
+       if (*field)
+               buf[0] = '1';
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t mds_key_read(struct file *file,
+                                  char __user *user_buf,
+                                  size_t count, loff_t *ppos,
+                                  bool (*enabled_func) (void))
+{
+       u32 sysctl_mds_key = (*enabled_func)() ? 1 : 0;
+
+       return __enabled_read(file, user_buf, count, ppos,
+                             &sysctl_mds_key);
+}
+
+static ssize_t mds_key_write(struct file *file,
+                            const char __user *user_buf,
+                            size_t count, loff_t *ppos,
+                            void (*enable_func) (void),
+                            void (*disable_func) (void))
+{
+       char buf[2];
+       ssize_t len = 1;
+       unsigned int enable;
+
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtouint(buf, 0, &enable))
+               return -EINVAL;
+
+       /* Only 0 and 1 are allowed */
+       if (enable > 1)
+               return -EINVAL;
+
+       if (enable)
+               (*enable_func)();
+       else
+               (*disable_func)();
+
+       return count;
+}
+
+static ssize_t mds_idle_clear_read(struct file *file,
+                                  char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       return mds_key_read(file, user_buf, count, ppos,
+                           mds_idle_clear_enabled);
+}
+
+static ssize_t mds_user_clear_read(struct file *file,
+                                  char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       return mds_key_read(file, user_buf, count, ppos,
+                           mds_user_clear_enabled);
+}
+
+static ssize_t mds_user_clear_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       return mds_key_write(file, user_buf, count, ppos,
+                            mds_user_clear_enable,
+                            mds_user_clear_disable);
+}
+
+static ssize_t mds_idle_clear_write(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       return mds_key_write(file, user_buf, count, ppos,
+                            mds_idle_clear_enable,
+                            mds_idle_clear_disable);
+}
+
+static const struct file_operations fops_mds_user_clear = {
+       .read = mds_user_clear_read,
+       .write = mds_user_clear_write,
+       .llseek = default_llseek,
+};
+
+static const struct file_operations fops_mds_idle_clear = {
+       .read = mds_idle_clear_read,
+       .write = mds_idle_clear_write,
+       .llseek = default_llseek,
+};
+
+static int __init debugfs_mds_ctrl(void)
+{
+       debugfs_create_file("mds_user_clear",
+                          0600, arch_debugfs_dir, NULL,
+                          &fops_mds_user_clear);
+       debugfs_create_file("mds_idle_clear",
+                          0600, arch_debugfs_dir, NULL,
+                          &fops_mds_idle_clear);
+        return 0;
+}
+
+late_initcall(debugfs_mds_ctrl);