Michal Suchanek dd997a
From 8ec7791bae1327b1c279c5cd6e929c3b12daaf0a Mon Sep 17 00:00:00 2001
Michal Suchanek dd997a
From: Michael Ellerman <mpe@ellerman.id.au>
Michal Suchanek dd997a
Date: Thu, 6 May 2021 14:49:58 +1000
Michal Suchanek dd997a
Subject: [PATCH] powerpc/64s: Fix crashes when toggling stf barrier
Michal Suchanek dd997a
Michal Suchanek 70f4fd
References: bsc#1087082 git-fixes bsc#1186460 ltc#192531
Michal Suchanek dd997a
Patch-mainline: v5.13-rc2
Michal Suchanek dd997a
Git-commit: 8ec7791bae1327b1c279c5cd6e929c3b12daaf0a
Michal Suchanek dd997a
Michal Suchanek dd997a
The STF (store-to-load forwarding) barrier mitigation can be
Michal Suchanek dd997a
enabled/disabled at runtime via a debugfs file (stf_barrier), which
Michal Suchanek dd997a
causes the kernel to patch itself to enable/disable the relevant
Michal Suchanek dd997a
mitigations.
Michal Suchanek dd997a
Michal Suchanek dd997a
However depending on which mitigation we're using, it may not be safe to
Michal Suchanek dd997a
do that patching while other CPUs are active. For example the following
Michal Suchanek dd997a
crash:
Michal Suchanek dd997a
Michal Suchanek dd997a
  User access of kernel address (c00000003fff5af0) - exploit attempt? (uid: 0)
Michal Suchanek dd997a
  segfault (11) at c00000003fff5af0 nip 7fff8ad12198 lr 7fff8ad121f8 code 1
Michal Suchanek dd997a
  code: 40820128 e93c00d0 e9290058 7c292840 40810058 38600000 4bfd9a81 e8410018
Michal Suchanek dd997a
  code: 2c030006 41810154 3860ffb6 e9210098 <e94d8ff0> 7d295279 39400000 40820a3c
Michal Suchanek dd997a
Michal Suchanek dd997a
Shows that we returned to userspace without restoring the user r13
Michal Suchanek dd997a
value, due to executing the partially patched STF exit code.
Michal Suchanek dd997a
Michal Suchanek dd997a
Fix it by doing the patching under stop machine. The CPUs that aren't
Michal Suchanek dd997a
doing the patching will be spinning in the core of the stop machine
Michal Suchanek dd997a
logic. That is currently sufficient for our purposes, because none of
Michal Suchanek dd997a
the patching we do is to that code or anywhere in the vicinity.
Michal Suchanek dd997a
Michal Suchanek dd997a
Fixes: a048a07d7f45 ("powerpc/64s: Add support for a store forwarding barrier at kernel entry/exit")
Michal Suchanek dd997a
Cc: stable@vger.kernel.org # v4.17+
Michal Suchanek dd997a
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Michal Suchanek dd997a
Link: https://lore.kernel.org/r/20210506044959.1298123-1-mpe@ellerman.id.au
Michal Suchanek dd997a
Acked-by: Michal Suchanek <msuchanek@suse.de>
Michal Suchanek dd997a
---
Michal Suchanek dd997a
 arch/powerpc/lib/feature-fixups.c | 19 +++++++++++++++++--
Michal Suchanek dd997a
 1 file changed, 17 insertions(+), 2 deletions(-)
Michal Suchanek dd997a
Michal Suchanek dd997a
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
Michal Suchanek dd997a
index 1fd31b4b0e13..10083add8b33 100644
Michal Suchanek dd997a
--- a/arch/powerpc/lib/feature-fixups.c
Michal Suchanek dd997a
+++ b/arch/powerpc/lib/feature-fixups.c
Michal Suchanek dd997a
@@ -14,6 +14,7 @@
Michal Suchanek dd997a
 #include <linux/string.h>
Michal Suchanek dd997a
 #include <linux/init.h>
Michal Suchanek dd997a
 #include <linux/sched/mm.h>
Michal Suchanek dd997a
+#include <linux/stop_machine.h>
Michal Suchanek dd997a
 #include <asm/cputable.h>
Michal Suchanek dd997a
 #include <asm/code-patching.h>
Michal Suchanek dd997a
 #include <asm/page.h>
Michal Suchanek dd997a
@@ -227,11 +228,25 @@ static void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
Michal Suchanek dd997a
 		                                           : "unknown");
Michal Suchanek dd997a
 }
Michal Suchanek dd997a
 
Michal Suchanek dd997a
+static int __do_stf_barrier_fixups(void *data)
Michal Suchanek dd997a
+{
Michal Suchanek dd997a
+	enum stf_barrier_type *types = data;
Michal Suchanek dd997a
+
Michal Suchanek dd997a
+	do_stf_entry_barrier_fixups(*types);
Michal Suchanek dd997a
+	do_stf_exit_barrier_fixups(*types);
Michal Suchanek dd997a
+
Michal Suchanek dd997a
+	return 0;
Michal Suchanek dd997a
+}
Michal Suchanek dd997a
 
Michal Suchanek dd997a
 void do_stf_barrier_fixups(enum stf_barrier_type types)
Michal Suchanek dd997a
 {
Michal Suchanek dd997a
-	do_stf_entry_barrier_fixups(types);
Michal Suchanek dd997a
-	do_stf_exit_barrier_fixups(types);
Michal Suchanek dd997a
+	/*
Michal Suchanek dd997a
+	 * The call to the fallback entry flush, and the fallback/sync-ori exit
Michal Suchanek dd997a
+	 * flush can not be safely patched in/out while other CPUs are executing
Michal Suchanek dd997a
+	 * them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs
Michal Suchanek dd997a
+	 * spin in the stop machine core with interrupts hard disabled.
Michal Suchanek dd997a
+	 */
Michal Suchanek dd997a
+	stop_machine(__do_stf_barrier_fixups, &types, NULL);
Michal Suchanek dd997a
 }
Michal Suchanek dd997a
 
Michal Suchanek dd997a
 void do_rfi_flush_fixups(enum l1d_flush_type types)
Michal Suchanek dd997a
-- 
Michal Suchanek dd997a
2.26.2
Michal Suchanek dd997a