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