1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <linux/capability.h> 4 #include <linux/cpu.h> 5 #include <linux/init.h> 6 #include <linux/prctl.h> 7 #include <linux/sched.h> 8 9 #include <asm/cpu_has_feature.h> 10 #include <asm/cputable.h> 11 #include <asm/processor.h> 12 #include <asm/reg.h> 13 14 static int __init init_task_dexcr(void) 15 { 16 if (!early_cpu_has_feature(CPU_FTR_ARCH_31)) 17 return 0; 18 19 current->thread.dexcr_onexec = mfspr(SPRN_DEXCR); 20 21 return 0; 22 } 23 early_initcall(init_task_dexcr) 24 25 /* Allow thread local configuration of these by default */ 26 #define DEXCR_PRCTL_EDITABLE ( \ 27 DEXCR_PR_IBRTPD | \ 28 DEXCR_PR_SRAPD | \ 29 DEXCR_PR_NPHIE) 30 31 static int prctl_to_aspect(unsigned long which, unsigned int *aspect) 32 { 33 switch (which) { 34 case PR_PPC_DEXCR_SBHE: 35 *aspect = DEXCR_PR_SBHE; 36 break; 37 case PR_PPC_DEXCR_IBRTPD: 38 *aspect = DEXCR_PR_IBRTPD; 39 break; 40 case PR_PPC_DEXCR_SRAPD: 41 *aspect = DEXCR_PR_SRAPD; 42 break; 43 case PR_PPC_DEXCR_NPHIE: 44 *aspect = DEXCR_PR_NPHIE; 45 break; 46 default: 47 return -ENODEV; 48 } 49 50 return 0; 51 } 52 53 int get_dexcr_prctl(struct task_struct *task, unsigned long which) 54 { 55 unsigned int aspect; 56 int ret; 57 58 ret = prctl_to_aspect(which, &aspect); 59 if (ret) 60 return ret; 61 62 if (aspect & DEXCR_PRCTL_EDITABLE) 63 ret |= PR_PPC_DEXCR_CTRL_EDITABLE; 64 65 if (aspect & mfspr(SPRN_DEXCR)) 66 ret |= PR_PPC_DEXCR_CTRL_SET; 67 else 68 ret |= PR_PPC_DEXCR_CTRL_CLEAR; 69 70 if (aspect & task->thread.dexcr_onexec) 71 ret |= PR_PPC_DEXCR_CTRL_SET_ONEXEC; 72 else 73 ret |= PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC; 74 75 return ret; 76 } 77 78 int set_dexcr_prctl(struct task_struct *task, unsigned long which, unsigned long ctrl) 79 { 80 unsigned long dexcr; 81 unsigned int aspect; 82 int err = 0; 83 84 err = prctl_to_aspect(which, &aspect); 85 if (err) 86 return err; 87 88 if (!(aspect & DEXCR_PRCTL_EDITABLE)) 89 return -EPERM; 90 91 if (ctrl & ~PR_PPC_DEXCR_CTRL_MASK) 92 return -EINVAL; 93 94 if (ctrl & PR_PPC_DEXCR_CTRL_SET && ctrl & PR_PPC_DEXCR_CTRL_CLEAR) 95 return -EINVAL; 96 97 if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC && ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC) 98 return -EINVAL; 99 100 /* 101 * We do not want an unprivileged process being able to disable 102 * a setuid process's hash check instructions 103 */ 104 if (aspect == DEXCR_PR_NPHIE && 105 ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC && 106 !capable(CAP_SYS_ADMIN)) 107 return -EPERM; 108 109 dexcr = mfspr(SPRN_DEXCR); 110 111 if (ctrl & PR_PPC_DEXCR_CTRL_SET) 112 dexcr |= aspect; 113 else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) 114 dexcr &= ~aspect; 115 116 if (ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC) 117 task->thread.dexcr_onexec |= aspect; 118 else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC) 119 task->thread.dexcr_onexec &= ~aspect; 120 121 mtspr(SPRN_DEXCR, dexcr); 122 123 return 0; 124 } 125