Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _PKEYS_HELPER_H
0003 #define _PKEYS_HELPER_H
0004 #define _GNU_SOURCE
0005 #include <string.h>
0006 #include <stdarg.h>
0007 #include <stdio.h>
0008 #include <stdint.h>
0009 #include <stdbool.h>
0010 #include <signal.h>
0011 #include <assert.h>
0012 #include <stdlib.h>
0013 #include <ucontext.h>
0014 #include <sys/mman.h>
0015 
0016 #include "../kselftest.h"
0017 
0018 /* Define some kernel-like types */
0019 #define  u8 __u8
0020 #define u16 __u16
0021 #define u32 __u32
0022 #define u64 __u64
0023 
0024 #define PTR_ERR_ENOTSUP ((void *)-ENOTSUP)
0025 
0026 #ifndef DEBUG_LEVEL
0027 #define DEBUG_LEVEL 0
0028 #endif
0029 #define DPRINT_IN_SIGNAL_BUF_SIZE 4096
0030 extern int dprint_in_signal;
0031 extern char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
0032 
0033 extern int test_nr;
0034 extern int iteration_nr;
0035 
0036 #ifdef __GNUC__
0037 __attribute__((format(printf, 1, 2)))
0038 #endif
0039 static inline void sigsafe_printf(const char *format, ...)
0040 {
0041     va_list ap;
0042 
0043     if (!dprint_in_signal) {
0044         va_start(ap, format);
0045         vprintf(format, ap);
0046         va_end(ap);
0047     } else {
0048         int ret;
0049         /*
0050          * No printf() functions are signal-safe.
0051          * They deadlock easily. Write the format
0052          * string to get some output, even if
0053          * incomplete.
0054          */
0055         ret = write(1, format, strlen(format));
0056         if (ret < 0)
0057             exit(1);
0058     }
0059 }
0060 #define dprintf_level(level, args...) do {  \
0061     if (level <= DEBUG_LEVEL)       \
0062         sigsafe_printf(args);       \
0063 } while (0)
0064 #define dprintf0(args...) dprintf_level(0, args)
0065 #define dprintf1(args...) dprintf_level(1, args)
0066 #define dprintf2(args...) dprintf_level(2, args)
0067 #define dprintf3(args...) dprintf_level(3, args)
0068 #define dprintf4(args...) dprintf_level(4, args)
0069 
0070 extern void abort_hooks(void);
0071 #define pkey_assert(condition) do {     \
0072     if (!(condition)) {         \
0073         dprintf0("assert() at %s::%d test_nr: %d iteration: %d\n", \
0074                 __FILE__, __LINE__, \
0075                 test_nr, iteration_nr); \
0076         dprintf0("errno at assert: %d", errno); \
0077         abort_hooks();          \
0078         exit(__LINE__);         \
0079     }                   \
0080 } while (0)
0081 
0082 __attribute__((noinline)) int read_ptr(int *ptr);
0083 void expected_pkey_fault(int pkey);
0084 int sys_pkey_alloc(unsigned long flags, unsigned long init_val);
0085 int sys_pkey_free(unsigned long pkey);
0086 int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
0087         unsigned long pkey);
0088 void record_pkey_malloc(void *ptr, long size, int prot);
0089 
0090 #if defined(__i386__) || defined(__x86_64__) /* arch */
0091 #include "pkey-x86.h"
0092 #elif defined(__powerpc64__) /* arch */
0093 #include "pkey-powerpc.h"
0094 #else /* arch */
0095 #error Architecture not supported
0096 #endif /* arch */
0097 
0098 #define PKEY_MASK   (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)
0099 
0100 static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
0101 {
0102     u32 shift = pkey_bit_position(pkey);
0103     /* mask out bits from pkey in old value */
0104     reg &= ~((u64)PKEY_MASK << shift);
0105     /* OR in new bits for pkey */
0106     reg |= (flags & PKEY_MASK) << shift;
0107     return reg;
0108 }
0109 
0110 static inline u64 get_pkey_bits(u64 reg, int pkey)
0111 {
0112     u32 shift = pkey_bit_position(pkey);
0113     /*
0114      * shift down the relevant bits to the lowest two, then
0115      * mask off all the other higher bits
0116      */
0117     return ((reg >> shift) & PKEY_MASK);
0118 }
0119 
0120 extern u64 shadow_pkey_reg;
0121 
0122 static inline u64 _read_pkey_reg(int line)
0123 {
0124     u64 pkey_reg = __read_pkey_reg();
0125 
0126     dprintf4("read_pkey_reg(line=%d) pkey_reg: %016llx"
0127             " shadow: %016llx\n",
0128             line, pkey_reg, shadow_pkey_reg);
0129     assert(pkey_reg == shadow_pkey_reg);
0130 
0131     return pkey_reg;
0132 }
0133 
0134 #define read_pkey_reg() _read_pkey_reg(__LINE__)
0135 
0136 static inline void write_pkey_reg(u64 pkey_reg)
0137 {
0138     dprintf4("%s() changing %016llx to %016llx\n", __func__,
0139             __read_pkey_reg(), pkey_reg);
0140     /* will do the shadow check for us: */
0141     read_pkey_reg();
0142     __write_pkey_reg(pkey_reg);
0143     shadow_pkey_reg = pkey_reg;
0144     dprintf4("%s(%016llx) pkey_reg: %016llx\n", __func__,
0145             pkey_reg, __read_pkey_reg());
0146 }
0147 
0148 /*
0149  * These are technically racy. since something could
0150  * change PKEY register between the read and the write.
0151  */
0152 static inline void __pkey_access_allow(int pkey, int do_allow)
0153 {
0154     u64 pkey_reg = read_pkey_reg();
0155     int bit = pkey * 2;
0156 
0157     if (do_allow)
0158         pkey_reg &= (1<<bit);
0159     else
0160         pkey_reg |= (1<<bit);
0161 
0162     dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
0163     write_pkey_reg(pkey_reg);
0164 }
0165 
0166 static inline void __pkey_write_allow(int pkey, int do_allow_write)
0167 {
0168     u64 pkey_reg = read_pkey_reg();
0169     int bit = pkey * 2 + 1;
0170 
0171     if (do_allow_write)
0172         pkey_reg &= (1<<bit);
0173     else
0174         pkey_reg |= (1<<bit);
0175 
0176     write_pkey_reg(pkey_reg);
0177     dprintf4("pkey_reg now: %016llx\n", read_pkey_reg());
0178 }
0179 
0180 #define ALIGN_UP(x, align_to)   (((x) + ((align_to)-1)) & ~((align_to)-1))
0181 #define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1))
0182 #define ALIGN_PTR_UP(p, ptr_align_to)   \
0183     ((typeof(p))ALIGN_UP((unsigned long)(p), ptr_align_to))
0184 #define ALIGN_PTR_DOWN(p, ptr_align_to) \
0185     ((typeof(p))ALIGN_DOWN((unsigned long)(p), ptr_align_to))
0186 #define __stringify_1(x...)     #x
0187 #define __stringify(x...)       __stringify_1(x)
0188 
0189 static inline u32 *siginfo_get_pkey_ptr(siginfo_t *si)
0190 {
0191 #ifdef si_pkey
0192     return &si->si_pkey;
0193 #else
0194     return (u32 *)(((u8 *)si) + si_pkey_offset);
0195 #endif
0196 }
0197 
0198 static inline int kernel_has_pkeys(void)
0199 {
0200     /* try allocating a key and see if it succeeds */
0201     int ret = sys_pkey_alloc(0, 0);
0202     if (ret <= 0) {
0203         return 0;
0204     }
0205     sys_pkey_free(ret);
0206     return 1;
0207 }
0208 
0209 static inline int is_pkeys_supported(void)
0210 {
0211     /* check if the cpu supports pkeys */
0212     if (!cpu_has_pkeys()) {
0213         dprintf1("SKIP: %s: no CPU support\n", __func__);
0214         return 0;
0215     }
0216 
0217     /* check if the kernel supports pkeys */
0218     if (!kernel_has_pkeys()) {
0219         dprintf1("SKIP: %s: no kernel support\n", __func__);
0220         return 0;
0221     }
0222 
0223     return 1;
0224 }
0225 
0226 #endif /* _PKEYS_HELPER_H */