powerpc/dexcr: Add DEXCR prctl interface

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
This commit is contained in:
Benjamin Gray 2024-04-17 21:23:20 +10:00 committed by Michael Ellerman
parent bbd99922d0
commit 628d701f2d
4 changed files with 143 additions and 0 deletions

View 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);

View 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;
}

View 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 */

View file

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