124 lines
2.6 KiB
C
124 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#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)
|
|
|
|
/* 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;
|
|
}
|