0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define _GNU_SOURCE
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <signal.h>
0017
0018 #include <unistd.h>
0019 #include <pthread.h>
0020 #include <sys/mman.h>
0021
0022 #include "pkeys.h"
0023
0024 #define PPC_INST_NOP 0x60000000
0025 #define PPC_INST_BLR 0x4e800020
0026 #define PROT_RWX (PROT_READ | PROT_WRITE | PROT_EXEC)
0027
0028 #define NUM_ITERATIONS 1000000
0029
0030 static volatile sig_atomic_t perm_pkey, rest_pkey;
0031 static volatile sig_atomic_t rights, fault_count;
0032 static volatile unsigned int *volatile fault_addr;
0033 static pthread_barrier_t iteration_barrier;
0034
0035 static void segv_handler(int signum, siginfo_t *sinfo, void *ctx)
0036 {
0037 void *pgstart;
0038 size_t pgsize;
0039 int pkey;
0040
0041 pkey = siginfo_pkey(sinfo);
0042
0043
0044 if (sinfo->si_code != SEGV_PKUERR) {
0045 sigsafe_err("got a fault for an unexpected reason\n");
0046 _exit(1);
0047 }
0048
0049
0050 if (sinfo->si_addr != (void *) fault_addr) {
0051 sigsafe_err("got a fault for an unexpected address\n");
0052 _exit(1);
0053 }
0054
0055
0056 if (pkey != rest_pkey) {
0057 sigsafe_err("got a fault for an unexpected pkey\n");
0058 _exit(1);
0059 }
0060
0061
0062 if (fault_count > 0) {
0063 sigsafe_err("got too many faults for the same address\n");
0064 _exit(1);
0065 }
0066
0067 pgsize = getpagesize();
0068 pgstart = (void *) ((unsigned long) fault_addr & ~(pgsize - 1));
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 if (rights == PKEY_DISABLE_EXECUTE &&
0083 mprotect(pgstart, pgsize, PROT_EXEC))
0084 _exit(1);
0085 else
0086 pkey_set_rights(pkey, 0);
0087
0088 fault_count++;
0089 }
0090
0091 struct region {
0092 unsigned long rights;
0093 unsigned int *base;
0094 size_t size;
0095 };
0096
0097 static void *protect(void *p)
0098 {
0099 unsigned long rights;
0100 unsigned int *base;
0101 size_t size;
0102 int tid, i;
0103
0104 tid = gettid();
0105 base = ((struct region *) p)->base;
0106 size = ((struct region *) p)->size;
0107 FAIL_IF_EXIT(!base);
0108
0109
0110 rights = 0;
0111
0112 printf("tid %d, pkey permissions are %s\n", tid, pkey_rights(rights));
0113
0114
0115 perm_pkey = sys_pkey_alloc(0, rights);
0116 FAIL_IF_EXIT(perm_pkey < 0);
0117
0118
0119
0120
0121
0122 for (i = 0; i < NUM_ITERATIONS; i++) {
0123
0124
0125
0126
0127 pthread_barrier_wait(&iteration_barrier);
0128
0129
0130 FAIL_IF_EXIT(sys_pkey_mprotect(base, size, PROT_RWX,
0131 perm_pkey));
0132 }
0133
0134
0135 sys_pkey_free(perm_pkey);
0136
0137 return NULL;
0138 }
0139
0140 static void *protect_access(void *p)
0141 {
0142 size_t size, numinsns;
0143 unsigned int *base;
0144 int tid, i;
0145
0146 tid = gettid();
0147 base = ((struct region *) p)->base;
0148 size = ((struct region *) p)->size;
0149 rights = ((struct region *) p)->rights;
0150 numinsns = size / sizeof(base[0]);
0151 FAIL_IF_EXIT(!base);
0152
0153
0154 rest_pkey = sys_pkey_alloc(0, rights);
0155 FAIL_IF_EXIT(rest_pkey < 0);
0156
0157 printf("tid %d, pkey permissions are %s\n", tid, pkey_rights(rights));
0158 printf("tid %d, %s randomly in range [%p, %p]\n", tid,
0159 (rights == PKEY_DISABLE_EXECUTE) ? "execute" :
0160 (rights == PKEY_DISABLE_WRITE) ? "write" : "read",
0161 base, base + numinsns);
0162
0163
0164
0165
0166
0167 for (i = 0; i < NUM_ITERATIONS; i++) {
0168
0169
0170
0171
0172 pthread_barrier_wait(&iteration_barrier);
0173
0174
0175 FAIL_IF_EXIT(sys_pkey_mprotect(base, size, PROT_RWX,
0176 rest_pkey));
0177
0178
0179 fault_addr = base + (rand() % numinsns);
0180 fault_count = 0;
0181
0182 switch (rights) {
0183
0184 case PKEY_DISABLE_ACCESS:
0185
0186
0187
0188
0189
0190 FAIL_IF_EXIT(*fault_addr != PPC_INST_NOP &&
0191 *fault_addr != PPC_INST_BLR);
0192 break;
0193
0194
0195 case PKEY_DISABLE_WRITE:
0196
0197
0198
0199
0200 *fault_addr = PPC_INST_BLR;
0201 FAIL_IF_EXIT(*fault_addr != PPC_INST_BLR);
0202 break;
0203
0204
0205 case PKEY_DISABLE_EXECUTE:
0206
0207 asm volatile(
0208 "mtctr %0; bctrl"
0209 : : "r"(fault_addr) : "ctr", "lr");
0210 break;
0211 }
0212
0213
0214
0215
0216
0217
0218 pkey_set_rights(rest_pkey, rights);
0219 }
0220
0221
0222 sys_pkey_free(rest_pkey);
0223
0224 return NULL;
0225 }
0226
0227 static void reset_pkeys(unsigned long rights)
0228 {
0229 int pkeys[NR_PKEYS], i;
0230
0231
0232 for (i = 0; i < NR_PKEYS; i++)
0233 pkeys[i] = sys_pkey_alloc(0, rights);
0234
0235
0236 for (i = 0; i < NR_PKEYS; i++)
0237 sys_pkey_free(pkeys[i]);
0238 }
0239
0240 static int test(void)
0241 {
0242 pthread_t prot_thread, pacc_thread;
0243 struct sigaction act;
0244 pthread_attr_t attr;
0245 size_t numinsns;
0246 struct region r;
0247 int ret, i;
0248
0249 srand(time(NULL));
0250 ret = pkeys_unsupported();
0251 if (ret)
0252 return ret;
0253
0254
0255 r.size = getpagesize();
0256 r.base = mmap(NULL, r.size, PROT_RWX,
0257 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
0258 FAIL_IF(r.base == MAP_FAILED);
0259
0260
0261
0262
0263
0264 numinsns = r.size / sizeof(r.base[0]);
0265 for (i = 0; i < numinsns - 1; i++)
0266 r.base[i] = PPC_INST_NOP;
0267 r.base[i] = PPC_INST_BLR;
0268
0269
0270 act.sa_handler = 0;
0271 act.sa_sigaction = segv_handler;
0272 FAIL_IF(sigprocmask(SIG_SETMASK, 0, &act.sa_mask) != 0);
0273 act.sa_flags = SA_SIGINFO;
0274 act.sa_restorer = 0;
0275 FAIL_IF(sigaction(SIGSEGV, &act, NULL) != 0);
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292 reset_pkeys(0);
0293
0294
0295 FAIL_IF(pthread_attr_init(&attr) != 0);
0296 FAIL_IF(pthread_barrier_init(&iteration_barrier, NULL, 2) != 0);
0297
0298
0299 puts("starting thread pair (protect, protect-and-read)");
0300 r.rights = PKEY_DISABLE_ACCESS;
0301 FAIL_IF(pthread_create(&prot_thread, &attr, &protect, &r) != 0);
0302 FAIL_IF(pthread_create(&pacc_thread, &attr, &protect_access, &r) != 0);
0303 FAIL_IF(pthread_join(prot_thread, NULL) != 0);
0304 FAIL_IF(pthread_join(pacc_thread, NULL) != 0);
0305
0306
0307 puts("starting thread pair (protect, protect-and-write)");
0308 r.rights = PKEY_DISABLE_WRITE;
0309 FAIL_IF(pthread_create(&prot_thread, &attr, &protect, &r) != 0);
0310 FAIL_IF(pthread_create(&pacc_thread, &attr, &protect_access, &r) != 0);
0311 FAIL_IF(pthread_join(prot_thread, NULL) != 0);
0312 FAIL_IF(pthread_join(pacc_thread, NULL) != 0);
0313
0314
0315 puts("starting thread pair (protect, protect-and-execute)");
0316 r.rights = PKEY_DISABLE_EXECUTE;
0317 FAIL_IF(pthread_create(&prot_thread, &attr, &protect, &r) != 0);
0318 FAIL_IF(pthread_create(&pacc_thread, &attr, &protect_access, &r) != 0);
0319 FAIL_IF(pthread_join(prot_thread, NULL) != 0);
0320 FAIL_IF(pthread_join(pacc_thread, NULL) != 0);
0321
0322
0323 FAIL_IF(pthread_attr_destroy(&attr) != 0);
0324 FAIL_IF(pthread_barrier_destroy(&iteration_barrier) != 0);
0325 munmap(r.base, r.size);
0326
0327 return 0;
0328 }
0329
0330 int main(void)
0331 {
0332 return test_harness(test, "pkey_siginfo");
0333 }