[PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec

Benjamin Gray bgray at linux.ibm.com
Wed Apr 17 21:23:19 AEST 2024


Inheriting the DEXCR across exec can have security and usability
concerns. If a program is compiled with hash instructions it generally
expects to run with NPHIE enabled. But if the parent process disables
NPHIE then if it's not careful it will be disabled for any children too
and the protection offered by hash checks is basically worthless.

This patch introduces a per-process reset value that new execs in a
particular process tree are initialized with. This enables fine grained
control over what DEXCR value child processes run with by default. For
example, containers running legacy binaries that expect hash
instructions to act as NOPs could configure the reset value of the
container root to control the default reset value for all members of the
container.

Signed-off-by: Benjamin Gray <bgray at linux.ibm.com>

---

This differs from the previous iterations by making the reset value
totally independent of the process's current DEXCR value. The original
iterations stored an 'inherit' bitmask, where the mask decides which of
the current DEXCR aspects are kept across exec, and the others are reset
to a fixed default.

That approach has a flaw when trying to prevent unauthorized inherited
hash check disabling. With a hierarchy A -> B -> C of process execs,
suppose A is privileged and enables NPHIE as an inherited aspect. If B
is unprivileged but clears its NPHIE aspect, the clear is
unintentionally inherited down to C as well (which may be setuid).

This new approach lets processes control the reset value directly
without any reference to the values the process itself is using.
Compared to the original approach, we don't run into an issue where an
unprivileged middle child ever controls the reset value.
---
 arch/powerpc/include/asm/processor.h |  2 +-
 arch/powerpc/kernel/Makefile         |  1 +
 arch/powerpc/kernel/dexcr.c          | 21 +++++++++++++++++++++
 arch/powerpc/kernel/process.c        |  7 +++++++
 4 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/kernel/dexcr.c

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 882e31296ea6..aad85a24134a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -261,7 +261,7 @@ struct thread_struct {
 	unsigned long   sier3;
 	unsigned long	hashkeyr;
 	unsigned long	dexcr;
-
+	unsigned long	dexcr_onexec;	/* Reset value to load on exec */
 #endif
 };
 
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index d3282fbea4f2..1d183b077948 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_PPC_DAWR)		+= dawr.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)	+= dexcr.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= mce.o mce_power.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_64e.o
 obj-$(CONFIG_PPC_BARRIER_NOSPEC) += security.o
diff --git a/arch/powerpc/kernel/dexcr.c b/arch/powerpc/kernel/dexcr.c
new file mode 100644
index 000000000000..f65c359968cc
--- /dev/null
+++ b/arch/powerpc/kernel/dexcr.c
@@ -0,0 +1,21 @@
+#include <linux/capability.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+
+#include <asm/cpu_has_feature.h>
+#include <asm/cputable.h>
+#include <asm/processor.h>
+#include <asm/reg.h>
+
+static int __init init_task_dexcr(void)
+{
+	if (!early_cpu_has_feature(CPU_FTR_ARCH_31))
+		return 0;
+
+	current->thread.dexcr_onexec = mfspr(SPRN_DEXCR);
+
+	return 0;
+}
+early_initcall(init_task_dexcr)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index d482c3fd81d7..8ab779a3bdde 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1641,6 +1641,13 @@ void arch_setup_new_exec(void)
 	current->thread.regs->amr  = default_amr;
 	current->thread.regs->iamr  = default_iamr;
 #endif
+
+#ifdef CONFIG_PPC_BOOK3S_64
+	if (cpu_has_feature(CPU_FTR_ARCH_31)) {
+		current->thread.dexcr = current->thread.dexcr_onexec;
+		mtspr(SPRN_DEXCR, current->thread.dexcr);
+	}
+#endif /* CONFIG_PPC_BOOK3S_64 */
 }
 
 #ifdef CONFIG_PPC64
-- 
2.44.0



More information about the Linuxppc-dev mailing list