arm64: Move SSBD prctl() handler alongside other spectre mitigation code
authorWill Deacon <will@kernel.org>
Fri, 18 Sep 2020 10:45:57 +0000 (11:45 +0100)
committerWill Deacon <will@kernel.org>
Tue, 29 Sep 2020 15:08:16 +0000 (16:08 +0100)
As part of the spectre consolidation effort to shift all of the ghosts
into their own proton pack, move all of the horrible SSBD prctl() code
out of its own 'ssbd.c' file.

Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/kernel/Makefile
arch/arm64/kernel/proton-pack.c
arch/arm64/kernel/ssbd.c [deleted file]

index 15b0fcb..bd12b9a 100644 (file)
@@ -19,7 +19,7 @@ obj-y                 := debug-monitors.o entry.o irq.o fpsimd.o              \
                           return_address.o cpuinfo.o cpu_errata.o              \
                           cpufeature.o alternative.o cacheinfo.o               \
                           smp.o smp_spin_table.o topology.o smccc-call.o       \
-                          ssbd.o syscall.o proton-pack.o
+                          syscall.o proton-pack.o
 
 targets                        += efi-entry.o
 
index 4f1411b..b373e47 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/arm-smccc.h>
 #include <linux/cpu.h>
 #include <linux/device.h>
+#include <linux/nospec.h>
 #include <linux/prctl.h>
 
 #include <asm/spectre.h>
@@ -318,3 +319,120 @@ void spectre_v2_enable_mitigation(const struct arm64_cpu_capabilities *__unused)
 
        update_mitigation_state(&spectre_v2_state, state);
 }
+
+/* Spectre v4 prctl */
+static void ssbd_ssbs_enable(struct task_struct *task)
+{
+       u64 val = is_compat_thread(task_thread_info(task)) ?
+                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
+
+       task_pt_regs(task)->pstate |= val;
+}
+
+static void ssbd_ssbs_disable(struct task_struct *task)
+{
+       u64 val = is_compat_thread(task_thread_info(task)) ?
+                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
+
+       task_pt_regs(task)->pstate &= ~val;
+}
+
+/*
+ * 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 -ENODEV;
+
+       /* 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);
+               ssbd_ssbs_enable(task);
+               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);
+               ssbd_ssbs_disable(task);
+               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);
+               ssbd_ssbs_disable(task);
+               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 -ENODEV;
+       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;
+       }
+}
diff --git a/arch/arm64/kernel/ssbd.c b/arch/arm64/kernel/ssbd.c
deleted file mode 100644 (file)
index b26955f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2018 ARM Ltd, All Rights Reserved.
- */
-
-#include <linux/compat.h>
-#include <linux/errno.h>
-#include <linux/prctl.h>
-#include <linux/sched.h>
-#include <linux/sched/task_stack.h>
-#include <linux/thread_info.h>
-
-#include <asm/cpufeature.h>
-
-static void ssbd_ssbs_enable(struct task_struct *task)
-{
-       u64 val = is_compat_thread(task_thread_info(task)) ?
-                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
-
-       task_pt_regs(task)->pstate |= val;
-}
-
-static void ssbd_ssbs_disable(struct task_struct *task)
-{
-       u64 val = is_compat_thread(task_thread_info(task)) ?
-                 PSR_AA32_SSBS_BIT : PSR_SSBS_BIT;
-
-       task_pt_regs(task)->pstate &= ~val;
-}
-
-/*
- * 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 -ENODEV;
-
-       /* 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);
-               ssbd_ssbs_enable(task);
-               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);
-               ssbd_ssbs_disable(task);
-               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);
-               ssbd_ssbs_disable(task);
-               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 -ENODEV;
-       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;
-       }
-}