linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/9] Add dynamic DEXCR support
@ 2024-04-17 11:23 Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
                   ` (9 more replies)
  0 siblings, 10 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Adds support for a process to change its DEXCR value. The implementation is
somewhat conservative; SBHE (speculative branch hint enable) is not exposed
as an editable aspect because its effects can bleed over to other threads.

As explained in the third patch, this series changes the reset/inherit
behaviour on exec. Previously there was a bitmask that tracked which aspects
to copy from the current state vs resetting to a fixed default. This
allows unprivileged processes to disable ROP protection for setuid binaries
though, and is generally a weird interface to work with. The actual intent
(and new implementation) tracks the exec value as an independent value that
doesn't use the parent's DEXCR at all. The parent can control this reset value
separately to its own DEXCR value.

The other interesting part is the prctl interface. I've made the _SET, _CLEAR,
_SET_ONEXEC, and _CLEAR_ONEXEC controls each a separate flag. This makes it
easier to re-use with the getter prctl, as opposed to making set/clear a boolean
value with a separate flag for if it's 'on-exec'. With separate flags you can
return both the current and on-exec state in the getter in the same way you'd
prepare it for the setter.

There are still more features that can be added. A global switch to disable
ROP protection could be useful as an option to prevent performance degradation.
Also a prctl to randomise the hash key could be useful for when userspace knows
a fork is not going to run any parent hashes. These features could be added in
a future series (or the next version of this one :) ) though.

Benjamin Gray (9):
  selftests/powerpc/dexcr: Add -no-pie to hashchk tests
  powerpc/dexcr: Track the DEXCR per-process
  powerpc/dexcr: Reset DEXCR value across exec
  powerpc/dexcr: Add DEXCR prctl interface
  selftests/powerpc/dexcr: Add DEXCR prctl interface test
  selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest
  selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr
  selftests/powerpc/dexcr: Add chdexcr utility
  Documentation: Document PowerPC kernel dynamic DEXCR interface

 Documentation/arch/powerpc/dexcr.rst          | 141 +++++++++++-
 arch/powerpc/include/asm/processor.h          |  13 +-
 arch/powerpc/kernel/Makefile                  |   1 +
 arch/powerpc/kernel/dexcr.c                   | 120 ++++++++++
 arch/powerpc/kernel/process.c                 |  17 ++
 arch/powerpc/kernel/ptrace/ptrace-view.c      |   7 +-
 include/uapi/linux/prctl.h                    |  16 ++
 kernel/sys.c                                  |  16 ++
 .../selftests/powerpc/dexcr/.gitignore        |   2 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   8 +-
 .../testing/selftests/powerpc/dexcr/chdexcr.c | 110 +++++++++
 tools/testing/selftests/powerpc/dexcr/dexcr.c |  40 ++++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |  57 +++++
 .../selftests/powerpc/dexcr/dexcr_test.c      | 213 ++++++++++++++++++
 .../selftests/powerpc/dexcr/hashchk_test.c    |   8 +-
 .../testing/selftests/powerpc/dexcr/lsdexcr.c | 103 ++++++---
 16 files changed, 823 insertions(+), 49 deletions(-)
 create mode 100644 arch/powerpc/kernel/dexcr.c
 create mode 100644 tools/testing/selftests/powerpc/dexcr/chdexcr.c
 create mode 100644 tools/testing/selftests/powerpc/dexcr/dexcr_test.c

--
2.44.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-05-07  7:44   ` Andrew Donnellan
  2024-04-17 11:23 ` [PATCH v1 2/9] powerpc/dexcr: Track the DEXCR per-process Benjamin Gray
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

The hashchk tests want to verify that the hash key is changed over exec.
It does so by calculating hashes at the same address across an exec.
This is made simpler by disabling PIE functionality, so we can
re-execute ourselves and be using the same addresses in the child.

While -fno-pie is already added, -no-pie is also required.

Fixes: ca64da7574f8 ("selftests/powerpc/dexcr: Add hashst/hashchk test")
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>

---

This is not related to features introduced in this series, just fixes
the test added in the static DEXCR series.
---
 tools/testing/selftests/powerpc/dexcr/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 76210f2bcec3..829ad075b4a4 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -3,7 +3,7 @@ TEST_GEN_FILES := lsdexcr
 
 include ../../lib.mk
 
-$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie $(call cc-option,-mno-rop-protect)
+$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-option,-mno-rop-protect)
 
 $(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
 $(TEST_GEN_FILES): ../utils.c ./dexcr.c
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 2/9] powerpc/dexcr: Track the DEXCR per-process
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec Benjamin Gray
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Add capability to make the DEXCR act as a per-process SPR.

We do not yet have an interface for changing the values per task. We
also expect the kernel to use a single DEXCR value across all tasks
while in privileged state, so there is no need to synchronize after
changing it (the userspace aspects will synchronize upon returning to
userspace).

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 arch/powerpc/include/asm/processor.h     |  1 +
 arch/powerpc/kernel/process.c            | 10 ++++++++++
 arch/powerpc/kernel/ptrace/ptrace-view.c |  7 +------
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b2c51d337e60..882e31296ea6 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -260,6 +260,7 @@ struct thread_struct {
 	unsigned long   sier2;
 	unsigned long   sier3;
 	unsigned long	hashkeyr;
+	unsigned long	dexcr;
 
 #endif
 };
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 9452a54d356c..d482c3fd81d7 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1185,6 +1185,9 @@ static inline void save_sprs(struct thread_struct *t)
 
 	if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE))
 		t->hashkeyr = mfspr(SPRN_HASHKEYR);
+
+	if (cpu_has_feature(CPU_FTR_ARCH_31))
+		t->dexcr = mfspr(SPRN_DEXCR);
 #endif
 }
 
@@ -1267,6 +1270,10 @@ static inline void restore_sprs(struct thread_struct *old_thread,
 	if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) &&
 	    old_thread->hashkeyr != new_thread->hashkeyr)
 		mtspr(SPRN_HASHKEYR, new_thread->hashkeyr);
+
+	if (cpu_has_feature(CPU_FTR_ARCH_31) &&
+	    old_thread->dexcr != new_thread->dexcr)
+		mtspr(SPRN_DEXCR, new_thread->dexcr);
 #endif
 
 }
@@ -1878,6 +1885,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 #ifdef CONFIG_PPC_BOOK3S_64
 	if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE))
 		p->thread.hashkeyr = current->thread.hashkeyr;
+
+	if (cpu_has_feature(CPU_FTR_ARCH_31))
+		p->thread.dexcr = mfspr(SPRN_DEXCR);
 #endif
 	return 0;
 }
diff --git a/arch/powerpc/kernel/ptrace/ptrace-view.c b/arch/powerpc/kernel/ptrace/ptrace-view.c
index 584cf5c3df50..c1819e0a6684 100644
--- a/arch/powerpc/kernel/ptrace/ptrace-view.c
+++ b/arch/powerpc/kernel/ptrace/ptrace-view.c
@@ -469,12 +469,7 @@ static int dexcr_get(struct task_struct *target, const struct user_regset *regse
 	if (!cpu_has_feature(CPU_FTR_ARCH_31))
 		return -ENODEV;
 
-	/*
-	 * The DEXCR is currently static across all CPUs, so we don't
-	 * store the target's value anywhere, but the static value
-	 * will also be correct.
-	 */
-	membuf_store(&to, (u64)lower_32_bits(DEXCR_INIT));
+	membuf_store(&to, (u64)lower_32_bits(target->thread.dexcr));
 
 	/*
 	 * Technically the HDEXCR is per-cpu, but a hypervisor can't reasonably
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 2/9] powerpc/dexcr: Track the DEXCR per-process Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 4/9] powerpc/dexcr: Add DEXCR prctl interface Benjamin Gray
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

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@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


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 4/9] powerpc/dexcr: Add DEXCR prctl interface
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (2 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test Benjamin Gray
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Now that we track a DEXCR on a per-task basis, individual tasks are free
to configure it as they like.

The interface is a pair of getter/setter prctl's that work on a single
aspect at a time (multiple aspects at once is more difficult if there
are different rules applied for each aspect, now or in future). The
getter shows the current state of the process config, and the setter
allows setting/clearing the aspect.

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

---

I'm intentionally trying to avoid saying 'enabling' or 'disabling' the
aspect, as that could be confusing when the aspects themselves may
'enable' or 'disable' their feature when the aspect is set.
---
 arch/powerpc/include/asm/processor.h | 10 +++
 arch/powerpc/kernel/dexcr.c          | 99 ++++++++++++++++++++++++++++
 include/uapi/linux/prctl.h           | 16 +++++
 kernel/sys.c                         | 16 +++++
 4 files changed, 141 insertions(+)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index aad85a24134a..e44cac0da346 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -334,6 +334,16 @@ extern int set_endian(struct task_struct *tsk, unsigned int val);
 extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
 extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
 
+#ifdef CONFIG_PPC_BOOK3S_64
+
+#define PPC_GET_DEXCR_ASPECT(tsk, asp) get_dexcr_prctl((tsk), (asp))
+#define PPC_SET_DEXCR_ASPECT(tsk, asp, val) set_dexcr_prctl((tsk), (asp), (val))
+
+int get_dexcr_prctl(struct task_struct *tsk, unsigned long asp);
+int set_dexcr_prctl(struct task_struct *tsk, unsigned long asp, unsigned long val);
+
+#endif
+
 extern void load_fp_state(struct thread_fp_state *fp);
 extern void store_fp_state(struct thread_fp_state *fp);
 extern void load_vr_state(struct thread_vr_state *vr);
diff --git a/arch/powerpc/kernel/dexcr.c b/arch/powerpc/kernel/dexcr.c
index f65c359968cc..f50247b3daa1 100644
--- a/arch/powerpc/kernel/dexcr.c
+++ b/arch/powerpc/kernel/dexcr.c
@@ -19,3 +19,102 @@ static int __init init_task_dexcr(void)
 	return 0;
 }
 early_initcall(init_task_dexcr)
+
+/* Allow thread local configuration of these by default */
+#define DEXCR_PRCTL_EDITABLE ( \
+	DEXCR_PR_IBRTPD | \
+	DEXCR_PR_SRAPD | \
+	DEXCR_PR_NPHIE)
+
+static int prctl_to_aspect(unsigned long which, unsigned int *aspect)
+{
+	switch (which) {
+	case PR_PPC_DEXCR_SBHE:
+		*aspect = DEXCR_PR_SBHE;
+		break;
+	case PR_PPC_DEXCR_IBRTPD:
+		*aspect = DEXCR_PR_IBRTPD;
+		break;
+	case PR_PPC_DEXCR_SRAPD:
+		*aspect = DEXCR_PR_SRAPD;
+		break;
+	case PR_PPC_DEXCR_NPHIE:
+		*aspect = DEXCR_PR_NPHIE;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+int get_dexcr_prctl(struct task_struct *task, unsigned long which)
+{
+	unsigned int aspect;
+	int ret;
+
+	ret = prctl_to_aspect(which, &aspect);
+	if (ret)
+		return ret;
+
+	if (aspect & DEXCR_PRCTL_EDITABLE)
+		ret |= PR_PPC_DEXCR_CTRL_EDITABLE;
+
+	if (aspect & mfspr(SPRN_DEXCR))
+		ret |= PR_PPC_DEXCR_CTRL_SET;
+	else
+		ret |= PR_PPC_DEXCR_CTRL_CLEAR;
+
+	if (aspect & task->thread.dexcr_onexec)
+		ret |= PR_PPC_DEXCR_CTRL_SET_ONEXEC;
+	else
+		ret |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC;
+
+	return ret;
+}
+
+int set_dexcr_prctl(struct task_struct *task, unsigned long which, unsigned long ctrl)
+{
+	unsigned long dexcr;
+	unsigned int aspect;
+	int err = 0;
+
+	err = prctl_to_aspect(which, &aspect);
+	if (err)
+		return err;
+
+	if (!(aspect & DEXCR_PRCTL_EDITABLE))
+		return -EPERM;
+
+	if (ctrl & ~PR_PPC_DEXCR_CTRL_MASK)
+		return -EINVAL;
+
+	if (ctrl & PR_PPC_DEXCR_CTRL_SET && ctrl & PR_PPC_DEXCR_CTRL_CLEAR)
+		return -EINVAL;
+
+	if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC && ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC)
+		return -EINVAL;
+
+	/*
+	 * We do not want an unprivileged process being able to disable
+	 * a setuid process's hash check instructions
+	 */
+	if (aspect == DEXCR_PR_NPHIE && ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC && !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	dexcr = mfspr(SPRN_DEXCR);
+
+	if (ctrl & PR_PPC_DEXCR_CTRL_SET)
+		dexcr |= aspect;
+	else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR)
+		dexcr &= ~aspect;
+
+	if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC)
+		task->thread.dexcr_onexec |= aspect;
+	else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC)
+		task->thread.dexcr_onexec &= ~aspect;
+
+	mtspr(SPRN_DEXCR, dexcr);
+
+	return 0;
+}
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 370ed14b1ae0..3ffd463ac8fe 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -306,4 +306,20 @@ struct prctl_mm_map {
 # define PR_RISCV_V_VSTATE_CTRL_NEXT_MASK	0xc
 # define PR_RISCV_V_VSTATE_CTRL_MASK		0x1f
 
+/* PowerPC Dynamic Execution Control Register (DEXCR) controls */
+#define PR_PPC_GET_DEXCR		71
+#define PR_PPC_SET_DEXCR		72
+/* DEXCR aspect to act on */
+# define PR_PPC_DEXCR_SBHE		0 /* Speculative branch hint enable */
+# define PR_PPC_DEXCR_IBRTPD		1 /* Indirect branch recurrent target prediction disable */
+# define PR_PPC_DEXCR_SRAPD		2 /* Subroutine return address prediction disable */
+# define PR_PPC_DEXCR_NPHIE		3 /* Non-privileged hash instruction enable */
+/* Action to apply / return */
+# define PR_PPC_DEXCR_CTRL_EDITABLE		(1UL << 0) /* This aspect can be modified with PR_PPC_SET_DEXCR */
+# define PR_PPC_DEXCR_CTRL_SET			(1UL << 1) /* Set the aspect for this process */
+# define PR_PPC_DEXCR_CTRL_CLEAR		(1UL << 2) /* Clear the aspect for this process */
+# define PR_PPC_DEXCR_CTRL_SET_ONEXEC		(1UL << 3) /* Set the aspect on exec */
+# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC		(1UL << 4) /* Clear the aspect on exec */
+# define PR_PPC_DEXCR_CTRL_MASK			0x1f
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 8bb106a56b3a..f9c95410278c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -146,6 +146,12 @@
 #ifndef RISCV_V_GET_CONTROL
 # define RISCV_V_GET_CONTROL()		(-EINVAL)
 #endif
+#ifndef PPC_GET_DEXCR_ASPECT
+# define PPC_GET_DEXCR_ASPECT(a, b)	(-EINVAL)
+#endif
+#ifndef PPC_SET_DEXCR_ASPECT
+# define PPC_SET_DEXCR_ASPECT(a, b, c)	(-EINVAL)
+#endif
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -2726,6 +2732,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_GET_MDWE:
 		error = prctl_get_mdwe(arg2, arg3, arg4, arg5);
 		break;
+	case PR_PPC_GET_DEXCR:
+		if (arg3 || arg4 || arg5)
+			return -EINVAL;
+		error = PPC_GET_DEXCR_ASPECT(me, arg2);
+		break;
+	case PR_PPC_SET_DEXCR:
+		if (arg4 || arg5)
+			return -EINVAL;
+		error = PPC_SET_DEXCR_ASPECT(me, arg2, arg3);
+		break;
 	case PR_SET_VMA:
 		error = prctl_set_vma(arg2, arg3, arg4, arg5);
 		break;
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (3 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 4/9] powerpc/dexcr: Add DEXCR prctl interface Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest Benjamin Gray
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Some basic tests of the prctl interface of the DEXCR.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../selftests/powerpc/dexcr/.gitignore        |   1 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   4 +-
 tools/testing/selftests/powerpc/dexcr/dexcr.c |  40 ++++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |  10 +
 .../selftests/powerpc/dexcr/dexcr_test.c      | 213 ++++++++++++++++++
 5 files changed, 267 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/dexcr/dexcr_test.c

diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore
index b82f45dd46b9..5d526613cd26 100644
--- a/tools/testing/selftests/powerpc/dexcr/.gitignore
+++ b/tools/testing/selftests/powerpc/dexcr/.gitignore
@@ -1,2 +1,3 @@
+dexcr_test
 hashchk_test
 lsdexcr
diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 829ad075b4a4..076943193c07 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -1,8 +1,10 @@
-TEST_GEN_PROGS := hashchk_test
+TEST_GEN_PROGS := dexcr_test hashchk_test
 TEST_GEN_FILES := lsdexcr
 
 include ../../lib.mk
 
+CFLAGS += $(KHDR_INCLUDES)
+
 $(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-option,-mno-rop-protect)
 
 $(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.c b/tools/testing/selftests/powerpc/dexcr/dexcr.c
index 65ec5347de98..468fd0dc9912 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.c
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.c
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <setjmp.h>
 #include <signal.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -43,6 +44,45 @@ bool dexcr_exists(void)
 	return exists;
 }
 
+unsigned int pr_which_to_aspect(unsigned long which)
+{
+	switch (which) {
+	case PR_PPC_DEXCR_SBHE:
+		return DEXCR_PR_SBHE;
+	case PR_PPC_DEXCR_IBRTPD:
+		return DEXCR_PR_IBRTPD;
+	case PR_PPC_DEXCR_SRAPD:
+		return DEXCR_PR_SRAPD;
+	case PR_PPC_DEXCR_NPHIE:
+		return DEXCR_PR_NPHIE;
+	default:
+		FAIL_IF_EXIT_MSG(true, "unknown PR aspect");
+	}
+}
+
+int pr_get_dexcr(unsigned long which)
+{
+	return prctl(PR_PPC_GET_DEXCR, which, 0UL, 0UL, 0UL);
+}
+
+int pr_set_dexcr(unsigned long which, unsigned long ctrl)
+{
+	return prctl(PR_PPC_SET_DEXCR, which, ctrl, 0UL, 0UL);
+}
+
+bool pr_dexcr_aspect_supported(unsigned long which)
+{
+	if (pr_get_dexcr(which) == -1)
+		return errno == ENODEV;
+
+	return true;
+}
+
+bool pr_dexcr_aspect_editable(unsigned long which)
+{
+	return pr_get_dexcr(which) & PR_PPC_DEXCR_CTRL_EDITABLE;
+}
+
 /*
  * Just test if a bad hashchk triggers a signal, without checking
  * for support or if the NPHIE aspect is enabled.
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h
index f55cbbc8643b..a6aa7eac11da 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.h
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h
@@ -28,6 +28,16 @@
 
 bool dexcr_exists(void);
 
+bool pr_dexcr_aspect_supported(unsigned long which);
+
+bool pr_dexcr_aspect_editable(unsigned long which);
+
+int pr_get_dexcr(unsigned long pr_aspect);
+
+int pr_set_dexcr(unsigned long pr_aspect, unsigned long ctrl);
+
+unsigned int pr_which_to_aspect(unsigned long which);
+
 bool hashchk_triggers(void);
 
 enum dexcr_source {
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr_test.c b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
new file mode 100644
index 000000000000..4662c823a4f1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr_test.c
@@ -0,0 +1,213 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "dexcr.h"
+#include "utils.h"
+
+/*
+ * Helper function for testing the behaviour of a newly exec-ed process
+ */
+static int dexcr_prctl_onexec_test_child(unsigned long which, const char *status)
+{
+	unsigned long dexcr = mfspr(SPRN_DEXCR_RO);
+	unsigned long aspect = pr_which_to_aspect(which);
+	int ctrl = pr_get_dexcr(which);
+
+	if (!strcmp(status, "set")) {
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET),
+				 "setting aspect across exec not applied");
+
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC),
+				 "setting aspect across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(!(aspect & dexcr), "setting aspect across exec did not take effect");
+	} else if (!strcmp(status, "clear")) {
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR),
+				 "clearing aspect across exec not applied");
+
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC),
+				 "clearing aspect across exec not inherited");
+
+		FAIL_IF_EXIT_MSG(aspect & dexcr, "clearing aspect across exec did not take effect");
+	} else {
+		FAIL_IF_EXIT_MSG(true, "unknown expected status");
+	}
+
+	return 0;
+}
+
+/*
+ * Test that the given prctl value can be manipulated freely
+ */
+static int dexcr_prctl_aspect_test(unsigned long which)
+{
+	unsigned long aspect = pr_which_to_aspect(which);
+	pid_t pid;
+	int ctrl;
+	int err;
+	int errno_save;
+
+	SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported");
+	SKIP_IF_MSG(!pr_dexcr_aspect_supported(which), "DEXCR aspect not supported");
+	SKIP_IF_MSG(!pr_dexcr_aspect_editable(which), "DEXCR aspect not editable with prctl");
+
+	/* We reject invalid combinations of arguments */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR);
+	errno_save = errno;
+	FAIL_IF_MSG(err != -1, "simultaneous set and clear should be rejected");
+	FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear should be rejected with EINVAL");
+
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
+	errno_save = errno;
+	FAIL_IF_MSG(err != -1, "simultaneous set and clear on exec should be rejected");
+	FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear on exec should be rejected with EINVAL");
+
+	/* We set the aspect */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET");
+	FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR, "config value unexpected clear flag");
+	FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "setting aspect did not take effect");
+
+	/* We clear the aspect */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR");
+	FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET, "config value unexpected set flag");
+	FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "clearing aspect did not take effect");
+
+	/* We make it set on exec (doesn't change our current value) */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET_ONEXEC failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect should still be cleared");
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC");
+	FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC, "config value unexpected clear on exec flag");
+	FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "scheduling aspect to set on exec should not change it now");
+
+	/* We make it clear on exec (doesn't change our current value) */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect config should still be cleared");
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC");
+	FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC, "config value unexpected set on exec flag");
+	FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should still be cleared");
+
+	/* We allow setting the current and on-exec value in a single call */
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET");
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC");
+	FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "process aspect should be set");
+
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC failed");
+
+	ctrl = pr_get_dexcr(which);
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR");
+	FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC");
+	FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should be clear");
+
+	/* Verify the onexec value is applied across exec */
+	pid = fork();
+	if (!pid) {
+		char which_str[32] = {};
+		char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "set", NULL };
+		unsigned int ctrl = pr_get_dexcr(which);
+
+		sprintf(which_str, "%lu", which);
+
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC),
+				 "setting aspect on exec not copied across fork");
+
+		FAIL_IF_EXIT_MSG(mfspr(SPRN_DEXCR_RO) & aspect,
+				 "setting aspect on exec wrongly applied to fork");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
+	FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
+
+	pid = fork();
+	if (!pid) {
+		char which_str[32] = {};
+		char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "clear", NULL };
+		unsigned int ctrl = pr_get_dexcr(which);
+
+		sprintf(which_str, "%lu", which);
+
+		FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC),
+				 "clearing aspect on exec not copied across fork");
+
+		FAIL_IF_EXIT_MSG(!(mfspr(SPRN_DEXCR_RO) & aspect),
+				 "clearing aspect on exec wrongly applied to fork");
+
+		execve("/proc/self/exe", args, NULL);
+		_exit(errno);
+	}
+	await_child_success(pid);
+
+	return 0;
+}
+
+static int dexcr_prctl_ibrtpd_test(void)
+{
+	return dexcr_prctl_aspect_test(PR_PPC_DEXCR_IBRTPD);
+}
+
+static int dexcr_prctl_srapd_test(void)
+{
+	return dexcr_prctl_aspect_test(PR_PPC_DEXCR_SRAPD);
+}
+
+static int dexcr_prctl_nphie_test(void)
+{
+	return dexcr_prctl_aspect_test(PR_PPC_DEXCR_NPHIE);
+}
+
+int main(int argc, char *argv[])
+{
+	int err = 0;
+
+	/*
+	 * Some tests require checking what happens across exec, so we may be
+	 * invoked as the child of a particular test
+	 */
+	if (argc > 1) {
+		if (argc == 3 && !strcmp(argv[0], "dexcr_prctl_onexec_test_child")) {
+			unsigned long which;
+
+			err = parse_ulong(argv[1], strlen(argv[1]), &which, 10);
+			FAIL_IF_MSG(err, "failed to parse which value for child");
+
+			return dexcr_prctl_onexec_test_child(which, argv[2]);
+		}
+
+		FAIL_IF_MSG(true, "unknown test case");
+	}
+
+	/*
+	 * Otherwise we are the main test invocation and run the full suite
+	 */
+	err |= test_harness(dexcr_prctl_ibrtpd_test, "dexcr_prctl_ibrtpd");
+	err |= test_harness(dexcr_prctl_srapd_test, "dexcr_prctl_srapd");
+	err |= test_harness(dexcr_prctl_nphie_test, "dexcr_prctl_nphie");
+
+	return err;
+}
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (4 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr Benjamin Gray
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Now that a process can control its DEXCR to some extent, make the
hashchk tests more reliable by explicitly setting the local and onexec
NPHIE aspect.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 tools/testing/selftests/powerpc/dexcr/hashchk_test.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/powerpc/dexcr/hashchk_test.c b/tools/testing/selftests/powerpc/dexcr/hashchk_test.c
index 7d5658c9ebe4..645224bdc142 100644
--- a/tools/testing/selftests/powerpc/dexcr/hashchk_test.c
+++ b/tools/testing/selftests/powerpc/dexcr/hashchk_test.c
@@ -21,8 +21,14 @@
 static int require_nphie(void)
 {
 	SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported");
+
+	pr_set_dexcr(PR_PPC_DEXCR_NPHIE, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_SET_ONEXEC);
+
+	if (get_dexcr(EFFECTIVE) & DEXCR_PR_NPHIE)
+		return 0;
+
 	SKIP_IF_MSG(!(get_dexcr(EFFECTIVE) & DEXCR_PR_NPHIE),
-		    "DEXCR[NPHIE] not enabled");
+		    "Failed to enable DEXCR[NPHIE]");
 
 	return 0;
 }
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (5 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 8/9] selftests/powerpc/dexcr: Add chdexcr utility Benjamin Gray
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Now that the DEXCR can be configured with prctl, add a section in
lsdexcr that explains why each aspect is set the way it is.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../testing/selftests/powerpc/dexcr/lsdexcr.c | 113 +++++++++++++++++-
 1 file changed, 111 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
index 94abbfcc389e..a63db47b6610 100644
--- a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
+++ b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
@@ -1,9 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0+
 
-#include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/prctl.h>
 
 #include "dexcr.h"
 #include "utils.h"
@@ -16,6 +16,8 @@ struct dexcr_aspect {
 	const char *name;
 	const char *desc;
 	unsigned int index;
+	unsigned long prctl;
+	const char *sysctl;
 };
 
 static const struct dexcr_aspect aspects[] = {
@@ -23,26 +25,36 @@ static const struct dexcr_aspect aspects[] = {
 		.name = "SBHE",
 		.desc = "Speculative branch hint enable",
 		.index = 0,
+		.prctl = PR_PPC_DEXCR_SBHE,
+		.sysctl = "speculative_branch_hint_enable",
 	},
 	{
 		.name = "IBRTPD",
 		.desc = "Indirect branch recurrent target prediction disable",
 		.index = 3,
+		.prctl = PR_PPC_DEXCR_IBRTPD,
+		.sysctl = "indirect_branch_recurrent_target_prediction_disable",
 	},
 	{
 		.name = "SRAPD",
 		.desc = "Subroutine return address prediction disable",
 		.index = 4,
+		.prctl = PR_PPC_DEXCR_SRAPD,
+		.sysctl = "subroutine_return_address_prediction_disable",
 	},
 	{
 		.name = "NPHIE",
 		.desc = "Non-privileged hash instruction enable",
 		.index = 5,
+		.prctl = PR_PPC_DEXCR_NPHIE,
+		.sysctl = "nonprivileged_hash_instruction_enable",
 	},
 	{
 		.name = "PHIE",
 		.desc = "Privileged hash instruction enable",
 		.index = 6,
+		.prctl = -1,
+		.sysctl = NULL,
 	},
 };
 
@@ -60,7 +72,7 @@ static void print_dexcr(char *name, unsigned int bits)
 	const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL};
 	size_t j = 0;
 
-	printf("%s: %08x", name, bits);
+	printf("%s: 0x%08x", name, bits);
 
 	if (bits == 0) {
 		printf("\n");
@@ -103,6 +115,95 @@ static void print_aspect(const struct dexcr_aspect *aspect)
 	printf("  \t(%s)\n", aspect->desc);
 }
 
+static void print_aspect_config(const struct dexcr_aspect *aspect)
+{
+	char sysctl_path[128] = "/proc/sys/kernel/dexcr/";
+	const char *reason = "unknown";
+	const char *reason_hyp = NULL;
+	const char *reason_sysctl = "no sysctl";
+	const char *reason_prctl = "no prctl";
+	bool actual = effective & DEXCR_PR_BIT(aspect->index);
+	bool expected = false;
+
+	long sysctl_ctrl = 0;
+	int prctl_ctrl = 0;
+	int err;
+
+	if (aspect->prctl >= 0) {
+		prctl_ctrl = pr_get_dexcr(aspect->prctl);
+		if (prctl_ctrl < 0)
+			reason_prctl = "(failed to read prctl)";
+		else {
+			if (prctl_ctrl & PR_PPC_DEXCR_CTRL_SET) {
+				reason_prctl = "set by prctl";
+				expected = true;
+			} else if (prctl_ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
+				reason_prctl = "cleared by prctl";
+				expected = false;
+			} else
+				reason_prctl = "unknown prctl";
+
+			reason = reason_prctl;
+		}
+	}
+
+	if (aspect->sysctl) {
+		strcat(sysctl_path, aspect->sysctl);
+		err = read_long(sysctl_path, &sysctl_ctrl, 10);
+		if (err)
+			reason_sysctl = "(failed to read sysctl)";
+		else {
+			switch (sysctl_ctrl) {
+			case 0:
+				reason_sysctl = "cleared by sysctl";
+				reason = reason_sysctl;
+				expected = false;
+				break;
+			case 1:
+				reason_sysctl = "set by sysctl";
+				reason = reason_sysctl;
+				expected = true;
+				break;
+			case 2:
+				reason_sysctl = "not modified by sysctl";
+				break;
+			case 3:
+				reason_sysctl = "cleared by sysctl (permanent)";
+				reason = reason_sysctl;
+				expected = false;
+				break;
+			case 4:
+				reason_sysctl = "set by sysctl (permanent)";
+				reason = reason_sysctl;
+				expected = true;
+				break;
+			default:
+				reason_sysctl = "unknown sysctl";
+				break;
+			}
+		}
+	}
+
+
+	if (hdexcr & DEXCR_PR_BIT(aspect->index)) {
+		reason_hyp = "set by hypervisor";
+		reason = reason_hyp;
+		expected = true;
+	} else
+		reason_hyp = "not modified by hypervisor";
+
+	printf("%12s (%d): %-28s (%s, %s, %s)\n",
+	       aspect->name,
+	       aspect->index,
+	       reason,
+	       reason_hyp,
+	       reason_sysctl,
+	       reason_prctl);
+
+	if (actual != expected)
+		printf("                : ! actual %s does not match config\n", aspect->name);
+}
+
 int main(int argc, char *argv[])
 {
 	if (!dexcr_exists()) {
@@ -114,6 +215,8 @@ int main(int argc, char *argv[])
 	hdexcr = get_dexcr(HDEXCR);
 	effective = dexcr | hdexcr;
 
+	printf("current status:\n");
+
 	print_dexcr("    DEXCR", dexcr);
 	print_dexcr("   HDEXCR", hdexcr);
 	print_dexcr("Effective", effective);
@@ -136,6 +239,12 @@ int main(int argc, char *argv[])
 		else
 			printf("ignored\n");
 	}
+	printf("\n");
+
+	printf("configuration:\n");
+	for (size_t i = 0; i < ARRAY_SIZE(aspects); i++)
+		print_aspect_config(&aspects[i]);
+	printf("\n");
 
 	return 0;
 }
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 8/9] selftests/powerpc/dexcr: Add chdexcr utility
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (6 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-04-17 11:23 ` [PATCH v1 9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface Benjamin Gray
  2024-05-08 13:39 ` [PATCH v1 0/9] Add dynamic DEXCR support Michael Ellerman
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Adds a utility to exercise the prctl DEXCR inheritance in the shell.
Supports setting and clearing each aspect.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 .../selftests/powerpc/dexcr/.gitignore        |   1 +
 .../testing/selftests/powerpc/dexcr/Makefile  |   2 +-
 .../testing/selftests/powerpc/dexcr/chdexcr.c | 110 +++++++++++++++
 tools/testing/selftests/powerpc/dexcr/dexcr.h |  47 +++++++
 .../testing/selftests/powerpc/dexcr/lsdexcr.c | 130 ++++--------------
 5 files changed, 185 insertions(+), 105 deletions(-)
 create mode 100644 tools/testing/selftests/powerpc/dexcr/chdexcr.c

diff --git a/tools/testing/selftests/powerpc/dexcr/.gitignore b/tools/testing/selftests/powerpc/dexcr/.gitignore
index 5d526613cd26..11eefb4b9fa4 100644
--- a/tools/testing/selftests/powerpc/dexcr/.gitignore
+++ b/tools/testing/selftests/powerpc/dexcr/.gitignore
@@ -1,3 +1,4 @@
 dexcr_test
 hashchk_test
+chdexcr
 lsdexcr
diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile b/tools/testing/selftests/powerpc/dexcr/Makefile
index 076943193c07..6a89e88ef7b2 100644
--- a/tools/testing/selftests/powerpc/dexcr/Makefile
+++ b/tools/testing/selftests/powerpc/dexcr/Makefile
@@ -1,5 +1,5 @@
 TEST_GEN_PROGS := dexcr_test hashchk_test
-TEST_GEN_FILES := lsdexcr
+TEST_GEN_FILES := lsdexcr chdexcr
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/dexcr/chdexcr.c b/tools/testing/selftests/powerpc/dexcr/chdexcr.c
new file mode 100644
index 000000000000..217187a83224
--- /dev/null
+++ b/tools/testing/selftests/powerpc/dexcr/chdexcr.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#include "dexcr.h"
+#include "utils.h"
+
+static void die(const char *msg)
+{
+	printf("%s\n", msg);
+	exit(1);
+}
+
+static void help(void)
+{
+	printf("Invoke a provided program with a custom DEXCR on-exec reset value\n"
+	       "\n"
+	       "usage: chdexcr [CHDEXCR OPTIONS] -- PROGRAM [ARGS...]\n"
+	       "\n"
+	       "Each configurable DEXCR aspect is exposed as an option.\n"
+	       "\n"
+	       "The normal option sets the aspect in the DEXCR. The --no- variant\n"
+	       "clears that aspect. For example, --ibrtpd sets the IBRTPD aspect bit,\n"
+	       "so indirect branch predicition will be disabled in the provided program.\n"
+	       "Conversely, --no-ibrtpd clears the aspect bit, so indirect branch\n"
+	       "prediction may occur.\n"
+	       "\n"
+	       "CHDEXCR OPTIONS:\n");
+
+	for (int i = 0; i < ARRAY_SIZE(aspects); i++) {
+		const struct dexcr_aspect *aspect = &aspects[i];
+
+		if (aspect->prctl == -1)
+			continue;
+
+		printf("  --%-6s / --no-%-6s : %s\n", aspect->opt, aspect->opt, aspect->desc);
+	}
+}
+
+static const struct dexcr_aspect *opt_to_aspect(const char *opt)
+{
+	for (int i = 0; i < ARRAY_SIZE(aspects); i++)
+		if (aspects[i].prctl != -1 && !strcmp(aspects[i].opt, opt))
+			return &aspects[i];
+
+	return NULL;
+}
+
+static int apply_option(const char *option)
+{
+	const struct dexcr_aspect *aspect;
+	const char *opt = NULL;
+	const char *set_prefix = "--";
+	const char *clear_prefix = "--no-";
+	unsigned long ctrl = 0;
+	int err;
+
+	if (!strcmp(option, "-h") || !strcmp(option, "--help")) {
+		help();
+		exit(0);
+	}
+
+	/* Strip out --(no-) prefix and determine ctrl value */
+	if (!strncmp(option, clear_prefix, strlen(clear_prefix))) {
+		opt = &option[strlen(clear_prefix)];
+		ctrl |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC;
+	} else if (!strncmp(option, set_prefix, strlen(set_prefix))) {
+		opt = &option[strlen(set_prefix)];
+		ctrl |= PR_PPC_DEXCR_CTRL_SET_ONEXEC;
+	}
+
+	if (!opt || !*opt)
+		return 1;
+
+	aspect = opt_to_aspect(opt);
+	if (!aspect)
+		die("unknown aspect");
+
+	err = pr_set_dexcr(aspect->prctl, ctrl);
+	if (err)
+		die("failed to apply option");
+
+	return 0;
+}
+
+int main(int argc, char *const argv[], char *const envp[])
+{
+	int i;
+
+	if (!dexcr_exists())
+		die("DEXCR not detected on this hardware");
+
+	for (i = 1; i < argc; i++)
+		if (apply_option(argv[i]))
+			break;
+
+	if (i < argc && !strcmp(argv[i], "--"))
+		i++;
+
+	if (i >= argc)
+		die("missing command");
+
+	execve(argv[i], &argv[i], envp);
+	return errno;
+}
diff --git a/tools/testing/selftests/powerpc/dexcr/dexcr.h b/tools/testing/selftests/powerpc/dexcr/dexcr.h
index a6aa7eac11da..51e9ba3b0997 100644
--- a/tools/testing/selftests/powerpc/dexcr/dexcr.h
+++ b/tools/testing/selftests/powerpc/dexcr/dexcr.h
@@ -9,6 +9,7 @@
 #define _SELFTESTS_POWERPC_DEXCR_DEXCR_H
 
 #include <stdbool.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 
 #include "reg.h"
@@ -26,6 +27,52 @@
 #define PPC_RAW_HASHCHK(b, i, a) \
 	str(.long (0x7C0005E4 | PPC_RAW_HASH_ARGS(b, i, a));)
 
+struct dexcr_aspect {
+	const char *name;	/* Short display name */
+	const char *opt;	/* Option name for chdexcr */
+	const char *desc;	/* Expanded aspect meaning */
+	unsigned int index;	/* Aspect bit index in DEXCR */
+	unsigned long prctl;	/* 'which' value for get/set prctl */
+};
+
+static const struct dexcr_aspect aspects[] = {
+	{
+		.name = "SBHE",
+		.opt = "sbhe",
+		.desc = "Speculative branch hint enable",
+		.index = 0,
+		.prctl = PR_PPC_DEXCR_SBHE,
+	},
+	{
+		.name = "IBRTPD",
+		.opt = "ibrtpd",
+		.desc = "Indirect branch recurrent target prediction disable",
+		.index = 3,
+		.prctl = PR_PPC_DEXCR_IBRTPD,
+	},
+	{
+		.name = "SRAPD",
+		.opt = "srapd",
+		.desc = "Subroutine return address prediction disable",
+		.index = 4,
+		.prctl = PR_PPC_DEXCR_SRAPD,
+	},
+	{
+		.name = "NPHIE",
+		.opt = "nphie",
+		.desc = "Non-privileged hash instruction enable",
+		.index = 5,
+		.prctl = PR_PPC_DEXCR_NPHIE,
+	},
+	{
+		.name = "PHIE",
+		.opt = "phie",
+		.desc = "Privileged hash instruction enable",
+		.index = 6,
+		.prctl = -1,
+	},
+};
+
 bool dexcr_exists(void);
 
 bool pr_dexcr_aspect_supported(unsigned long which);
diff --git a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
index a63db47b6610..7588929180ab 100644
--- a/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
+++ b/tools/testing/selftests/powerpc/dexcr/lsdexcr.c
@@ -12,52 +12,6 @@ static unsigned int dexcr;
 static unsigned int hdexcr;
 static unsigned int effective;
 
-struct dexcr_aspect {
-	const char *name;
-	const char *desc;
-	unsigned int index;
-	unsigned long prctl;
-	const char *sysctl;
-};
-
-static const struct dexcr_aspect aspects[] = {
-	{
-		.name = "SBHE",
-		.desc = "Speculative branch hint enable",
-		.index = 0,
-		.prctl = PR_PPC_DEXCR_SBHE,
-		.sysctl = "speculative_branch_hint_enable",
-	},
-	{
-		.name = "IBRTPD",
-		.desc = "Indirect branch recurrent target prediction disable",
-		.index = 3,
-		.prctl = PR_PPC_DEXCR_IBRTPD,
-		.sysctl = "indirect_branch_recurrent_target_prediction_disable",
-	},
-	{
-		.name = "SRAPD",
-		.desc = "Subroutine return address prediction disable",
-		.index = 4,
-		.prctl = PR_PPC_DEXCR_SRAPD,
-		.sysctl = "subroutine_return_address_prediction_disable",
-	},
-	{
-		.name = "NPHIE",
-		.desc = "Non-privileged hash instruction enable",
-		.index = 5,
-		.prctl = PR_PPC_DEXCR_NPHIE,
-		.sysctl = "nonprivileged_hash_instruction_enable",
-	},
-	{
-		.name = "PHIE",
-		.desc = "Privileged hash instruction enable",
-		.index = 6,
-		.prctl = -1,
-		.sysctl = NULL,
-	},
-};
-
 static void print_list(const char *list[], size_t len)
 {
 	for (size_t i = 0; i < len; i++) {
@@ -117,89 +71,57 @@ static void print_aspect(const struct dexcr_aspect *aspect)
 
 static void print_aspect_config(const struct dexcr_aspect *aspect)
 {
-	char sysctl_path[128] = "/proc/sys/kernel/dexcr/";
-	const char *reason = "unknown";
+	const char *reason = NULL;
 	const char *reason_hyp = NULL;
-	const char *reason_sysctl = "no sysctl";
 	const char *reason_prctl = "no prctl";
 	bool actual = effective & DEXCR_PR_BIT(aspect->index);
-	bool expected = false;
-
-	long sysctl_ctrl = 0;
-	int prctl_ctrl = 0;
-	int err;
-
-	if (aspect->prctl >= 0) {
-		prctl_ctrl = pr_get_dexcr(aspect->prctl);
-		if (prctl_ctrl < 0)
-			reason_prctl = "(failed to read prctl)";
-		else {
-			if (prctl_ctrl & PR_PPC_DEXCR_CTRL_SET) {
+	bool expected = actual;  /* Assume it's fine if we don't expect a specific set/clear value */
+
+	if (actual)
+		reason = "set by unknown";
+	else
+		reason = "cleared by unknown";
+
+	if (aspect->prctl != -1) {
+		int ctrl = pr_get_dexcr(aspect->prctl);
+
+		if (ctrl < 0) {
+			reason_prctl = "failed to read prctl";
+		} else {
+			if (ctrl & PR_PPC_DEXCR_CTRL_SET) {
 				reason_prctl = "set by prctl";
 				expected = true;
-			} else if (prctl_ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
+			} else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
 				reason_prctl = "cleared by prctl";
 				expected = false;
-			} else
+			} else {
 				reason_prctl = "unknown prctl";
+			}
 
 			reason = reason_prctl;
 		}
 	}
 
-	if (aspect->sysctl) {
-		strcat(sysctl_path, aspect->sysctl);
-		err = read_long(sysctl_path, &sysctl_ctrl, 10);
-		if (err)
-			reason_sysctl = "(failed to read sysctl)";
-		else {
-			switch (sysctl_ctrl) {
-			case 0:
-				reason_sysctl = "cleared by sysctl";
-				reason = reason_sysctl;
-				expected = false;
-				break;
-			case 1:
-				reason_sysctl = "set by sysctl";
-				reason = reason_sysctl;
-				expected = true;
-				break;
-			case 2:
-				reason_sysctl = "not modified by sysctl";
-				break;
-			case 3:
-				reason_sysctl = "cleared by sysctl (permanent)";
-				reason = reason_sysctl;
-				expected = false;
-				break;
-			case 4:
-				reason_sysctl = "set by sysctl (permanent)";
-				reason = reason_sysctl;
-				expected = true;
-				break;
-			default:
-				reason_sysctl = "unknown sysctl";
-				break;
-			}
-		}
-	}
-
-
 	if (hdexcr & DEXCR_PR_BIT(aspect->index)) {
 		reason_hyp = "set by hypervisor";
 		reason = reason_hyp;
 		expected = true;
-	} else
+	} else {
 		reason_hyp = "not modified by hypervisor";
+	}
 
-	printf("%12s (%d): %-28s (%s, %s, %s)\n",
+	printf("%12s (%d): %-28s (%s, %s)\n",
 	       aspect->name,
 	       aspect->index,
 	       reason,
 	       reason_hyp,
-	       reason_sysctl,
 	       reason_prctl);
 
+	/*
+	 * The checks are not atomic, so this can technically trigger if the
+	 * hypervisor makes a change while we are checking each source. It's
+	 * far more likely to be a bug if we see this though.
+	 */
 	if (actual != expected)
 		printf("                : ! actual %s does not match config\n", aspect->name);
 }
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v1 9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (7 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 8/9] selftests/powerpc/dexcr: Add chdexcr utility Benjamin Gray
@ 2024-04-17 11:23 ` Benjamin Gray
  2024-05-08 13:39 ` [PATCH v1 0/9] Add dynamic DEXCR support Michael Ellerman
  9 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gray @ 2024-04-17 11:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Benjamin Gray

Documents how to use the PR_PPC_GET_DEXCR and PR_PPC_SET_DEXCR prctl()'s
for changing a process's DEXCR or its process tree default value.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 Documentation/arch/powerpc/dexcr.rst | 141 ++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 2 deletions(-)

diff --git a/Documentation/arch/powerpc/dexcr.rst b/Documentation/arch/powerpc/dexcr.rst
index 615a631f51fa..ab0724212fcd 100644
--- a/Documentation/arch/powerpc/dexcr.rst
+++ b/Documentation/arch/powerpc/dexcr.rst
@@ -36,8 +36,145 @@ state for a process.
 Configuration
 =============
 
-The DEXCR is currently unconfigurable. All threads are run with the
-NPHIE aspect enabled.
+prctl
+-----
+
+A process can control its own userspace DEXCR value using the
+``PR_PPC_GET_DEXCR`` and ``PR_PPC_SET_DEXCR`` pair of
+:manpage:`prctl(2)` commands. These calls have the form::
+
+    prctl(PR_PPC_GET_DEXCR, unsigned long which, 0, 0, 0);
+    prctl(PR_PPC_SET_DEXCR, unsigned long which, unsigned long ctrl, 0, 0);
+
+The possible 'which' and 'ctrl' values are as follows. Note there is no relation
+between the 'which' value and the DEXCR aspect's index.
+
+.. flat-table::
+   :header-rows: 1
+   :widths: 2 7 1
+
+   * - ``prctl()`` which
+     - Aspect name
+     - Aspect index
+
+   * - ``PR_PPC_DEXCR_SBHE``
+     - Speculative Branch Hint Enable (SBHE)
+     - 0
+
+   * - ``PR_PPC_DEXCR_IBRTPD``
+     - Indirect Branch Recurrent Target Prediction Disable (IBRTPD)
+     - 3
+
+   * - ``PR_PPC_DEXCR_SRAPD``
+     - Subroutine Return Address Prediction Disable (SRAPD)
+     - 4
+
+   * - ``PR_PPC_DEXCR_NPHIE``
+     - Non-Privileged Hash Instruction Enable (NPHIE)
+     - 5
+
+.. flat-table::
+   :header-rows: 1
+   :widths: 2 8
+
+   * - ``prctl()`` ctrl
+     - Meaning
+
+   * - ``PR_PPC_DEXCR_CTRL_EDITABLE``
+     - This aspect can be configured with PR_PPC_SET_DEXCR (get only)
+
+   * - ``PR_PPC_DEXCR_CTRL_SET``
+     - This aspect is set / set this aspect
+
+   * - ``PR_PPC_DEXCR_CTRL_CLEAR``
+     - This aspect is clear / clear this aspect
+
+   * - ``PR_PPC_DEXCR_CTRL_SET_ONEXEC``
+     - This aspect will be set after exec / set this aspect after exec
+
+   * - ``PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC``
+     - This aspect will be clear after exec / clear this aspect after exec
+
+Note that
+
+* which is a plain value, not a bitmask. Aspects must be worked with individually.
+
+* ctrl is a bitmask. ``PR_PPC_GET_DEXCR`` returns both the current and onexec
+  configuration. For example, ``PR_PPC_GET_DEXCR`` may return
+  ``PR_PPC_DEXCR_CTRL_EDITABLE | PR_PPC_DEXCR_CTRL_SET |
+  PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC``. This would indicate the aspect is currently
+  set, it will be cleared when you run exec, and you can change this with the
+  ``PR_PPC_SET_DEXCR`` prctl.
+
+* The set/clear terminology refers to setting/clearing the bit in the DEXCR.
+  For example::
+
+      prctl(PR_PPC_SET_DEXCR, PR_PPC_DEXCR_IBRTPD, PR_PPC_DEXCR_CTRL_SET, 0, 0);
+
+  will set the IBRTPD aspect bit in the DEXCR, causing indirect branch prediction
+  to be disabled.
+
+* The status returned by ``PR_PPC_GET_DEXCR`` represents what value the process
+  would like applied. It does not include any alternative overrides, such as if
+  the hypervisor is enforcing the aspect be set. To see the true DEXCR state
+  software should read the appropriate SPRs directly.
+
+* The aspect state when starting a process is copied from the parent's state on
+  :manpage:`fork(2)`. The state is reset to a fixed value on
+  :manpage:`execve(2)`. The PR_PPC_SET_DEXCR prctl() can control both of these
+  values.
+
+* The ``*_ONEXEC`` controls do not change the current process's DEXCR.
+
+Use ``PR_PPC_SET_DEXCR`` with one of ``PR_PPC_DEXCR_CTRL_SET`` or
+``PR_PPC_DEXCR_CTRL_CLEAR`` to edit a given aspect.
+
+Common error codes for both getting and setting the DEXCR are as follows:
+
+.. flat-table::
+   :header-rows: 1
+   :widths: 2 8
+
+   * - Error
+     - Meaning
+
+   * - ``EINVAL``
+     - The DEXCR is not supported by the kernel.
+
+   * - ``ENODEV``
+     - The aspect is not recognised by the kernel or not supported by the
+       hardware.
+
+``PR_PPC_SET_DEXCR`` may also report the following error codes:
+
+.. flat-table::
+   :header-rows: 1
+   :widths: 2 8
+
+   * - Error
+     - Meaning
+
+   * - ``EINVAL``
+     - The ctrl value contains unrecognised flags.
+
+   * - ``EINVAL``
+     - The ctrl value contains mutually conflicting flags (e.g.,
+       ``PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR``)
+
+   * - ``EPERM``
+     - This aspect cannot be modified with prctl() (check for the
+       PR_PPC_DEXCR_CTRL_EDITABLE flag with PR_PPC_GET_DEXCR).
+
+   * - ``EPERM``
+     - The process does not have sufficient privilege to perform the operation.
+       For example, clearing NPHIE on exec is a privileged operation (a process
+       can still clear its own NPHIE aspect without privileges).
+
+This interface allows a process to control its own DEXCR aspects, and also set
+the initial DEXCR value for any children in its process tree (up to the next
+child to use an ``*_ONEXEC`` control). This allows fine-grained control over the
+default value of the DEXCR, for example allowing containers to run with different
+default values.
 
 
 coredump and ptrace
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests
  2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
@ 2024-05-07  7:44   ` Andrew Donnellan
  0 siblings, 0 replies; 12+ messages in thread
From: Andrew Donnellan @ 2024-05-07  7:44 UTC (permalink / raw)
  To: Benjamin Gray, linuxppc-dev

On Wed, 2024-04-17 at 21:23 +1000, Benjamin Gray wrote:
> The hashchk tests want to verify that the hash key is changed over
> exec.
> It does so by calculating hashes at the same address across an exec.
> This is made simpler by disabling PIE functionality, so we can
> re-execute ourselves and be using the same addresses in the child.
> 
> While -fno-pie is already added, -no-pie is also required.
> 
> Fixes: ca64da7574f8 ("selftests/powerpc/dexcr: Add hashst/hashchk
> test")
> Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>

This matches the gcc documentation.

Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
Tested-by: Andrew Donnellan <ajd@linux.ibm.com>

> 
> ---
> 
> This is not related to features introduced in this series, just fixes
> the test added in the static DEXCR series.
> ---
>  tools/testing/selftests/powerpc/dexcr/Makefile | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/powerpc/dexcr/Makefile
> b/tools/testing/selftests/powerpc/dexcr/Makefile
> index 76210f2bcec3..829ad075b4a4 100644
> --- a/tools/testing/selftests/powerpc/dexcr/Makefile
> +++ b/tools/testing/selftests/powerpc/dexcr/Makefile
> @@ -3,7 +3,7 @@ TEST_GEN_FILES := lsdexcr
>  
>  include ../../lib.mk
>  
> -$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie $(call cc-option,-mno-
> rop-protect)
> +$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-
> option,-mno-rop-protect)
>  
>  $(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
>  $(TEST_GEN_FILES): ../utils.c ./dexcr.c

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v1 0/9] Add dynamic DEXCR support
  2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
                   ` (8 preceding siblings ...)
  2024-04-17 11:23 ` [PATCH v1 9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface Benjamin Gray
@ 2024-05-08 13:39 ` Michael Ellerman
  9 siblings, 0 replies; 12+ messages in thread
From: Michael Ellerman @ 2024-05-08 13:39 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Gray

On Wed, 17 Apr 2024 21:23:16 +1000, Benjamin Gray wrote:
> Adds support for a process to change its DEXCR value. The implementation is
> somewhat conservative; SBHE (speculative branch hint enable) is not exposed
> as an editable aspect because its effects can bleed over to other threads.
> 
> As explained in the third patch, this series changes the reset/inherit
> behaviour on exec. Previously there was a bitmask that tracked which aspects
> to copy from the current state vs resetting to a fixed default. This
> allows unprivileged processes to disable ROP protection for setuid binaries
> though, and is generally a weird interface to work with. The actual intent
> (and new implementation) tracks the exec value as an independent value that
> doesn't use the parent's DEXCR at all. The parent can control this reset value
> separately to its own DEXCR value.
> 
> [...]

Applied to powerpc/next.

[1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests
      https://git.kernel.org/powerpc/c/d7228a58d9438d6f219dc7f33eab0d1980b3bd2f
[2/9] powerpc/dexcr: Track the DEXCR per-process
      https://git.kernel.org/powerpc/c/75171f06c4507c3b6b5a69d793879fb20d108bb1
[3/9] powerpc/dexcr: Reset DEXCR value across exec
      https://git.kernel.org/powerpc/c/bbd99922d0f4518518282217159666c679c6a0d1
[4/9] powerpc/dexcr: Add DEXCR prctl interface
      https://git.kernel.org/powerpc/c/628d701f2de5b9a16d1dd82bea68fd895f56f1a1
[5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test
      https://git.kernel.org/powerpc/c/5bfa66bf86d792bbcc76bc09cf99a2ae9d6e0eec
[6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest
      https://git.kernel.org/powerpc/c/9930fba02a1c587849aea1e6c5688168013c065f
[7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr
      https://git.kernel.org/powerpc/c/9c4866b209ad31cae7c832d45c6137ce6a993ca0
[8/9] selftests/powerpc/dexcr: Add chdexcr utility
      https://git.kernel.org/powerpc/c/f88723a609787254f7645eb6ac261b8363e8a5bc
[9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface
      https://git.kernel.org/powerpc/c/9248edf31ab28723fb00900ecb8bacdb05eeefff

cheers

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-05-08 13:42 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-17 11:23 [PATCH v1 0/9] Add dynamic DEXCR support Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 1/9] selftests/powerpc/dexcr: Add -no-pie to hashchk tests Benjamin Gray
2024-05-07  7:44   ` Andrew Donnellan
2024-04-17 11:23 ` [PATCH v1 2/9] powerpc/dexcr: Track the DEXCR per-process Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 3/9] powerpc/dexcr: Reset DEXCR value across exec Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 4/9] powerpc/dexcr: Add DEXCR prctl interface Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 5/9] selftests/powerpc/dexcr: Add DEXCR prctl interface test Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 6/9] selftests/powerpc/dexcr: Attempt to enable NPHIE in hashchk selftest Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 7/9] selftests/powerpc/dexcr: Add DEXCR config details to lsdexcr Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 8/9] selftests/powerpc/dexcr: Add chdexcr utility Benjamin Gray
2024-04-17 11:23 ` [PATCH v1 9/9] Documentation: Document PowerPC kernel dynamic DEXCR interface Benjamin Gray
2024-05-08 13:39 ` [PATCH v1 0/9] Add dynamic DEXCR support Michael Ellerman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).