Michal Suchanek 49a18f
From aec86b052df6541cc97c5fca44e5934cbea4963b Mon Sep 17 00:00:00 2001
Michal Suchanek 49a18f
From: Michael Ellerman <mpe@ellerman.id.au>
Michal Suchanek 49a18f
Date: Thu, 6 May 2021 14:49:59 +1000
Michal Suchanek 49a18f
Subject: [PATCH] powerpc/64s: Fix crashes when toggling entry flush barrier
Michal Suchanek 49a18f
Michal Suchanek 70f4fd
References: bsc#1177666 git-fixes bsc#1186460 ltc#192531
Michal Suchanek 49a18f
Patch-mainline: v5.13-rc2
Michal Suchanek 49a18f
Git-commit: aec86b052df6541cc97c5fca44e5934cbea4963b
Michal Suchanek 49a18f
Michal Suchanek 49a18f
The entry flush mitigation can be enabled/disabled at runtime via a
Michal Suchanek 49a18f
debugfs file (entry_flush), which causes the kernel to patch itself to
Michal Suchanek 49a18f
enable/disable the relevant mitigations.
Michal Suchanek 49a18f
Michal Suchanek 49a18f
However depending on which mitigation we're using, it may not be safe to
Michal Suchanek 49a18f
do that patching while other CPUs are active. For example the following
Michal Suchanek 49a18f
crash:
Michal Suchanek 49a18f
Michal Suchanek 49a18f
  sleeper[15639]: segfault (11) at c000000000004c20 nip c000000000004c20 lr c000000000004c20
Michal Suchanek 49a18f
Michal Suchanek 49a18f
Shows that we returned to userspace with a corrupted LR that points into
Michal Suchanek 49a18f
the kernel, due to executing the partially patched call to the fallback
Michal Suchanek 49a18f
entry flush (ie. we missed the LR restore).
Michal Suchanek 49a18f
Michal Suchanek 49a18f
Fix it by doing the patching under stop machine. The CPUs that aren't
Michal Suchanek 49a18f
doing the patching will be spinning in the core of the stop machine
Michal Suchanek 49a18f
logic. That is currently sufficient for our purposes, because none of
Michal Suchanek 49a18f
the patching we do is to that code or anywhere in the vicinity.
Michal Suchanek 49a18f
Michal Suchanek 49a18f
Fixes: f79643787e0a ("powerpc/64s: flush L1D on kernel entry")
Michal Suchanek 49a18f
Cc: stable@vger.kernel.org # v5.10+
Michal Suchanek 49a18f
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Michal Suchanek 49a18f
Link: https://lore.kernel.org/r/20210506044959.1298123-2-mpe@ellerman.id.au
Michal Suchanek 49a18f
Acked-by: Michal Suchanek <msuchanek@suse.de>
Michal Suchanek 49a18f
---
Michal Suchanek 49a18f
 arch/powerpc/lib/feature-fixups.c | 16 +++++++++++++++-
Michal Suchanek 49a18f
 1 file changed, 15 insertions(+), 1 deletion(-)
Michal Suchanek 49a18f
Michal Suchanek 49a18f
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
Michal Suchanek 49a18f
index 10083add8b33..0aefa6a4a259 100644
Michal Suchanek 49a18f
--- a/arch/powerpc/lib/feature-fixups.c
Michal Suchanek 49a18f
+++ b/arch/powerpc/lib/feature-fixups.c
Michal Suchanek 49a18f
@@ -299,8 +299,9 @@ void do_uaccess_flush_fixups(enum l1d_flush_type types)
Michal Suchanek 49a18f
 						: "unknown");
Michal Suchanek 49a18f
 }
Michal Suchanek 49a18f
 
Michal Suchanek 49a18f
-void do_entry_flush_fixups(enum l1d_flush_type types)
Michal Suchanek 49a18f
+static int __do_entry_flush_fixups(void *data)
Michal Suchanek 49a18f
 {
Michal Suchanek 49a18f
+	enum l1d_flush_type types = *(enum l1d_flush_type *)data;
Michal Suchanek 49a18f
 	unsigned int instrs[3], *dest;
Michal Suchanek 49a18f
 	long *start, *end;
Michal Suchanek 49a18f
 	int i;
Michal Suchanek 49a18f
@@ -369,6 +370,19 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
Michal Suchanek 49a18f
 							: "ori type" :
Michal Suchanek 49a18f
 		(types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
Michal Suchanek 49a18f
 						: "unknown");
Michal Suchanek 49a18f
+
Michal Suchanek 49a18f
+	return 0;
Michal Suchanek 49a18f
+}
Michal Suchanek 49a18f
+
Michal Suchanek 49a18f
+void do_entry_flush_fixups(enum l1d_flush_type types)
Michal Suchanek 49a18f
+{
Michal Suchanek 49a18f
+	/*
Michal Suchanek 49a18f
+	 * The call to the fallback flush can not be safely patched in/out while
Michal Suchanek 49a18f
+	 * other CPUs are executing it. So call __do_entry_flush_fixups() on one
Michal Suchanek 49a18f
+	 * CPU while all other CPUs spin in the stop machine core with interrupts
Michal Suchanek 49a18f
+	 * hard disabled.
Michal Suchanek 49a18f
+	 */
Michal Suchanek 49a18f
+	stop_machine(__do_entry_flush_fixups, &types, NULL);
Michal Suchanek 49a18f
 }
Michal Suchanek 49a18f
 
Michal Suchanek 49a18f
 void do_rfi_flush_fixups(enum l1d_flush_type types)
Michal Suchanek 49a18f
-- 
Michal Suchanek 49a18f
2.26.2
Michal Suchanek 49a18f