[RFC PATCH 4/6] powerpc/dexcr: Add prctl implementation

Benjamin Gray bgray at linux.ibm.com
Mon Oct 9 16:54:04 AEDT 2023


Adds an initial prctl interface implementation. Unprivileged processes
can query the current prctl setting, including whether an aspect is
implemented by the hardware or is permitted to be modified by a setter
prctl. Editable aspects can be changed by a CAP_SYS_ADMIN privileged
process.

The prctl setting represents what the process itself has requested, and
does not account for any overrides. Either the kernel or a hypervisor
may enforce a different setting for an aspect.

Userspace can access a readonly view of the current DEXCR via SPR 812,
and a readonly view of the aspects enforced by the hypervisor via
SPR 455. A bitwise OR of these two SPRs will give the effective
DEXCR aspect state of the process.

Signed-off-by: Benjamin Gray <bgray at linux.ibm.com>
---
 arch/powerpc/include/asm/processor.h |  10 +++
 arch/powerpc/kernel/Makefile         |   1 +
 arch/powerpc/kernel/dexcr.c          | 128 +++++++++++++++++++++++++++
 3 files changed, 139 insertions(+)
 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 28a72023f9bd..a9d83621dfad 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -336,6 +336,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/Makefile b/arch/powerpc/kernel/Makefile
index 2919433be355..24f82b09246c 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -88,6 +88,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..db663ce7b3ce
--- /dev/null
+++ b/arch/powerpc/kernel/dexcr.c
@@ -0,0 +1,128 @@
+#include <linux/capability.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>
+
+/* Allow thread local configuration of these by default */
+#define DEXCR_PRCTL_EDITABLE ( \
+	DEXCR_PR_IBRTPD | \
+	DEXCR_PR_SRAPD | \
+	DEXCR_PR_NPHIE)
+
+static unsigned long dexcr_supported __ro_after_init = 0;
+
+static int __init dexcr_init(void)
+{
+	if (!early_cpu_has_feature(CPU_FTR_ARCH_31))
+		return 0;
+
+	if (early_cpu_has_feature(CPU_FTR_DEXCR_SBHE))
+		dexcr_supported |= DEXCR_PR_SBHE;
+
+	if (early_cpu_has_feature(CPU_FTR_DEXCR_IBRTPD))
+		dexcr_supported |= DEXCR_PR_IBRTPD;
+
+	if (early_cpu_has_feature(CPU_FTR_DEXCR_SRAPD))
+		dexcr_supported |= DEXCR_PR_SRAPD;
+
+	if (early_cpu_has_feature(CPU_FTR_DEXCR_NPHIE))
+		dexcr_supported |= DEXCR_PR_NPHIE;
+
+	return 0;
+}
+early_initcall(dexcr_init);
+
+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_supported))
+		return -ENODEV;
+
+	if (aspect & task->thread.dexcr_enabled)
+		ret |= PR_PPC_DEXCR_CTRL_ON;
+	else
+		ret |= PR_PPC_DEXCR_CTRL_OFF;
+
+	if (aspect & task->thread.dexcr_inherit)
+		ret |= PR_PPC_DEXCR_CTRL_INHERIT;
+
+	return ret;
+}
+
+int set_dexcr_prctl(struct task_struct *task, unsigned long which, unsigned long ctrl)
+{
+	unsigned int aspect;
+	unsigned long enable;
+	unsigned long disable;
+	unsigned long inherit;
+	int err = 0;
+
+	/* We do not want an unprivileged process being able to set a value that a setuid process may inherit (particularly for NPHIE) */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	err = prctl_to_aspect(which, &aspect);
+	if (err)
+		return err;
+
+	if (!(aspect & dexcr_supported))
+		return -ENODEV;
+
+	enable = ctrl & PR_PPC_DEXCR_CTRL_ON;
+	disable = ctrl & PR_PPC_DEXCR_CTRL_OFF;
+	inherit = ctrl & PR_PPC_DEXCR_CTRL_INHERIT;
+	ctrl &= ~(PR_PPC_DEXCR_CTRL_ON | PR_PPC_DEXCR_CTRL_OFF | PR_PPC_DEXCR_CTRL_INHERIT);
+
+	if (ctrl)
+		return -EINVAL;
+
+	if ((enable && disable) || !(enable || disable))
+		return -EINVAL;
+
+	if (enable)
+		task->thread.dexcr_enabled |= aspect;
+	else
+		task->thread.dexcr_enabled &= ~aspect;
+
+	if (inherit)
+		task->thread.dexcr_inherit |= aspect;
+	else
+		task->thread.dexcr_inherit &= ~aspect;
+
+	mtspr(SPRN_DEXCR, get_thread_dexcr(&current->thread));
+
+	return 0;
+}
-- 
2.41.0



More information about the Linuxppc-dev mailing list