]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
arm64: ssbd: Add prctl interface for per-thread mitigation
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 20 Jul 2018 09:53:08 +0000 (10:53 +0100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 5 Sep 2018 12:53:32 +0000 (14:53 +0200)
BugLink: https://bugs.launchpad.net/bugs/1787993
CVE-2018-3639 (arm64)

commit 9cdc0108baa8ef87c76ed834619886a46bd70cbe upstream.

If running on a system that performs dynamic SSBD mitigation, allow
userspace to request the mitigation for itself. This is implemented
as a prctl call, allowing the mitigation to be enabled or disabled at
will for this particular thread.

Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(backported from commit b769d86ea9d4b2d77387791cc747462b19e8af22
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git /
linux-4.14.y)
Signed-off-by: Paolo Pisati <paolo.pisati@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
arch/arm64/kernel/Makefile
arch/arm64/kernel/ssbd.c [new file with mode: 0644]

index b87541360f43824e6df20961af87a3154f1f7c0f..a403fb488f9fc41f72fe243a31ad4be8b6cb2482 100644 (file)
@@ -53,6 +53,7 @@ arm64-obj-$(CONFIG_ARM64_RELOC_TEST)  += arm64-reloc-test.o
 arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
 arm64-obj-$(CONFIG_CRASH_DUMP)         += crash_dump.o
 arm64-obj-$(CONFIG_ARM_SDE_INTERFACE)  += sdei.o
+arm64-obj-$(CONFIG_ARM64_SSBD)         += ssbd.o
 
 ifeq ($(CONFIG_KVM),y)
 arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR)    += bpi.o
diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c
new file mode 100644 (file)
index 0000000..0560738
--- /dev/null
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+
+#include <asm/cpufeature.h>
+
+/*
+ * prctl interface for SSBD
+ */
+static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
+{
+       int state = arm64_get_ssbd_state();
+
+       /* Unsupported */
+       if (state == ARM64_SSBD_UNKNOWN)
+               return -EINVAL;
+
+       /* Treat the unaffected/mitigated state separately */
+       if (state == ARM64_SSBD_MITIGATED) {
+               switch (ctrl) {
+               case PR_SPEC_ENABLE:
+                       return -EPERM;
+               case PR_SPEC_DISABLE:
+               case PR_SPEC_FORCE_DISABLE:
+                       return 0;
+               }
+       }
+
+       /*
+        * Things are a bit backward here: the arm64 internal API
+        * *enables the mitigation* when the userspace API *disables
+        * speculation*. So much fun.
+        */
+       switch (ctrl) {
+       case PR_SPEC_ENABLE:
+               /* If speculation is force disabled, enable is not allowed */
+               if (state == ARM64_SSBD_FORCE_ENABLE ||
+                   task_spec_ssb_force_disable(task))
+                       return -EPERM;
+               task_clear_spec_ssb_disable(task);
+               clear_tsk_thread_flag(task, TIF_SSBD);
+               break;
+       case PR_SPEC_DISABLE:
+               if (state == ARM64_SSBD_FORCE_DISABLE)
+                       return -EPERM;
+               task_set_spec_ssb_disable(task);
+               set_tsk_thread_flag(task, TIF_SSBD);
+               break;
+       case PR_SPEC_FORCE_DISABLE:
+               if (state == ARM64_SSBD_FORCE_DISABLE)
+                       return -EPERM;
+               task_set_spec_ssb_disable(task);
+               task_set_spec_ssb_force_disable(task);
+               set_tsk_thread_flag(task, TIF_SSBD);
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
+int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
+                            unsigned long ctrl)
+{
+       switch (which) {
+       case PR_SPEC_STORE_BYPASS:
+               return ssbd_prctl_set(task, ctrl);
+       default:
+               return -ENODEV;
+       }
+}
+
+static int ssbd_prctl_get(struct task_struct *task)
+{
+       switch (arm64_get_ssbd_state()) {
+       case ARM64_SSBD_UNKNOWN:
+               return -EINVAL;
+       case ARM64_SSBD_FORCE_ENABLE:
+               return PR_SPEC_DISABLE;
+       case ARM64_SSBD_KERNEL:
+               if (task_spec_ssb_force_disable(task))
+                       return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
+               if (task_spec_ssb_disable(task))
+                       return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
+               return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
+       case ARM64_SSBD_FORCE_DISABLE:
+               return PR_SPEC_ENABLE;
+       default:
+               return PR_SPEC_NOT_AFFECTED;
+       }
+}
+
+int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
+{
+       switch (which) {
+       case PR_SPEC_STORE_BYPASS:
+               return ssbd_prctl_get(task);
+       default:
+               return -ENODEV;
+       }
+}