Skip to content

Commit

Permalink
powerpc/dexcr: Add DEXCR prctl interface
Browse files Browse the repository at this point in the history
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
  • Loading branch information
BenjaminGrayNp1 authored and mpe committed May 6, 2024
1 parent bbd9992 commit 628d701
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
10 changes: 10 additions & 0 deletions arch/powerpc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
101 changes: 101 additions & 0 deletions arch/powerpc/kernel/dexcr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
16 changes: 16 additions & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
16 changes: 16 additions & 0 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 628d701

Please sign in to comment.