~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/protection_keys.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Tests Memory Protection Keys (see Documentation/core-api/protection-keys.rst)
  4  *
  5  * There are examples in here of:
  6  *  * how to set protection keys on memory
  7  *  * how to set/clear bits in pkey registers (the rights register)
  8  *  * how to handle SEGV_PKUERR signals and extract pkey-relevant
  9  *    information from the siginfo
 10  *
 11  * Things to add:
 12  *      make sure KSM and KSM COW breaking works
 13  *      prefault pages in at malloc, or not
 14  *      protect MPX bounds tables with protection keys?
 15  *      make sure VMA splitting/merging is working correctly
 16  *      OOMs can destroy mm->mmap (see exit_mmap()), so make sure it is immune to pkeys
 17  *      look for pkey "leaks" where it is still set on a VMA but "freed" back to the kernel
 18  *      do a plain mprotect() to a mprotect_pkey() area and make sure the pkey sticks
 19  *
 20  * Compile like this:
 21  *      gcc -mxsave      -o protection_keys    -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
 22  *      gcc -mxsave -m32 -o protection_keys_32 -O2 -g -std=gnu99 -pthread -Wall protection_keys.c -lrt -ldl -lm
 23  */
 24 #define _GNU_SOURCE
 25 #define __SANE_USERSPACE_TYPES__
 26 #include <errno.h>
 27 #include <linux/elf.h>
 28 #include <linux/futex.h>
 29 #include <time.h>
 30 #include <sys/time.h>
 31 #include <sys/syscall.h>
 32 #include <string.h>
 33 #include <stdio.h>
 34 #include <stdint.h>
 35 #include <stdbool.h>
 36 #include <signal.h>
 37 #include <assert.h>
 38 #include <stdlib.h>
 39 #include <ucontext.h>
 40 #include <sys/mman.h>
 41 #include <sys/types.h>
 42 #include <sys/wait.h>
 43 #include <sys/stat.h>
 44 #include <fcntl.h>
 45 #include <asm-generic/unistd.h>
 46 #include <sys/ptrace.h>
 47 #include <setjmp.h>
 48 
 49 #include "pkey-helpers.h"
 50 
 51 int iteration_nr = 1;
 52 int test_nr;
 53 
 54 u64 shadow_pkey_reg;
 55 int dprint_in_signal;
 56 char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
 57 
 58 void cat_into_file(char *str, char *file)
 59 {
 60         int fd = open(file, O_RDWR);
 61         int ret;
 62 
 63         dprintf2("%s(): writing '%s' to '%s'\n", __func__, str, file);
 64         /*
 65          * these need to be raw because they are called under
 66          * pkey_assert()
 67          */
 68         if (fd < 0) {
 69                 fprintf(stderr, "error opening '%s'\n", str);
 70                 perror("error: ");
 71                 exit(__LINE__);
 72         }
 73 
 74         ret = write(fd, str, strlen(str));
 75         if (ret != strlen(str)) {
 76                 perror("write to file failed");
 77                 fprintf(stderr, "filename: '%s' str: '%s'\n", file, str);
 78                 exit(__LINE__);
 79         }
 80         close(fd);
 81 }
 82 
 83 #if CONTROL_TRACING > 0
 84 static int warned_tracing;
 85 int tracing_root_ok(void)
 86 {
 87         if (geteuid() != 0) {
 88                 if (!warned_tracing)
 89                         fprintf(stderr, "WARNING: not run as root, "
 90                                         "can not do tracing control\n");
 91                 warned_tracing = 1;
 92                 return 0;
 93         }
 94         return 1;
 95 }
 96 #endif
 97 
 98 void tracing_on(void)
 99 {
100 #if CONTROL_TRACING > 0
101 #define TRACEDIR "/sys/kernel/tracing"
102         char pidstr[32];
103 
104         if (!tracing_root_ok())
105                 return;
106 
107         sprintf(pidstr, "%d", getpid());
108         cat_into_file("", TRACEDIR "/tracing_on");
109         cat_into_file("\n", TRACEDIR "/trace");
110         if (1) {
111                 cat_into_file("function_graph", TRACEDIR "/current_tracer");
112                 cat_into_file("1", TRACEDIR "/options/funcgraph-proc");
113         } else {
114                 cat_into_file("nop", TRACEDIR "/current_tracer");
115         }
116         cat_into_file(pidstr, TRACEDIR "/set_ftrace_pid");
117         cat_into_file("1", TRACEDIR "/tracing_on");
118         dprintf1("enabled tracing\n");
119 #endif
120 }
121 
122 void tracing_off(void)
123 {
124 #if CONTROL_TRACING > 0
125         if (!tracing_root_ok())
126                 return;
127         cat_into_file("", "/sys/kernel/tracing/tracing_on");
128 #endif
129 }
130 
131 void abort_hooks(void)
132 {
133         fprintf(stderr, "running %s()...\n", __func__);
134         tracing_off();
135 #ifdef SLEEP_ON_ABORT
136         sleep(SLEEP_ON_ABORT);
137 #endif
138 }
139 
140 /*
141  * This attempts to have roughly a page of instructions followed by a few
142  * instructions that do a write, and another page of instructions.  That
143  * way, we are pretty sure that the write is in the second page of
144  * instructions and has at least a page of padding behind it.
145  *
146  * *That* lets us be sure to madvise() away the write instruction, which
147  * will then fault, which makes sure that the fault code handles
148  * execute-only memory properly.
149  */
150 #ifdef __powerpc64__
151 /* This way, both 4K and 64K alignment are maintained */
152 __attribute__((__aligned__(65536)))
153 #else
154 __attribute__((__aligned__(PAGE_SIZE)))
155 #endif
156 void lots_o_noops_around_write(int *write_to_me)
157 {
158         dprintf3("running %s()\n", __func__);
159         __page_o_noops();
160         /* Assume this happens in the second page of instructions: */
161         *write_to_me = __LINE__;
162         /* pad out by another page: */
163         __page_o_noops();
164         dprintf3("%s() done\n", __func__);
165 }
166 
167 void dump_mem(void *dumpme, int len_bytes)
168 {
169         char *c = (void *)dumpme;
170         int i;
171 
172         for (i = 0; i < len_bytes; i += sizeof(u64)) {
173                 u64 *ptr = (u64 *)(c + i);
174                 dprintf1("dump[%03d][@%p]: %016llx\n", i, ptr, *ptr);
175         }
176 }
177 
178 static u32 hw_pkey_get(int pkey, unsigned long flags)
179 {
180         u64 pkey_reg = __read_pkey_reg();
181 
182         dprintf1("%s(pkey=%d, flags=%lx) = %x / %d\n",
183                         __func__, pkey, flags, 0, 0);
184         dprintf2("%s() raw pkey_reg: %016llx\n", __func__, pkey_reg);
185 
186         return (u32) get_pkey_bits(pkey_reg, pkey);
187 }
188 
189 static int hw_pkey_set(int pkey, unsigned long rights, unsigned long flags)
190 {
191         u32 mask = (PKEY_DISABLE_ACCESS|PKEY_DISABLE_WRITE);
192         u64 old_pkey_reg = __read_pkey_reg();
193         u64 new_pkey_reg;
194 
195         /* make sure that 'rights' only contains the bits we expect: */
196         assert(!(rights & ~mask));
197 
198         /* modify bits accordingly in old pkey_reg and assign it */
199         new_pkey_reg = set_pkey_bits(old_pkey_reg, pkey, rights);
200 
201         __write_pkey_reg(new_pkey_reg);
202 
203         dprintf3("%s(pkey=%d, rights=%lx, flags=%lx) = %x"
204                 " pkey_reg now: %016llx old_pkey_reg: %016llx\n",
205                 __func__, pkey, rights, flags, 0, __read_pkey_reg(),
206                 old_pkey_reg);
207         return 0;
208 }
209 
210 void pkey_disable_set(int pkey, int flags)
211 {
212         unsigned long syscall_flags = 0;
213         int ret;
214         int pkey_rights;
215         u64 orig_pkey_reg = read_pkey_reg();
216 
217         dprintf1("START->%s(%d, 0x%x)\n", __func__,
218                 pkey, flags);
219         pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
220 
221         pkey_rights = hw_pkey_get(pkey, syscall_flags);
222 
223         dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
224                         pkey, pkey, pkey_rights);
225 
226         pkey_assert(pkey_rights >= 0);
227 
228         pkey_rights |= flags;
229 
230         ret = hw_pkey_set(pkey, pkey_rights, syscall_flags);
231         assert(!ret);
232         /* pkey_reg and flags have the same format */
233         shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights);
234         dprintf1("%s(%d) shadow: 0x%016llx\n",
235                 __func__, pkey, shadow_pkey_reg);
236 
237         pkey_assert(ret >= 0);
238 
239         pkey_rights = hw_pkey_get(pkey, syscall_flags);
240         dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
241                         pkey, pkey, pkey_rights);
242 
243         dprintf1("%s(%d) pkey_reg: 0x%016llx\n",
244                 __func__, pkey, read_pkey_reg());
245         if (flags)
246                 pkey_assert(read_pkey_reg() >= orig_pkey_reg);
247         dprintf1("END<---%s(%d, 0x%x)\n", __func__,
248                 pkey, flags);
249 }
250 
251 void pkey_disable_clear(int pkey, int flags)
252 {
253         unsigned long syscall_flags = 0;
254         int ret;
255         int pkey_rights = hw_pkey_get(pkey, syscall_flags);
256         u64 orig_pkey_reg = read_pkey_reg();
257 
258         pkey_assert(flags & (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE));
259 
260         dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
261                         pkey, pkey, pkey_rights);
262         pkey_assert(pkey_rights >= 0);
263 
264         pkey_rights &= ~flags;
265 
266         ret = hw_pkey_set(pkey, pkey_rights, 0);
267         shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, pkey, pkey_rights);
268         pkey_assert(ret >= 0);
269 
270         pkey_rights = hw_pkey_get(pkey, syscall_flags);
271         dprintf1("%s(%d) hw_pkey_get(%d): %x\n", __func__,
272                         pkey, pkey, pkey_rights);
273 
274         dprintf1("%s(%d) pkey_reg: 0x%016llx\n", __func__,
275                         pkey, read_pkey_reg());
276         if (flags)
277                 assert(read_pkey_reg() <= orig_pkey_reg);
278 }
279 
280 void pkey_write_allow(int pkey)
281 {
282         pkey_disable_clear(pkey, PKEY_DISABLE_WRITE);
283 }
284 void pkey_write_deny(int pkey)
285 {
286         pkey_disable_set(pkey, PKEY_DISABLE_WRITE);
287 }
288 void pkey_access_allow(int pkey)
289 {
290         pkey_disable_clear(pkey, PKEY_DISABLE_ACCESS);
291 }
292 void pkey_access_deny(int pkey)
293 {
294         pkey_disable_set(pkey, PKEY_DISABLE_ACCESS);
295 }
296 
297 static char *si_code_str(int si_code)
298 {
299         if (si_code == SEGV_MAPERR)
300                 return "SEGV_MAPERR";
301         if (si_code == SEGV_ACCERR)
302                 return "SEGV_ACCERR";
303         if (si_code == SEGV_BNDERR)
304                 return "SEGV_BNDERR";
305         if (si_code == SEGV_PKUERR)
306                 return "SEGV_PKUERR";
307         return "UNKNOWN";
308 }
309 
310 int pkey_faults;
311 int last_si_pkey = -1;
312 void signal_handler(int signum, siginfo_t *si, void *vucontext)
313 {
314         ucontext_t *uctxt = vucontext;
315         int trapno;
316         unsigned long ip;
317         char *fpregs;
318 #if defined(__i386__) || defined(__x86_64__) /* arch */
319         u32 *pkey_reg_ptr;
320         int pkey_reg_offset;
321 #endif /* arch */
322         u64 siginfo_pkey;
323         u32 *si_pkey_ptr;
324 
325         dprint_in_signal = 1;
326         dprintf1(">>>>===============SIGSEGV============================\n");
327         dprintf1("%s()::%d, pkey_reg: 0x%016llx shadow: %016llx\n",
328                         __func__, __LINE__,
329                         __read_pkey_reg(), shadow_pkey_reg);
330 
331         trapno = uctxt->uc_mcontext.gregs[REG_TRAPNO];
332         ip = uctxt->uc_mcontext.gregs[REG_IP_IDX];
333         fpregs = (char *) uctxt->uc_mcontext.fpregs;
334 
335         dprintf2("%s() trapno: %d ip: 0x%016lx info->si_code: %s/%d\n",
336                         __func__, trapno, ip, si_code_str(si->si_code),
337                         si->si_code);
338 
339 #if defined(__i386__) || defined(__x86_64__) /* arch */
340 #ifdef __i386__
341         /*
342          * 32-bit has some extra padding so that userspace can tell whether
343          * the XSTATE header is present in addition to the "legacy" FPU
344          * state.  We just assume that it is here.
345          */
346         fpregs += 0x70;
347 #endif /* i386 */
348         pkey_reg_offset = pkey_reg_xstate_offset();
349         pkey_reg_ptr = (void *)(&fpregs[pkey_reg_offset]);
350 
351         /*
352          * If we got a PKEY fault, we *HAVE* to have at least one bit set in
353          * here.
354          */
355         dprintf1("pkey_reg_xstate_offset: %d\n", pkey_reg_xstate_offset());
356         if (DEBUG_LEVEL > 4)
357                 dump_mem(pkey_reg_ptr - 128, 256);
358         pkey_assert(*pkey_reg_ptr);
359 #endif /* arch */
360 
361         dprintf1("siginfo: %p\n", si);
362         dprintf1(" fpregs: %p\n", fpregs);
363 
364         if ((si->si_code == SEGV_MAPERR) ||
365             (si->si_code == SEGV_ACCERR) ||
366             (si->si_code == SEGV_BNDERR)) {
367                 printf("non-PK si_code, exiting...\n");
368                 exit(4);
369         }
370 
371         si_pkey_ptr = siginfo_get_pkey_ptr(si);
372         dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr);
373         dump_mem((u8 *)si_pkey_ptr - 8, 24);
374         siginfo_pkey = *si_pkey_ptr;
375         pkey_assert(siginfo_pkey < NR_PKEYS);
376         last_si_pkey = siginfo_pkey;
377 
378         /*
379          * need __read_pkey_reg() version so we do not do shadow_pkey_reg
380          * checking
381          */
382         dprintf1("signal pkey_reg from  pkey_reg: %016llx\n",
383                         __read_pkey_reg());
384         dprintf1("pkey from siginfo: %016llx\n", siginfo_pkey);
385 #if defined(__i386__) || defined(__x86_64__) /* arch */
386         dprintf1("signal pkey_reg from xsave: %08x\n", *pkey_reg_ptr);
387         *(u64 *)pkey_reg_ptr = 0x00000000;
388         dprintf1("WARNING: set PKEY_REG=0 to allow faulting instruction to continue\n");
389 #elif defined(__powerpc64__) /* arch */
390         /* restore access and let the faulting instruction continue */
391         pkey_access_allow(siginfo_pkey);
392 #endif /* arch */
393         pkey_faults++;
394         dprintf1("<<<<==================================================\n");
395         dprint_in_signal = 0;
396 }
397 
398 int wait_all_children(void)
399 {
400         int status;
401         return waitpid(-1, &status, 0);
402 }
403 
404 void sig_chld(int x)
405 {
406         dprint_in_signal = 1;
407         dprintf2("[%d] SIGCHLD: %d\n", getpid(), x);
408         dprint_in_signal = 0;
409 }
410 
411 void setup_sigsegv_handler(void)
412 {
413         int r, rs;
414         struct sigaction newact;
415         struct sigaction oldact;
416 
417         /* #PF is mapped to sigsegv */
418         int signum  = SIGSEGV;
419 
420         newact.sa_handler = 0;
421         newact.sa_sigaction = signal_handler;
422 
423         /*sigset_t - signals to block while in the handler */
424         /* get the old signal mask. */
425         rs = sigprocmask(SIG_SETMASK, 0, &newact.sa_mask);
426         pkey_assert(rs == 0);
427 
428         /* call sa_sigaction, not sa_handler*/
429         newact.sa_flags = SA_SIGINFO;
430 
431         newact.sa_restorer = 0;  /* void(*)(), obsolete */
432         r = sigaction(signum, &newact, &oldact);
433         r = sigaction(SIGALRM, &newact, &oldact);
434         pkey_assert(r == 0);
435 }
436 
437 void setup_handlers(void)
438 {
439         signal(SIGCHLD, &sig_chld);
440         setup_sigsegv_handler();
441 }
442 
443 pid_t fork_lazy_child(void)
444 {
445         pid_t forkret;
446 
447         forkret = fork();
448         pkey_assert(forkret >= 0);
449         dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
450 
451         if (!forkret) {
452                 /* in the child */
453                 while (1) {
454                         dprintf1("child sleeping...\n");
455                         sleep(30);
456                 }
457         }
458         return forkret;
459 }
460 
461 int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
462                 unsigned long pkey)
463 {
464         int sret;
465 
466         dprintf2("%s(0x%p, %zx, prot=%lx, pkey=%lx)\n", __func__,
467                         ptr, size, orig_prot, pkey);
468 
469         errno = 0;
470         sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey);
471         if (errno) {
472                 dprintf2("SYS_mprotect_key sret: %d\n", sret);
473                 dprintf2("SYS_mprotect_key prot: 0x%lx\n", orig_prot);
474                 dprintf2("SYS_mprotect_key failed, errno: %d\n", errno);
475                 if (DEBUG_LEVEL >= 2)
476                         perror("SYS_mprotect_pkey");
477         }
478         return sret;
479 }
480 
481 int sys_pkey_alloc(unsigned long flags, unsigned long init_val)
482 {
483         int ret = syscall(SYS_pkey_alloc, flags, init_val);
484         dprintf1("%s(flags=%lx, init_val=%lx) syscall ret: %d errno: %d\n",
485                         __func__, flags, init_val, ret, errno);
486         return ret;
487 }
488 
489 int alloc_pkey(void)
490 {
491         int ret;
492         unsigned long init_val = 0x0;
493 
494         dprintf1("%s()::%d, pkey_reg: 0x%016llx shadow: %016llx\n",
495                         __func__, __LINE__, __read_pkey_reg(), shadow_pkey_reg);
496         ret = sys_pkey_alloc(0, init_val);
497         /*
498          * pkey_alloc() sets PKEY register, so we need to reflect it in
499          * shadow_pkey_reg:
500          */
501         dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
502                         " shadow: 0x%016llx\n",
503                         __func__, __LINE__, ret, __read_pkey_reg(),
504                         shadow_pkey_reg);
505         if (ret > 0) {
506                 /* clear both the bits: */
507                 shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
508                                                 ~PKEY_MASK);
509                 dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
510                                 " shadow: 0x%016llx\n",
511                                 __func__,
512                                 __LINE__, ret, __read_pkey_reg(),
513                                 shadow_pkey_reg);
514                 /*
515                  * move the new state in from init_val
516                  * (remember, we cheated and init_val == pkey_reg format)
517                  */
518                 shadow_pkey_reg = set_pkey_bits(shadow_pkey_reg, ret,
519                                                 init_val);
520         }
521         dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
522                         " shadow: 0x%016llx\n",
523                         __func__, __LINE__, ret, __read_pkey_reg(),
524                         shadow_pkey_reg);
525         dprintf1("%s()::%d errno: %d\n", __func__, __LINE__, errno);
526         /* for shadow checking: */
527         read_pkey_reg();
528         dprintf4("%s()::%d, ret: %d pkey_reg: 0x%016llx"
529                  " shadow: 0x%016llx\n",
530                 __func__, __LINE__, ret, __read_pkey_reg(),
531                 shadow_pkey_reg);
532         return ret;
533 }
534 
535 int sys_pkey_free(unsigned long pkey)
536 {
537         int ret = syscall(SYS_pkey_free, pkey);
538         dprintf1("%s(pkey=%ld) syscall ret: %d\n", __func__, pkey, ret);
539         return ret;
540 }
541 
542 /*
543  * I had a bug where pkey bits could be set by mprotect() but
544  * not cleared.  This ensures we get lots of random bit sets
545  * and clears on the vma and pte pkey bits.
546  */
547 int alloc_random_pkey(void)
548 {
549         int max_nr_pkey_allocs;
550         int ret;
551         int i;
552         int alloced_pkeys[NR_PKEYS];
553         int nr_alloced = 0;
554         int random_index;
555         memset(alloced_pkeys, 0, sizeof(alloced_pkeys));
556 
557         /* allocate every possible key and make a note of which ones we got */
558         max_nr_pkey_allocs = NR_PKEYS;
559         for (i = 0; i < max_nr_pkey_allocs; i++) {
560                 int new_pkey = alloc_pkey();
561                 if (new_pkey < 0)
562                         break;
563                 alloced_pkeys[nr_alloced++] = new_pkey;
564         }
565 
566         pkey_assert(nr_alloced > 0);
567         /* select a random one out of the allocated ones */
568         random_index = rand() % nr_alloced;
569         ret = alloced_pkeys[random_index];
570         /* now zero it out so we don't free it next */
571         alloced_pkeys[random_index] = 0;
572 
573         /* go through the allocated ones that we did not want and free them */
574         for (i = 0; i < nr_alloced; i++) {
575                 int free_ret;
576                 if (!alloced_pkeys[i])
577                         continue;
578                 free_ret = sys_pkey_free(alloced_pkeys[i]);
579                 pkey_assert(!free_ret);
580         }
581         dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx"
582                          " shadow: 0x%016llx\n", __func__,
583                         __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg);
584         return ret;
585 }
586 
587 int mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
588                 unsigned long pkey)
589 {
590         int nr_iterations = random() % 100;
591         int ret;
592 
593         while (0) {
594                 int rpkey = alloc_random_pkey();
595                 ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
596                 dprintf1("sys_mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
597                                 ptr, size, orig_prot, pkey, ret);
598                 if (nr_iterations-- < 0)
599                         break;
600 
601                 dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx"
602                         " shadow: 0x%016llx\n",
603                         __func__, __LINE__, ret, __read_pkey_reg(),
604                         shadow_pkey_reg);
605                 sys_pkey_free(rpkey);
606                 dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx"
607                         " shadow: 0x%016llx\n",
608                         __func__, __LINE__, ret, __read_pkey_reg(),
609                         shadow_pkey_reg);
610         }
611         pkey_assert(pkey < NR_PKEYS);
612 
613         ret = sys_mprotect_pkey(ptr, size, orig_prot, pkey);
614         dprintf1("mprotect_pkey(%p, %zx, prot=0x%lx, pkey=%ld) ret: %d\n",
615                         ptr, size, orig_prot, pkey, ret);
616         pkey_assert(!ret);
617         dprintf1("%s()::%d, ret: %d pkey_reg: 0x%016llx"
618                         " shadow: 0x%016llx\n", __func__,
619                         __LINE__, ret, __read_pkey_reg(), shadow_pkey_reg);
620         return ret;
621 }
622 
623 struct pkey_malloc_record {
624         void *ptr;
625         long size;
626         int prot;
627 };
628 struct pkey_malloc_record *pkey_malloc_records;
629 struct pkey_malloc_record *pkey_last_malloc_record;
630 long nr_pkey_malloc_records;
631 void record_pkey_malloc(void *ptr, long size, int prot)
632 {
633         long i;
634         struct pkey_malloc_record *rec = NULL;
635 
636         for (i = 0; i < nr_pkey_malloc_records; i++) {
637                 rec = &pkey_malloc_records[i];
638                 /* find a free record */
639                 if (rec)
640                         break;
641         }
642         if (!rec) {
643                 /* every record is full */
644                 size_t old_nr_records = nr_pkey_malloc_records;
645                 size_t new_nr_records = (nr_pkey_malloc_records * 2 + 1);
646                 size_t new_size = new_nr_records * sizeof(struct pkey_malloc_record);
647                 dprintf2("new_nr_records: %zd\n", new_nr_records);
648                 dprintf2("new_size: %zd\n", new_size);
649                 pkey_malloc_records = realloc(pkey_malloc_records, new_size);
650                 pkey_assert(pkey_malloc_records != NULL);
651                 rec = &pkey_malloc_records[nr_pkey_malloc_records];
652                 /*
653                  * realloc() does not initialize memory, so zero it from
654                  * the first new record all the way to the end.
655                  */
656                 for (i = 0; i < new_nr_records - old_nr_records; i++)
657                         memset(rec + i, 0, sizeof(*rec));
658         }
659         dprintf3("filling malloc record[%d/%p]: {%p, %ld}\n",
660                 (int)(rec - pkey_malloc_records), rec, ptr, size);
661         rec->ptr = ptr;
662         rec->size = size;
663         rec->prot = prot;
664         pkey_last_malloc_record = rec;
665         nr_pkey_malloc_records++;
666 }
667 
668 void free_pkey_malloc(void *ptr)
669 {
670         long i;
671         int ret;
672         dprintf3("%s(%p)\n", __func__, ptr);
673         for (i = 0; i < nr_pkey_malloc_records; i++) {
674                 struct pkey_malloc_record *rec = &pkey_malloc_records[i];
675                 dprintf4("looking for ptr %p at record[%ld/%p]: {%p, %ld}\n",
676                                 ptr, i, rec, rec->ptr, rec->size);
677                 if ((ptr <  rec->ptr) ||
678                     (ptr >= rec->ptr + rec->size))
679                         continue;
680 
681                 dprintf3("found ptr %p at record[%ld/%p]: {%p, %ld}\n",
682                                 ptr, i, rec, rec->ptr, rec->size);
683                 nr_pkey_malloc_records--;
684                 ret = munmap(rec->ptr, rec->size);
685                 dprintf3("munmap ret: %d\n", ret);
686                 pkey_assert(!ret);
687                 dprintf3("clearing rec->ptr, rec: %p\n", rec);
688                 rec->ptr = NULL;
689                 dprintf3("done clearing rec->ptr, rec: %p\n", rec);
690                 return;
691         }
692         pkey_assert(false);
693 }
694 
695 
696 void *malloc_pkey_with_mprotect(long size, int prot, u16 pkey)
697 {
698         void *ptr;
699         int ret;
700 
701         read_pkey_reg();
702         dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
703                         size, prot, pkey);
704         pkey_assert(pkey < NR_PKEYS);
705         ptr = mmap(NULL, size, prot, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
706         pkey_assert(ptr != (void *)-1);
707         ret = mprotect_pkey((void *)ptr, PAGE_SIZE, prot, pkey);
708         pkey_assert(!ret);
709         record_pkey_malloc(ptr, size, prot);
710         read_pkey_reg();
711 
712         dprintf1("%s() for pkey %d @ %p\n", __func__, pkey, ptr);
713         return ptr;
714 }
715 
716 void *malloc_pkey_anon_huge(long size, int prot, u16 pkey)
717 {
718         int ret;
719         void *ptr;
720 
721         dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
722                         size, prot, pkey);
723         /*
724          * Guarantee we can fit at least one huge page in the resulting
725          * allocation by allocating space for 2:
726          */
727         size = ALIGN_UP(size, HPAGE_SIZE * 2);
728         ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
729         pkey_assert(ptr != (void *)-1);
730         record_pkey_malloc(ptr, size, prot);
731         mprotect_pkey(ptr, size, prot, pkey);
732 
733         dprintf1("unaligned ptr: %p\n", ptr);
734         ptr = ALIGN_PTR_UP(ptr, HPAGE_SIZE);
735         dprintf1("  aligned ptr: %p\n", ptr);
736         ret = madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE);
737         dprintf1("MADV_HUGEPAGE ret: %d\n", ret);
738         ret = madvise(ptr, HPAGE_SIZE, MADV_WILLNEED);
739         dprintf1("MADV_WILLNEED ret: %d\n", ret);
740         memset(ptr, 0, HPAGE_SIZE);
741 
742         dprintf1("mmap()'d thp for pkey %d @ %p\n", pkey, ptr);
743         return ptr;
744 }
745 
746 int hugetlb_setup_ok;
747 #define SYSFS_FMT_NR_HUGE_PAGES "/sys/kernel/mm/hugepages/hugepages-%ldkB/nr_hugepages"
748 #define GET_NR_HUGE_PAGES 10
749 void setup_hugetlbfs(void)
750 {
751         int err;
752         int fd;
753         char buf[256];
754         long hpagesz_kb;
755         long hpagesz_mb;
756 
757         if (geteuid() != 0) {
758                 fprintf(stderr, "WARNING: not run as root, can not do hugetlb test\n");
759                 return;
760         }
761 
762         cat_into_file(__stringify(GET_NR_HUGE_PAGES), "/proc/sys/vm/nr_hugepages");
763 
764         /*
765          * Now go make sure that we got the pages and that they
766          * are PMD-level pages. Someone might have made PUD-level
767          * pages the default.
768          */
769         hpagesz_kb = HPAGE_SIZE / 1024;
770         hpagesz_mb = hpagesz_kb / 1024;
771         sprintf(buf, SYSFS_FMT_NR_HUGE_PAGES, hpagesz_kb);
772         fd = open(buf, O_RDONLY);
773         if (fd < 0) {
774                 fprintf(stderr, "opening sysfs %ldM hugetlb config: %s\n",
775                         hpagesz_mb, strerror(errno));
776                 return;
777         }
778 
779         /* -1 to guarantee leaving the trailing \0 */
780         err = read(fd, buf, sizeof(buf)-1);
781         close(fd);
782         if (err <= 0) {
783                 fprintf(stderr, "reading sysfs %ldM hugetlb config: %s\n",
784                         hpagesz_mb, strerror(errno));
785                 return;
786         }
787 
788         if (atoi(buf) != GET_NR_HUGE_PAGES) {
789                 fprintf(stderr, "could not confirm %ldM pages, got: '%s' expected %d\n",
790                         hpagesz_mb, buf, GET_NR_HUGE_PAGES);
791                 return;
792         }
793 
794         hugetlb_setup_ok = 1;
795 }
796 
797 void *malloc_pkey_hugetlb(long size, int prot, u16 pkey)
798 {
799         void *ptr;
800         int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB;
801 
802         if (!hugetlb_setup_ok)
803                 return PTR_ERR_ENOTSUP;
804 
805         dprintf1("doing %s(%ld, %x, %x)\n", __func__, size, prot, pkey);
806         size = ALIGN_UP(size, HPAGE_SIZE * 2);
807         pkey_assert(pkey < NR_PKEYS);
808         ptr = mmap(NULL, size, PROT_NONE, flags, -1, 0);
809         pkey_assert(ptr != (void *)-1);
810         mprotect_pkey(ptr, size, prot, pkey);
811 
812         record_pkey_malloc(ptr, size, prot);
813 
814         dprintf1("mmap()'d hugetlbfs for pkey %d @ %p\n", pkey, ptr);
815         return ptr;
816 }
817 
818 void *malloc_pkey_mmap_dax(long size, int prot, u16 pkey)
819 {
820         void *ptr;
821         int fd;
822 
823         dprintf1("doing %s(size=%ld, prot=0x%x, pkey=%d)\n", __func__,
824                         size, prot, pkey);
825         pkey_assert(pkey < NR_PKEYS);
826         fd = open("/dax/foo", O_RDWR);
827         pkey_assert(fd >= 0);
828 
829         ptr = mmap(0, size, prot, MAP_SHARED, fd, 0);
830         pkey_assert(ptr != (void *)-1);
831 
832         mprotect_pkey(ptr, size, prot, pkey);
833 
834         record_pkey_malloc(ptr, size, prot);
835 
836         dprintf1("mmap()'d for pkey %d @ %p\n", pkey, ptr);
837         close(fd);
838         return ptr;
839 }
840 
841 void *(*pkey_malloc[])(long size, int prot, u16 pkey) = {
842 
843         malloc_pkey_with_mprotect,
844         malloc_pkey_with_mprotect_subpage,
845         malloc_pkey_anon_huge,
846         malloc_pkey_hugetlb
847 /* can not do direct with the pkey_mprotect() API:
848         malloc_pkey_mmap_direct,
849         malloc_pkey_mmap_dax,
850 */
851 };
852 
853 void *malloc_pkey(long size, int prot, u16 pkey)
854 {
855         void *ret;
856         static int malloc_type;
857         int nr_malloc_types = ARRAY_SIZE(pkey_malloc);
858 
859         pkey_assert(pkey < NR_PKEYS);
860 
861         while (1) {
862                 pkey_assert(malloc_type < nr_malloc_types);
863 
864                 ret = pkey_malloc[malloc_type](size, prot, pkey);
865                 pkey_assert(ret != (void *)-1);
866 
867                 malloc_type++;
868                 if (malloc_type >= nr_malloc_types)
869                         malloc_type = (random()%nr_malloc_types);
870 
871                 /* try again if the malloc_type we tried is unsupported */
872                 if (ret == PTR_ERR_ENOTSUP)
873                         continue;
874 
875                 break;
876         }
877 
878         dprintf3("%s(%ld, prot=%x, pkey=%x) returning: %p\n", __func__,
879                         size, prot, pkey, ret);
880         return ret;
881 }
882 
883 int last_pkey_faults;
884 #define UNKNOWN_PKEY -2
885 void expected_pkey_fault(int pkey)
886 {
887         dprintf2("%s(): last_pkey_faults: %d pkey_faults: %d\n",
888                         __func__, last_pkey_faults, pkey_faults);
889         dprintf2("%s(%d): last_si_pkey: %d\n", __func__, pkey, last_si_pkey);
890         pkey_assert(last_pkey_faults + 1 == pkey_faults);
891 
892        /*
893         * For exec-only memory, we do not know the pkey in
894         * advance, so skip this check.
895         */
896         if (pkey != UNKNOWN_PKEY)
897                 pkey_assert(last_si_pkey == pkey);
898 
899 #if defined(__i386__) || defined(__x86_64__) /* arch */
900         /*
901          * The signal handler shold have cleared out PKEY register to let the
902          * test program continue.  We now have to restore it.
903          */
904         if (__read_pkey_reg() != 0)
905 #else /* arch */
906         if (__read_pkey_reg() != shadow_pkey_reg)
907 #endif /* arch */
908                 pkey_assert(0);
909 
910         __write_pkey_reg(shadow_pkey_reg);
911         dprintf1("%s() set pkey_reg=%016llx to restore state after signal "
912                        "nuked it\n", __func__, shadow_pkey_reg);
913         last_pkey_faults = pkey_faults;
914         last_si_pkey = -1;
915 }
916 
917 #define do_not_expect_pkey_fault(msg)   do {                    \
918         if (last_pkey_faults != pkey_faults)                    \
919                 dprintf0("unexpected PKey fault: %s\n", msg);   \
920         pkey_assert(last_pkey_faults == pkey_faults);           \
921 } while (0)
922 
923 int test_fds[10] = { -1 };
924 int nr_test_fds;
925 void __save_test_fd(int fd)
926 {
927         pkey_assert(fd >= 0);
928         pkey_assert(nr_test_fds < ARRAY_SIZE(test_fds));
929         test_fds[nr_test_fds] = fd;
930         nr_test_fds++;
931 }
932 
933 int get_test_read_fd(void)
934 {
935         int test_fd = open("/etc/passwd", O_RDONLY);
936         __save_test_fd(test_fd);
937         return test_fd;
938 }
939 
940 void close_test_fds(void)
941 {
942         int i;
943 
944         for (i = 0; i < nr_test_fds; i++) {
945                 if (test_fds[i] < 0)
946                         continue;
947                 close(test_fds[i]);
948                 test_fds[i] = -1;
949         }
950         nr_test_fds = 0;
951 }
952 
953 #define barrier() __asm__ __volatile__("": : :"memory")
954 __attribute__((noinline)) int read_ptr(int *ptr)
955 {
956         /*
957          * Keep GCC from optimizing this away somehow
958          */
959         barrier();
960         return *ptr;
961 }
962 
963 void test_pkey_alloc_free_attach_pkey0(int *ptr, u16 pkey)
964 {
965         int i, err;
966         int max_nr_pkey_allocs;
967         int alloced_pkeys[NR_PKEYS];
968         int nr_alloced = 0;
969         long size;
970 
971         pkey_assert(pkey_last_malloc_record);
972         size = pkey_last_malloc_record->size;
973         /*
974          * This is a bit of a hack.  But mprotect() requires
975          * huge-page-aligned sizes when operating on hugetlbfs.
976          * So, make sure that we use something that's a multiple
977          * of a huge page when we can.
978          */
979         if (size >= HPAGE_SIZE)
980                 size = HPAGE_SIZE;
981 
982         /* allocate every possible key and make sure key-0 never got allocated */
983         max_nr_pkey_allocs = NR_PKEYS;
984         for (i = 0; i < max_nr_pkey_allocs; i++) {
985                 int new_pkey = alloc_pkey();
986                 pkey_assert(new_pkey != 0);
987 
988                 if (new_pkey < 0)
989                         break;
990                 alloced_pkeys[nr_alloced++] = new_pkey;
991         }
992         /* free all the allocated keys */
993         for (i = 0; i < nr_alloced; i++) {
994                 int free_ret;
995 
996                 if (!alloced_pkeys[i])
997                         continue;
998                 free_ret = sys_pkey_free(alloced_pkeys[i]);
999                 pkey_assert(!free_ret);
1000         }
1001 
1002         /* attach key-0 in various modes */
1003         err = sys_mprotect_pkey(ptr, size, PROT_READ, 0);
1004         pkey_assert(!err);
1005         err = sys_mprotect_pkey(ptr, size, PROT_WRITE, 0);
1006         pkey_assert(!err);
1007         err = sys_mprotect_pkey(ptr, size, PROT_EXEC, 0);
1008         pkey_assert(!err);
1009         err = sys_mprotect_pkey(ptr, size, PROT_READ|PROT_WRITE, 0);
1010         pkey_assert(!err);
1011         err = sys_mprotect_pkey(ptr, size, PROT_READ|PROT_WRITE|PROT_EXEC, 0);
1012         pkey_assert(!err);
1013 }
1014 
1015 void test_read_of_write_disabled_region(int *ptr, u16 pkey)
1016 {
1017         int ptr_contents;
1018 
1019         dprintf1("disabling write access to PKEY[1], doing read\n");
1020         pkey_write_deny(pkey);
1021         ptr_contents = read_ptr(ptr);
1022         dprintf1("*ptr: %d\n", ptr_contents);
1023         dprintf1("\n");
1024 }
1025 void test_read_of_access_disabled_region(int *ptr, u16 pkey)
1026 {
1027         int ptr_contents;
1028 
1029         dprintf1("disabling access to PKEY[%02d], doing read @ %p\n", pkey, ptr);
1030         read_pkey_reg();
1031         pkey_access_deny(pkey);
1032         ptr_contents = read_ptr(ptr);
1033         dprintf1("*ptr: %d\n", ptr_contents);
1034         expected_pkey_fault(pkey);
1035 }
1036 
1037 void test_read_of_access_disabled_region_with_page_already_mapped(int *ptr,
1038                 u16 pkey)
1039 {
1040         int ptr_contents;
1041 
1042         dprintf1("disabling access to PKEY[%02d], doing read @ %p\n",
1043                                 pkey, ptr);
1044         ptr_contents = read_ptr(ptr);
1045         dprintf1("reading ptr before disabling the read : %d\n",
1046                         ptr_contents);
1047         read_pkey_reg();
1048         pkey_access_deny(pkey);
1049         ptr_contents = read_ptr(ptr);
1050         dprintf1("*ptr: %d\n", ptr_contents);
1051         expected_pkey_fault(pkey);
1052 }
1053 
1054 void test_write_of_write_disabled_region_with_page_already_mapped(int *ptr,
1055                 u16 pkey)
1056 {
1057         *ptr = __LINE__;
1058         dprintf1("disabling write access; after accessing the page, "
1059                 "to PKEY[%02d], doing write\n", pkey);
1060         pkey_write_deny(pkey);
1061         *ptr = __LINE__;
1062         expected_pkey_fault(pkey);
1063 }
1064 
1065 void test_write_of_write_disabled_region(int *ptr, u16 pkey)
1066 {
1067         dprintf1("disabling write access to PKEY[%02d], doing write\n", pkey);
1068         pkey_write_deny(pkey);
1069         *ptr = __LINE__;
1070         expected_pkey_fault(pkey);
1071 }
1072 void test_write_of_access_disabled_region(int *ptr, u16 pkey)
1073 {
1074         dprintf1("disabling access to PKEY[%02d], doing write\n", pkey);
1075         pkey_access_deny(pkey);
1076         *ptr = __LINE__;
1077         expected_pkey_fault(pkey);
1078 }
1079 
1080 void test_write_of_access_disabled_region_with_page_already_mapped(int *ptr,
1081                         u16 pkey)
1082 {
1083         *ptr = __LINE__;
1084         dprintf1("disabling access; after accessing the page, "
1085                 " to PKEY[%02d], doing write\n", pkey);
1086         pkey_access_deny(pkey);
1087         *ptr = __LINE__;
1088         expected_pkey_fault(pkey);
1089 }
1090 
1091 void test_kernel_write_of_access_disabled_region(int *ptr, u16 pkey)
1092 {
1093         int ret;
1094         int test_fd = get_test_read_fd();
1095 
1096         dprintf1("disabling access to PKEY[%02d], "
1097                  "having kernel read() to buffer\n", pkey);
1098         pkey_access_deny(pkey);
1099         ret = read(test_fd, ptr, 1);
1100         dprintf1("read ret: %d\n", ret);
1101         pkey_assert(ret);
1102 }
1103 void test_kernel_write_of_write_disabled_region(int *ptr, u16 pkey)
1104 {
1105         int ret;
1106         int test_fd = get_test_read_fd();
1107 
1108         pkey_write_deny(pkey);
1109         ret = read(test_fd, ptr, 100);
1110         dprintf1("read ret: %d\n", ret);
1111         if (ret < 0 && (DEBUG_LEVEL > 0))
1112                 perror("verbose read result (OK for this to be bad)");
1113         pkey_assert(ret);
1114 }
1115 
1116 void test_kernel_gup_of_access_disabled_region(int *ptr, u16 pkey)
1117 {
1118         int pipe_ret, vmsplice_ret;
1119         struct iovec iov;
1120         int pipe_fds[2];
1121 
1122         pipe_ret = pipe(pipe_fds);
1123 
1124         pkey_assert(pipe_ret == 0);
1125         dprintf1("disabling access to PKEY[%02d], "
1126                  "having kernel vmsplice from buffer\n", pkey);
1127         pkey_access_deny(pkey);
1128         iov.iov_base = ptr;
1129         iov.iov_len = PAGE_SIZE;
1130         vmsplice_ret = vmsplice(pipe_fds[1], &iov, 1, SPLICE_F_GIFT);
1131         dprintf1("vmsplice() ret: %d\n", vmsplice_ret);
1132         pkey_assert(vmsplice_ret == -1);
1133 
1134         close(pipe_fds[0]);
1135         close(pipe_fds[1]);
1136 }
1137 
1138 void test_kernel_gup_write_to_write_disabled_region(int *ptr, u16 pkey)
1139 {
1140         int ignored = 0xdada;
1141         int futex_ret;
1142         int some_int = __LINE__;
1143 
1144         dprintf1("disabling write to PKEY[%02d], "
1145                  "doing futex gunk in buffer\n", pkey);
1146         *ptr = some_int;
1147         pkey_write_deny(pkey);
1148         futex_ret = syscall(SYS_futex, ptr, FUTEX_WAIT, some_int-1, NULL,
1149                         &ignored, ignored);
1150         if (DEBUG_LEVEL > 0)
1151                 perror("futex");
1152         dprintf1("futex() ret: %d\n", futex_ret);
1153 }
1154 
1155 /* Assumes that all pkeys other than 'pkey' are unallocated */
1156 void test_pkey_syscalls_on_non_allocated_pkey(int *ptr, u16 pkey)
1157 {
1158         int err;
1159         int i;
1160 
1161         /* Note: 0 is the default pkey, so don't mess with it */
1162         for (i = 1; i < NR_PKEYS; i++) {
1163                 if (pkey == i)
1164                         continue;
1165 
1166                 dprintf1("trying get/set/free to non-allocated pkey: %2d\n", i);
1167                 err = sys_pkey_free(i);
1168                 pkey_assert(err);
1169 
1170                 err = sys_pkey_free(i);
1171                 pkey_assert(err);
1172 
1173                 err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, i);
1174                 pkey_assert(err);
1175         }
1176 }
1177 
1178 /* Assumes that all pkeys other than 'pkey' are unallocated */
1179 void test_pkey_syscalls_bad_args(int *ptr, u16 pkey)
1180 {
1181         int err;
1182         int bad_pkey = NR_PKEYS+99;
1183 
1184         /* pass a known-invalid pkey in: */
1185         err = sys_mprotect_pkey(ptr, PAGE_SIZE, PROT_READ, bad_pkey);
1186         pkey_assert(err);
1187 }
1188 
1189 void become_child(void)
1190 {
1191         pid_t forkret;
1192 
1193         forkret = fork();
1194         pkey_assert(forkret >= 0);
1195         dprintf3("[%d] fork() ret: %d\n", getpid(), forkret);
1196 
1197         if (!forkret) {
1198                 /* in the child */
1199                 return;
1200         }
1201         exit(0);
1202 }
1203 
1204 /* Assumes that all pkeys other than 'pkey' are unallocated */
1205 void test_pkey_alloc_exhaust(int *ptr, u16 pkey)
1206 {
1207         int err;
1208         int allocated_pkeys[NR_PKEYS] = {0};
1209         int nr_allocated_pkeys = 0;
1210         int i;
1211 
1212         for (i = 0; i < NR_PKEYS*3; i++) {
1213                 int new_pkey;
1214                 dprintf1("%s() alloc loop: %d\n", __func__, i);
1215                 new_pkey = alloc_pkey();
1216                 dprintf4("%s()::%d, err: %d pkey_reg: 0x%016llx"
1217                                 " shadow: 0x%016llx\n",
1218                                 __func__, __LINE__, err, __read_pkey_reg(),
1219                                 shadow_pkey_reg);
1220                 read_pkey_reg(); /* for shadow checking */
1221                 dprintf2("%s() errno: %d ENOSPC: %d\n", __func__, errno, ENOSPC);
1222                 if ((new_pkey == -1) && (errno == ENOSPC)) {
1223                         dprintf2("%s() failed to allocate pkey after %d tries\n",
1224                                 __func__, nr_allocated_pkeys);
1225                 } else {
1226                         /*
1227                          * Ensure the number of successes never
1228                          * exceeds the number of keys supported
1229                          * in the hardware.
1230                          */
1231                         pkey_assert(nr_allocated_pkeys < NR_PKEYS);
1232                         allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
1233                 }
1234 
1235                 /*
1236                  * Make sure that allocation state is properly
1237                  * preserved across fork().
1238                  */
1239                 if (i == NR_PKEYS*2)
1240                         become_child();
1241         }
1242 
1243         dprintf3("%s()::%d\n", __func__, __LINE__);
1244 
1245         /*
1246          * On x86:
1247          * There are 16 pkeys supported in hardware.  Three are
1248          * allocated by the time we get here:
1249          *   1. The default key (0)
1250          *   2. One possibly consumed by an execute-only mapping.
1251          *   3. One allocated by the test code and passed in via
1252          *      'pkey' to this function.
1253          * Ensure that we can allocate at least another 13 (16-3).
1254          *
1255          * On powerpc:
1256          * There are either 5, 28, 29 or 32 pkeys supported in
1257          * hardware depending on the page size (4K or 64K) and
1258          * platform (powernv or powervm). Four are allocated by
1259          * the time we get here. These include pkey-0, pkey-1,
1260          * exec-only pkey and the one allocated by the test code.
1261          * Ensure that we can allocate the remaining.
1262          */
1263         pkey_assert(i >= (NR_PKEYS - get_arch_reserved_keys() - 1));
1264 
1265         for (i = 0; i < nr_allocated_pkeys; i++) {
1266                 err = sys_pkey_free(allocated_pkeys[i]);
1267                 pkey_assert(!err);
1268                 read_pkey_reg(); /* for shadow checking */
1269         }
1270 }
1271 
1272 void arch_force_pkey_reg_init(void)
1273 {
1274 #if defined(__i386__) || defined(__x86_64__) /* arch */
1275         u64 *buf;
1276 
1277         /*
1278          * All keys should be allocated and set to allow reads and
1279          * writes, so the register should be all 0.  If not, just
1280          * skip the test.
1281          */
1282         if (read_pkey_reg())
1283                 return;
1284 
1285         /*
1286          * Just allocate an absurd about of memory rather than
1287          * doing the XSAVE size enumeration dance.
1288          */
1289         buf = mmap(NULL, 1*MB, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
1290 
1291         /* These __builtins require compiling with -mxsave */
1292 
1293         /* XSAVE to build a valid buffer: */
1294         __builtin_ia32_xsave(buf, XSTATE_PKEY);
1295         /* Clear XSTATE_BV[PKRU]: */
1296         buf[XSTATE_BV_OFFSET/sizeof(u64)] &= ~XSTATE_PKEY;
1297         /* XRSTOR will likely get PKRU back to the init state: */
1298         __builtin_ia32_xrstor(buf, XSTATE_PKEY);
1299 
1300         munmap(buf, 1*MB);
1301 #endif
1302 }
1303 
1304 
1305 /*
1306  * This is mostly useless on ppc for now.  But it will not
1307  * hurt anything and should give some better coverage as
1308  * a long-running test that continually checks the pkey
1309  * register.
1310  */
1311 void test_pkey_init_state(int *ptr, u16 pkey)
1312 {
1313         int err;
1314         int allocated_pkeys[NR_PKEYS] = {0};
1315         int nr_allocated_pkeys = 0;
1316         int i;
1317 
1318         for (i = 0; i < NR_PKEYS; i++) {
1319                 int new_pkey = alloc_pkey();
1320 
1321                 if (new_pkey < 0)
1322                         continue;
1323                 allocated_pkeys[nr_allocated_pkeys++] = new_pkey;
1324         }
1325 
1326         dprintf3("%s()::%d\n", __func__, __LINE__);
1327 
1328         arch_force_pkey_reg_init();
1329 
1330         /*
1331          * Loop for a bit, hoping to get exercise the kernel
1332          * context switch code.
1333          */
1334         for (i = 0; i < 1000000; i++)
1335                 read_pkey_reg();
1336 
1337         for (i = 0; i < nr_allocated_pkeys; i++) {
1338                 err = sys_pkey_free(allocated_pkeys[i]);
1339                 pkey_assert(!err);
1340                 read_pkey_reg(); /* for shadow checking */
1341         }
1342 }
1343 
1344 /*
1345  * pkey 0 is special.  It is allocated by default, so you do not
1346  * have to call pkey_alloc() to use it first.  Make sure that it
1347  * is usable.
1348  */
1349 void test_mprotect_with_pkey_0(int *ptr, u16 pkey)
1350 {
1351         long size;
1352         int prot;
1353 
1354         assert(pkey_last_malloc_record);
1355         size = pkey_last_malloc_record->size;
1356         /*
1357          * This is a bit of a hack.  But mprotect() requires
1358          * huge-page-aligned sizes when operating on hugetlbfs.
1359          * So, make sure that we use something that's a multiple
1360          * of a huge page when we can.
1361          */
1362         if (size >= HPAGE_SIZE)
1363                 size = HPAGE_SIZE;
1364         prot = pkey_last_malloc_record->prot;
1365 
1366         /* Use pkey 0 */
1367         mprotect_pkey(ptr, size, prot, 0);
1368 
1369         /* Make sure that we can set it back to the original pkey. */
1370         mprotect_pkey(ptr, size, prot, pkey);
1371 }
1372 
1373 void test_ptrace_of_child(int *ptr, u16 pkey)
1374 {
1375         __attribute__((__unused__)) int peek_result;
1376         pid_t child_pid;
1377         void *ignored = 0;
1378         long ret;
1379         int status;
1380         /*
1381          * This is the "control" for our little expermient.  Make sure
1382          * we can always access it when ptracing.
1383          */
1384         int *plain_ptr_unaligned = malloc(HPAGE_SIZE);
1385         int *plain_ptr = ALIGN_PTR_UP(plain_ptr_unaligned, PAGE_SIZE);
1386 
1387         /*
1388          * Fork a child which is an exact copy of this process, of course.
1389          * That means we can do all of our tests via ptrace() and then plain
1390          * memory access and ensure they work differently.
1391          */
1392         child_pid = fork_lazy_child();
1393         dprintf1("[%d] child pid: %d\n", getpid(), child_pid);
1394 
1395         ret = ptrace(PTRACE_ATTACH, child_pid, ignored, ignored);
1396         if (ret)
1397                 perror("attach");
1398         dprintf1("[%d] attach ret: %ld %d\n", getpid(), ret, __LINE__);
1399         pkey_assert(ret != -1);
1400         ret = waitpid(child_pid, &status, WUNTRACED);
1401         if ((ret != child_pid) || !(WIFSTOPPED(status))) {
1402                 fprintf(stderr, "weird waitpid result %ld stat %x\n",
1403                                 ret, status);
1404                 pkey_assert(0);
1405         }
1406         dprintf2("waitpid ret: %ld\n", ret);
1407         dprintf2("waitpid status: %d\n", status);
1408 
1409         pkey_access_deny(pkey);
1410         pkey_write_deny(pkey);
1411 
1412         /* Write access, untested for now:
1413         ret = ptrace(PTRACE_POKEDATA, child_pid, peek_at, data);
1414         pkey_assert(ret != -1);
1415         dprintf1("poke at %p: %ld\n", peek_at, ret);
1416         */
1417 
1418         /*
1419          * Try to access the pkey-protected "ptr" via ptrace:
1420          */
1421         ret = ptrace(PTRACE_PEEKDATA, child_pid, ptr, ignored);
1422         /* expect it to work, without an error: */
1423         pkey_assert(ret != -1);
1424         /* Now access from the current task, and expect an exception: */
1425         peek_result = read_ptr(ptr);
1426         expected_pkey_fault(pkey);
1427 
1428         /*
1429          * Try to access the NON-pkey-protected "plain_ptr" via ptrace:
1430          */
1431         ret = ptrace(PTRACE_PEEKDATA, child_pid, plain_ptr, ignored);
1432         /* expect it to work, without an error: */
1433         pkey_assert(ret != -1);
1434         /* Now access from the current task, and expect NO exception: */
1435         peek_result = read_ptr(plain_ptr);
1436         do_not_expect_pkey_fault("read plain pointer after ptrace");
1437 
1438         ret = ptrace(PTRACE_DETACH, child_pid, ignored, 0);
1439         pkey_assert(ret != -1);
1440 
1441         ret = kill(child_pid, SIGKILL);
1442         pkey_assert(ret != -1);
1443 
1444         wait(&status);
1445 
1446         free(plain_ptr_unaligned);
1447 }
1448 
1449 void *get_pointer_to_instructions(void)
1450 {
1451         void *p1;
1452 
1453         p1 = ALIGN_PTR_UP(&lots_o_noops_around_write, PAGE_SIZE);
1454         dprintf3("&lots_o_noops: %p\n", &lots_o_noops_around_write);
1455         /* lots_o_noops_around_write should be page-aligned already */
1456         assert(p1 == &lots_o_noops_around_write);
1457 
1458         /* Point 'p1' at the *second* page of the function: */
1459         p1 += PAGE_SIZE;
1460 
1461         /*
1462          * Try to ensure we fault this in on next touch to ensure
1463          * we get an instruction fault as opposed to a data one
1464          */
1465         madvise(p1, PAGE_SIZE, MADV_DONTNEED);
1466 
1467         return p1;
1468 }
1469 
1470 void test_executing_on_unreadable_memory(int *ptr, u16 pkey)
1471 {
1472         void *p1;
1473         int scratch;
1474         int ptr_contents;
1475         int ret;
1476 
1477         p1 = get_pointer_to_instructions();
1478         lots_o_noops_around_write(&scratch);
1479         ptr_contents = read_ptr(p1);
1480         dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
1481 
1482         ret = mprotect_pkey(p1, PAGE_SIZE, PROT_EXEC, (u64)pkey);
1483         pkey_assert(!ret);
1484         pkey_access_deny(pkey);
1485 
1486         dprintf2("pkey_reg: %016llx\n", read_pkey_reg());
1487 
1488         /*
1489          * Make sure this is an *instruction* fault
1490          */
1491         madvise(p1, PAGE_SIZE, MADV_DONTNEED);
1492         lots_o_noops_around_write(&scratch);
1493         do_not_expect_pkey_fault("executing on PROT_EXEC memory");
1494         expect_fault_on_read_execonly_key(p1, pkey);
1495 }
1496 
1497 void test_implicit_mprotect_exec_only_memory(int *ptr, u16 pkey)
1498 {
1499         void *p1;
1500         int scratch;
1501         int ptr_contents;
1502         int ret;
1503 
1504         dprintf1("%s() start\n", __func__);
1505 
1506         p1 = get_pointer_to_instructions();
1507         lots_o_noops_around_write(&scratch);
1508         ptr_contents = read_ptr(p1);
1509         dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
1510 
1511         /* Use a *normal* mprotect(), not mprotect_pkey(): */
1512         ret = mprotect(p1, PAGE_SIZE, PROT_EXEC);
1513         pkey_assert(!ret);
1514 
1515         /*
1516          * Reset the shadow, assuming that the above mprotect()
1517          * correctly changed PKRU, but to an unknown value since
1518          * the actual allocated pkey is unknown.
1519          */
1520         shadow_pkey_reg = __read_pkey_reg();
1521 
1522         dprintf2("pkey_reg: %016llx\n", read_pkey_reg());
1523 
1524         /* Make sure this is an *instruction* fault */
1525         madvise(p1, PAGE_SIZE, MADV_DONTNEED);
1526         lots_o_noops_around_write(&scratch);
1527         do_not_expect_pkey_fault("executing on PROT_EXEC memory");
1528         expect_fault_on_read_execonly_key(p1, UNKNOWN_PKEY);
1529 
1530         /*
1531          * Put the memory back to non-PROT_EXEC.  Should clear the
1532          * exec-only pkey off the VMA and allow it to be readable
1533          * again.  Go to PROT_NONE first to check for a kernel bug
1534          * that did not clear the pkey when doing PROT_NONE.
1535          */
1536         ret = mprotect(p1, PAGE_SIZE, PROT_NONE);
1537         pkey_assert(!ret);
1538 
1539         ret = mprotect(p1, PAGE_SIZE, PROT_READ|PROT_EXEC);
1540         pkey_assert(!ret);
1541         ptr_contents = read_ptr(p1);
1542         do_not_expect_pkey_fault("plain read on recently PROT_EXEC area");
1543 }
1544 
1545 #if defined(__i386__) || defined(__x86_64__)
1546 void test_ptrace_modifies_pkru(int *ptr, u16 pkey)
1547 {
1548         u32 new_pkru;
1549         pid_t child;
1550         int status, ret;
1551         int pkey_offset = pkey_reg_xstate_offset();
1552         size_t xsave_size = cpu_max_xsave_size();
1553         void *xsave;
1554         u32 *pkey_register;
1555         u64 *xstate_bv;
1556         struct iovec iov;
1557 
1558         new_pkru = ~read_pkey_reg();
1559         /* Don't make PROT_EXEC mappings inaccessible */
1560         new_pkru &= ~3;
1561 
1562         child = fork();
1563         pkey_assert(child >= 0);
1564         dprintf3("[%d] fork() ret: %d\n", getpid(), child);
1565         if (!child) {
1566                 ptrace(PTRACE_TRACEME, 0, 0, 0);
1567                 /* Stop and allow the tracer to modify PKRU directly */
1568                 raise(SIGSTOP);
1569 
1570                 /*
1571                  * need __read_pkey_reg() version so we do not do shadow_pkey_reg
1572                  * checking
1573                  */
1574                 if (__read_pkey_reg() != new_pkru)
1575                         exit(1);
1576 
1577                 /* Stop and allow the tracer to clear XSTATE_BV for PKRU */
1578                 raise(SIGSTOP);
1579 
1580                 if (__read_pkey_reg() != 0)
1581                         exit(1);
1582 
1583                 /* Stop and allow the tracer to examine PKRU */
1584                 raise(SIGSTOP);
1585 
1586                 exit(0);
1587         }
1588 
1589         pkey_assert(child == waitpid(child, &status, 0));
1590         dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
1591         pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
1592 
1593         xsave = (void *)malloc(xsave_size);
1594         pkey_assert(xsave > 0);
1595 
1596         /* Modify the PKRU register directly */
1597         iov.iov_base = xsave;
1598         iov.iov_len = xsave_size;
1599         ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1600         pkey_assert(ret == 0);
1601 
1602         pkey_register = (u32 *)(xsave + pkey_offset);
1603         pkey_assert(*pkey_register == read_pkey_reg());
1604 
1605         *pkey_register = new_pkru;
1606 
1607         ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1608         pkey_assert(ret == 0);
1609 
1610         /* Test that the modification is visible in ptrace before any execution */
1611         memset(xsave, 0xCC, xsave_size);
1612         ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1613         pkey_assert(ret == 0);
1614         pkey_assert(*pkey_register == new_pkru);
1615 
1616         /* Execute the tracee */
1617         ret = ptrace(PTRACE_CONT, child, 0, 0);
1618         pkey_assert(ret == 0);
1619 
1620         /* Test that the tracee saw the PKRU value change */
1621         pkey_assert(child == waitpid(child, &status, 0));
1622         dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
1623         pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
1624 
1625         /* Test that the modification is visible in ptrace after execution */
1626         memset(xsave, 0xCC, xsave_size);
1627         ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1628         pkey_assert(ret == 0);
1629         pkey_assert(*pkey_register == new_pkru);
1630 
1631         /* Clear the PKRU bit from XSTATE_BV */
1632         xstate_bv = (u64 *)(xsave + 512);
1633         *xstate_bv &= ~(1 << 9);
1634 
1635         ret = ptrace(PTRACE_SETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1636         pkey_assert(ret == 0);
1637 
1638         /* Test that the modification is visible in ptrace before any execution */
1639         memset(xsave, 0xCC, xsave_size);
1640         ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1641         pkey_assert(ret == 0);
1642         pkey_assert(*pkey_register == 0);
1643 
1644         ret = ptrace(PTRACE_CONT, child, 0, 0);
1645         pkey_assert(ret == 0);
1646 
1647         /* Test that the tracee saw the PKRU value go to 0 */
1648         pkey_assert(child == waitpid(child, &status, 0));
1649         dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
1650         pkey_assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
1651 
1652         /* Test that the modification is visible in ptrace after execution */
1653         memset(xsave, 0xCC, xsave_size);
1654         ret = ptrace(PTRACE_GETREGSET, child, (void *)NT_X86_XSTATE, &iov);
1655         pkey_assert(ret == 0);
1656         pkey_assert(*pkey_register == 0);
1657 
1658         ret = ptrace(PTRACE_CONT, child, 0, 0);
1659         pkey_assert(ret == 0);
1660         pkey_assert(child == waitpid(child, &status, 0));
1661         dprintf3("[%d] waitpid(%d) status: %x\n", getpid(), child, status);
1662         pkey_assert(WIFEXITED(status));
1663         pkey_assert(WEXITSTATUS(status) == 0);
1664         free(xsave);
1665 }
1666 #endif
1667 
1668 void test_mprotect_pkey_on_unsupported_cpu(int *ptr, u16 pkey)
1669 {
1670         int size = PAGE_SIZE;
1671         int sret;
1672 
1673         if (cpu_has_pkeys()) {
1674                 dprintf1("SKIP: %s: no CPU support\n", __func__);
1675                 return;
1676         }
1677 
1678         sret = syscall(__NR_pkey_mprotect, ptr, size, PROT_READ, pkey);
1679         pkey_assert(sret < 0);
1680 }
1681 
1682 void (*pkey_tests[])(int *ptr, u16 pkey) = {
1683         test_read_of_write_disabled_region,
1684         test_read_of_access_disabled_region,
1685         test_read_of_access_disabled_region_with_page_already_mapped,
1686         test_write_of_write_disabled_region,
1687         test_write_of_write_disabled_region_with_page_already_mapped,
1688         test_write_of_access_disabled_region,
1689         test_write_of_access_disabled_region_with_page_already_mapped,
1690         test_kernel_write_of_access_disabled_region,
1691         test_kernel_write_of_write_disabled_region,
1692         test_kernel_gup_of_access_disabled_region,
1693         test_kernel_gup_write_to_write_disabled_region,
1694         test_executing_on_unreadable_memory,
1695         test_implicit_mprotect_exec_only_memory,
1696         test_mprotect_with_pkey_0,
1697         test_ptrace_of_child,
1698         test_pkey_init_state,
1699         test_pkey_syscalls_on_non_allocated_pkey,
1700         test_pkey_syscalls_bad_args,
1701         test_pkey_alloc_exhaust,
1702         test_pkey_alloc_free_attach_pkey0,
1703 #if defined(__i386__) || defined(__x86_64__)
1704         test_ptrace_modifies_pkru,
1705 #endif
1706 };
1707 
1708 void run_tests_once(void)
1709 {
1710         int *ptr;
1711         int prot = PROT_READ|PROT_WRITE;
1712 
1713         for (test_nr = 0; test_nr < ARRAY_SIZE(pkey_tests); test_nr++) {
1714                 int pkey;
1715                 int orig_pkey_faults = pkey_faults;
1716 
1717                 dprintf1("======================\n");
1718                 dprintf1("test %d preparing...\n", test_nr);
1719 
1720                 tracing_on();
1721                 pkey = alloc_random_pkey();
1722                 dprintf1("test %d starting with pkey: %d\n", test_nr, pkey);
1723                 ptr = malloc_pkey(PAGE_SIZE, prot, pkey);
1724                 dprintf1("test %d starting...\n", test_nr);
1725                 pkey_tests[test_nr](ptr, pkey);
1726                 dprintf1("freeing test memory: %p\n", ptr);
1727                 free_pkey_malloc(ptr);
1728                 sys_pkey_free(pkey);
1729 
1730                 dprintf1("pkey_faults: %d\n", pkey_faults);
1731                 dprintf1("orig_pkey_faults: %d\n", orig_pkey_faults);
1732 
1733                 tracing_off();
1734                 close_test_fds();
1735 
1736                 printf("test %2d PASSED (iteration %d)\n", test_nr, iteration_nr);
1737                 dprintf1("======================\n\n");
1738         }
1739         iteration_nr++;
1740 }
1741 
1742 void pkey_setup_shadow(void)
1743 {
1744         shadow_pkey_reg = __read_pkey_reg();
1745 }
1746 
1747 int main(void)
1748 {
1749         int nr_iterations = 22;
1750         int pkeys_supported = is_pkeys_supported();
1751 
1752         srand((unsigned int)time(NULL));
1753 
1754         setup_handlers();
1755 
1756         printf("has pkeys: %d\n", pkeys_supported);
1757 
1758         if (!pkeys_supported) {
1759                 int size = PAGE_SIZE;
1760                 int *ptr;
1761 
1762                 printf("running PKEY tests for unsupported CPU/OS\n");
1763 
1764                 ptr  = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
1765                 assert(ptr != (void *)-1);
1766                 test_mprotect_pkey_on_unsupported_cpu(ptr, 1);
1767                 exit(0);
1768         }
1769 
1770         pkey_setup_shadow();
1771         printf("startup pkey_reg: %016llx\n", read_pkey_reg());
1772         setup_hugetlbfs();
1773 
1774         while (nr_iterations-- > 0)
1775                 run_tests_once();
1776 
1777         printf("done (all tests OK)\n");
1778         return 0;
1779 }
1780 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php