pkey-helpers.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _PKEYS_HELPER_H
  3. #define _PKEYS_HELPER_H
  4. #define _GNU_SOURCE
  5. #include <string.h>
  6. #include <stdarg.h>
  7. #include <stdio.h>
  8. #include <stdint.h>
  9. #include <stdbool.h>
  10. #include <signal.h>
  11. #include <assert.h>
  12. #include <stdlib.h>
  13. #include <ucontext.h>
  14. #include <sys/mman.h>
  15. #include "../kselftest.h"
  16. /* Define some kernel-like types */
  17. #define u8 __u8
  18. #define u16 __u16
  19. #define u32 __u32
  20. #define u64 __u64
  21. #define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
  22. #ifndef DEBUG_LEVEL
  23. #define DEBUG_LEVEL 0
  24. #endif
  25. #define DPRINT_IN_SIGNAL_BUF_SIZE 4096
  26. extern int dprint_in_signal;
  27. extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
  28. extern int test_nr;
  29. extern int iteration_nr;
  30. #ifdef __GNUC__
  31. __printf(1, 2)
  32. #endif
  33. static inline void sigsafe_printf(const char *format, ...)
  34. {
  35. va_list ap;
  36. if (!dprint_in_signal) {
  37. va_start(ap, format);
  38. vprintf(format, ap);
  39. va_end(ap);
  40. } else {
  41. int ret;
  42. /*
  43. * No printf() functions are signal-safe.
  44. * They deadlock easily. Write the format
  45. * string to get some output, even if
  46. * incomplete.
  47. */
  48. ret = write(1, format, strlen(format));
  49. if (ret < 0)
  50. exit(1);
  51. }
  52. }
  53. #define dprintf_level(level, args...) do { \
  54. if (level <= DEBUG_LEVEL) \
  55. sigsafe_printf(args); \
  56. } while (0)
  57. #define dprintf0(args...) dprintf_level(0, args)
  58. #define dprintf1(args...) dprintf_level(1, args)
  59. #define dprintf2(args...) dprintf_level(2, args)
  60. #define dprintf3(args...) dprintf_level(3, args)
  61. #define dprintf4(args...) dprintf_level(4, args)
  62. extern void abort_hooks(void);
  63. #define pkey_assert(condition) do { \
  64. if (!(condition)) { \
  65. dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
  66. __FILE__, __LINE__, \
  67. test_nr, iteration_nr); \
  68. dprintf0("errno at assert: %d", errno); \
  69. abort_hooks(); \
  70. exit(__LINE__); \
  71. } \
  72. } while (0)
  73. #define barrier() __asm__ __volatile__("": : :"memory")
  74. #ifndef noinline
  75. # define noinline __attribute__((noinline))
  76. #endif
  77. noinline int read_ptr(int *ptr)
  78. {
  79. /* Keep GCC from optimizing this away somehow */
  80. barrier();
  81. return *ptr;
  82. }
  83. void expected_pkey_fault(int pkey);
  84. int sys_pkey_alloc(unsigned long flags, unsigned long init_val);
  85. int sys_pkey_free(unsigned long pkey);
  86. int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
  87. unsigned long pkey);
  88. void record_pkey_malloc(void *ptr, long size, int prot);
  89. #if defined(__i386__) || defined(__x86_64__) /* arch */
  90. #include "pkey-x86.h"
  91. #elif defined(__powerpc64__) /* arch */
  92. #include "pkey-powerpc.h"
  93. #elif defined(__aarch64__) /* arch */
  94. #include "pkey-arm64.h"
  95. #else /* arch */
  96. #error Architecture not supported
  97. #endif /* arch */
  98. #ifndef PKEY_MASK
  99. #define PKEY_MASK (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
  100. #endif
  101. #ifndef set_pkey_bits
  102. static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
  103. {
  104. u32 shift = pkey_bit_position(pkey);
  105. /* mask out bits from pkey in old value */
  106. reg &= ~((u64)PKEY_MASK << shift);
  107. /* OR in new bits for pkey */
  108. reg |= (flags & PKEY_MASK) << shift;
  109. return reg;
  110. }
  111. #endif
  112. #ifndef get_pkey_bits
  113. static inline u64 get_pkey_bits(u64 reg, int pkey)
  114. {
  115. u32 shift = pkey_bit_position(pkey);
  116. /*
  117. * shift down the relevant bits to the lowest two, then
  118. * mask off all the other higher bits
  119. */
  120. return ((reg >> shift) & PKEY_MASK);
  121. }
  122. #endif
  123. extern u64 shadow_pkey_reg;
  124. static inline u64 _read_pkey_reg(int line)
  125. {
  126. u64 pkey_reg = __read_pkey_reg();
  127. dprintf4("read_pkey_reg(line=%d) pkey_reg: %016llx"
  128. " shadow: %016llx\n",
  129. line, pkey_reg, shadow_pkey_reg);
  130. assert(pkey_reg == shadow_pkey_reg);
  131. return pkey_reg;
  132. }
  133. #define read_pkey_reg() _read_pkey_reg(__LINE__)
  134. static inline void write_pkey_reg(u64 pkey_reg)
  135. {
  136. dprintf4("%s() changing %016llx to %016llx\n", __func__,
  137. __read_pkey_reg(), pkey_reg);
  138. /* will do the shadow check for us: */
  139. read_pkey_reg();
  140. __write_pkey_reg(pkey_reg);
  141. shadow_pkey_reg = pkey_reg;
  142. dprintf4("%s(%016llx) pkey_reg: %016llx\n", __func__,
  143. pkey_reg, __read_pkey_reg());
  144. }
  145. /*
  146. * These are technically racy. since something could
  147. * change PKEY register between the read and the write.
  148. */
  149. static inline void __pkey_access_allow(int pkey, int do_allow)
  150. {
  151. u64 pkey_reg = read_pkey_reg();
  152. int bit = pkey * 2;
  153. if (do_allow)
  154. pkey_reg &= (1<<bit);
  155. else
  156. pkey_reg |= (1<<bit);
  157. dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
  158. write_pkey_reg(pkey_reg);
  159. }
  160. static inline void __pkey_write_allow(int pkey, int do_allow_write)
  161. {
  162. u64 pkey_reg = read_pkey_reg();
  163. int bit = pkey * 2 + 1;
  164. if (do_allow_write)
  165. pkey_reg &= (1<<bit);
  166. else
  167. pkey_reg |= (1<<bit);
  168. write_pkey_reg(pkey_reg);
  169. dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
  170. }
  171. #define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1))
  172. #define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
  173. #define ALIGN_PTR_UP(p, ptr_align_to) \
  174. ((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
  175. #define ALIGN_PTR_DOWN(p, ptr_align_to) \
  176. ((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
  177. #define __stringify_1(x...) #x
  178. #define __stringify(x...) __stringify_1(x)
  179. static inline u32 *siginfo_get_pkey_ptr(siginfo_t *si)
  180. {
  181. #ifdef si_pkey
  182. return &si->si_pkey;
  183. #else
  184. return (u32 *)(((u8 *)si) + si_pkey_offset);
  185. #endif
  186. }
  187. static inline int kernel_has_pkeys(void)
  188. {
  189. /* try allocating a key and see if it succeeds */
  190. int ret = sys_pkey_alloc(0, 0);
  191. if (ret <= 0) {
  192. return 0;
  193. }
  194. sys_pkey_free(ret);
  195. return 1;
  196. }
  197. static inline int is_pkeys_supported(void)
  198. {
  199. /* check if the cpu supports pkeys */
  200. if (!cpu_has_pkeys()) {
  201. dprintf1("SKIP: %s: no CPU support\n", __func__);
  202. return 0;
  203. }
  204. /* check if the kernel supports pkeys */
  205. if (!kernel_has_pkeys()) {
  206. dprintf1("SKIP: %s: no kernel support\n", __func__);
  207. return 0;
  208. }
  209. return 1;
  210. }
  211. #endif /* _PKEYS_HELPER_H */