]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
powerpc/dexcr: Add DEXCR prctl interface
authorBenjamin Gray <bgray@linux.ibm.com>
Wed, 17 Apr 2024 11:23:20 +0000 (21:23 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 6 May 2024 12:04:31 +0000 (22:04 +1000)
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>
[mpe: Account for PR_RISCV_SET_ICACHE_FLUSH_CTX, shrink some longs lines]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240417112325.728010-5-bgray@linux.ibm.com
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/dexcr.c
include/uapi/linux/prctl.h
kernel/sys.c

index aad85a24134ac3b1fd28084c31a14a98645f464d..e44cac0da346f8210fc7561b1e3cae04d1a5b2b0 100644 (file)
@@ -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);
index d5cd77421088d8332b76d1842fe10b639d20bfc2..3a0358e91c60ae270c8b179b800c8d947d8a546b 100644 (file)
@@ -21,3 +21,104 @@ 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;
+}
index 370ed14b1ae0928ce23312ac8a882db89a78dfdc..713d28788df7426754ea4cce5d0a30435f99e3c9 100644 (file)
@@ -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               72
+#define PR_PPC_SET_DEXCR               73
+/* 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     0x1 /* Aspect can be modified with PR_PPC_SET_DEXCR */
+# define PR_PPC_DEXCR_CTRL_SET          0x2 /* Set the aspect for this process */
+# define PR_PPC_DEXCR_CTRL_CLEAR        0x4 /* Clear the aspect for this process */
+# define PR_PPC_DEXCR_CTRL_SET_ONEXEC   0x8 /* Set the aspect on exec */
+# define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC        0x10 /* Clear the aspect on exec */
+# define PR_PPC_DEXCR_CTRL_MASK                0x1f
+
 #endif /* _LINUX_PRCTL_H */
index 8bb106a56b3a5f7b519598343bc0fd48e81cfbb7..f9c95410278c46eb812b65170e67689795cf7412 100644 (file)
 #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;