dexcr.c 2.6 KB

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