]> Git Repo - J-linux.git/blob - tools/testing/selftests/mm/mseal_test.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / mm / mseal_test.c
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <linux/mman.h>
4 #include <sys/mman.h>
5 #include <stdint.h>
6 #include <asm-generic/unistd.h>
7 #include <string.h>
8 #include <sys/time.h>
9 #include <sys/resource.h>
10 #include <stdbool.h>
11 #include "../kselftest.h"
12 #include <syscall.h>
13 #include <errno.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 #include <sys/ioctl.h>
18 #include <sys/vfs.h>
19 #include <sys/stat.h>
20 #include "mseal_helpers.h"
21
22 static unsigned long get_vma_size(void *addr, int *prot)
23 {
24         FILE *maps;
25         char line[256];
26         int size = 0;
27         uintptr_t  addr_start, addr_end;
28         char protstr[5];
29         *prot = 0;
30
31         maps = fopen("/proc/self/maps", "r");
32         if (!maps)
33                 return 0;
34
35         while (fgets(line, sizeof(line), maps)) {
36                 if (sscanf(line, "%lx-%lx %4s", &addr_start, &addr_end, protstr) == 3) {
37                         if (addr_start == (uintptr_t) addr) {
38                                 size = addr_end - addr_start;
39                                 if (protstr[0] == 'r')
40                                         *prot |= 0x4;
41                                 if (protstr[1] == 'w')
42                                         *prot |= 0x2;
43                                 if (protstr[2] == 'x')
44                                         *prot |= 0x1;
45                                 break;
46                         }
47                 }
48         }
49         fclose(maps);
50         return size;
51 }
52
53 /*
54  * define sys_xyx to call syscall directly.
55  */
56 static int sys_mseal(void *start, size_t len)
57 {
58         int sret;
59
60         errno = 0;
61         sret = syscall(__NR_mseal, start, len, 0);
62         return sret;
63 }
64
65 static int sys_mprotect(void *ptr, size_t size, unsigned long prot)
66 {
67         int sret;
68
69         errno = 0;
70         sret = syscall(__NR_mprotect, ptr, size, prot);
71         return sret;
72 }
73
74 static int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
75                 unsigned long pkey)
76 {
77         int sret;
78
79         errno = 0;
80         sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey);
81         return sret;
82 }
83
84 static int sys_munmap(void *ptr, size_t size)
85 {
86         int sret;
87
88         errno = 0;
89         sret = syscall(__NR_munmap, ptr, size);
90         return sret;
91 }
92
93 static int sys_madvise(void *start, size_t len, int types)
94 {
95         int sret;
96
97         errno = 0;
98         sret = syscall(__NR_madvise, start, len, types);
99         return sret;
100 }
101
102 static void *sys_mremap(void *addr, size_t old_len, size_t new_len,
103         unsigned long flags, void *new_addr)
104 {
105         void *sret;
106
107         errno = 0;
108         sret = (void *) syscall(__NR_mremap, addr, old_len, new_len, flags, new_addr);
109         return sret;
110 }
111
112 static int sys_pkey_alloc(unsigned long flags, unsigned long init_val)
113 {
114         int ret = syscall(__NR_pkey_alloc, flags, init_val);
115
116         return ret;
117 }
118
119 static unsigned int __read_pkey_reg(void)
120 {
121         unsigned int pkey_reg = 0;
122 #if defined(__i386__) || defined(__x86_64__) /* arch */
123         unsigned int eax, edx;
124         unsigned int ecx = 0;
125
126         asm volatile(".byte 0x0f,0x01,0xee\n\t"
127                         : "=a" (eax), "=d" (edx)
128                         : "c" (ecx));
129         pkey_reg = eax;
130 #endif
131         return pkey_reg;
132 }
133
134 static void __write_pkey_reg(u64 pkey_reg)
135 {
136 #if defined(__i386__) || defined(__x86_64__) /* arch */
137         unsigned int eax = pkey_reg;
138         unsigned int ecx = 0;
139         unsigned int edx = 0;
140
141         asm volatile(".byte 0x0f,0x01,0xef\n\t"
142                         : : "a" (eax), "c" (ecx), "d" (edx));
143 #endif
144 }
145
146 static unsigned long pkey_bit_position(int pkey)
147 {
148         return pkey * PKEY_BITS_PER_PKEY;
149 }
150
151 static u64 set_pkey_bits(u64 reg, int pkey, u64 flags)
152 {
153         unsigned long shift = pkey_bit_position(pkey);
154
155         /* mask out bits from pkey in old value */
156         reg &= ~((u64)PKEY_MASK << shift);
157         /* OR in new bits for pkey */
158         reg |= (flags & PKEY_MASK) << shift;
159         return reg;
160 }
161
162 static void set_pkey(int pkey, unsigned long pkey_value)
163 {
164         u64 new_pkey_reg;
165
166         new_pkey_reg = set_pkey_bits(__read_pkey_reg(), pkey, pkey_value);
167         __write_pkey_reg(new_pkey_reg);
168 }
169
170 static void setup_single_address(int size, void **ptrOut)
171 {
172         void *ptr;
173
174         ptr = mmap(NULL, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
175         *ptrOut = ptr;
176 }
177
178 static void setup_single_address_rw(int size, void **ptrOut)
179 {
180         void *ptr;
181         unsigned long mapflags = MAP_ANONYMOUS | MAP_PRIVATE;
182
183         ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, mapflags, -1, 0);
184         *ptrOut = ptr;
185 }
186
187 static int clean_single_address(void *ptr, int size)
188 {
189         int ret;
190         ret = munmap(ptr, size);
191         return ret;
192 }
193
194 static int seal_single_address(void *ptr, int size)
195 {
196         int ret;
197         ret = sys_mseal(ptr, size);
198         return ret;
199 }
200
201 bool seal_support(void)
202 {
203         int ret;
204         void *ptr;
205         unsigned long page_size = getpagesize();
206
207         ptr = mmap(NULL, page_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
208         if (ptr == (void *) -1)
209                 return false;
210
211         ret = sys_mseal(ptr, page_size);
212         if (ret < 0)
213                 return false;
214
215         return true;
216 }
217
218 bool pkey_supported(void)
219 {
220 #if defined(__i386__) || defined(__x86_64__) /* arch */
221         int pkey = sys_pkey_alloc(0, 0);
222
223         if (pkey > 0)
224                 return true;
225 #endif
226         return false;
227 }
228
229 static void test_seal_addseal(void)
230 {
231         int ret;
232         void *ptr;
233         unsigned long page_size = getpagesize();
234         unsigned long size = 4 * page_size;
235
236         setup_single_address(size, &ptr);
237         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
238
239         ret = sys_mseal(ptr, size);
240         FAIL_TEST_IF_FALSE(!ret);
241
242         REPORT_TEST_PASS();
243 }
244
245 static void test_seal_unmapped_start(void)
246 {
247         int ret;
248         void *ptr;
249         unsigned long page_size = getpagesize();
250         unsigned long size = 4 * page_size;
251
252         setup_single_address(size, &ptr);
253         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
254
255         /* munmap 2 pages from ptr. */
256         ret = sys_munmap(ptr, 2 * page_size);
257         FAIL_TEST_IF_FALSE(!ret);
258
259         /* mprotect will fail because 2 pages from ptr are unmapped. */
260         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
261         FAIL_TEST_IF_FALSE(ret < 0);
262
263         /* mseal will fail because 2 pages from ptr are unmapped. */
264         ret = sys_mseal(ptr, size);
265         FAIL_TEST_IF_FALSE(ret < 0);
266
267         ret = sys_mseal(ptr + 2 * page_size, 2 * page_size);
268         FAIL_TEST_IF_FALSE(!ret);
269
270         REPORT_TEST_PASS();
271 }
272
273 static void test_seal_unmapped_middle(void)
274 {
275         int ret;
276         void *ptr;
277         unsigned long page_size = getpagesize();
278         unsigned long size = 4 * page_size;
279
280         setup_single_address(size, &ptr);
281         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
282
283         /* munmap 2 pages from ptr + page. */
284         ret = sys_munmap(ptr + page_size, 2 * page_size);
285         FAIL_TEST_IF_FALSE(!ret);
286
287         /* mprotect will fail, since middle 2 pages are unmapped. */
288         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
289         FAIL_TEST_IF_FALSE(ret < 0);
290
291         /* mseal will fail as well. */
292         ret = sys_mseal(ptr, size);
293         FAIL_TEST_IF_FALSE(ret < 0);
294
295         /* we still can add seal to the first page and last page*/
296         ret = sys_mseal(ptr, page_size);
297         FAIL_TEST_IF_FALSE(!ret);
298
299         ret = sys_mseal(ptr + 3 * page_size, page_size);
300         FAIL_TEST_IF_FALSE(!ret);
301
302         REPORT_TEST_PASS();
303 }
304
305 static void test_seal_unmapped_end(void)
306 {
307         int ret;
308         void *ptr;
309         unsigned long page_size = getpagesize();
310         unsigned long size = 4 * page_size;
311
312         setup_single_address(size, &ptr);
313         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
314
315         /* unmap last 2 pages. */
316         ret = sys_munmap(ptr + 2 * page_size, 2 * page_size);
317         FAIL_TEST_IF_FALSE(!ret);
318
319         /* mprotect will fail since last 2 pages are unmapped. */
320         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
321         FAIL_TEST_IF_FALSE(ret < 0);
322
323         /* mseal will fail as well. */
324         ret = sys_mseal(ptr, size);
325         FAIL_TEST_IF_FALSE(ret < 0);
326
327         /* The first 2 pages is not sealed, and can add seals */
328         ret = sys_mseal(ptr, 2 * page_size);
329         FAIL_TEST_IF_FALSE(!ret);
330
331         REPORT_TEST_PASS();
332 }
333
334 static void test_seal_multiple_vmas(void)
335 {
336         int ret;
337         void *ptr;
338         unsigned long page_size = getpagesize();
339         unsigned long size = 4 * page_size;
340
341         setup_single_address(size, &ptr);
342         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
343
344         /* use mprotect to split the vma into 3. */
345         ret = sys_mprotect(ptr + page_size, 2 * page_size,
346                         PROT_READ | PROT_WRITE);
347         FAIL_TEST_IF_FALSE(!ret);
348
349         /* mprotect will get applied to all 4 pages - 3 VMAs. */
350         ret = sys_mprotect(ptr, size, PROT_READ);
351         FAIL_TEST_IF_FALSE(!ret);
352
353         /* use mprotect to split the vma into 3. */
354         ret = sys_mprotect(ptr + page_size, 2 * page_size,
355                         PROT_READ | PROT_WRITE);
356         FAIL_TEST_IF_FALSE(!ret);
357
358         /* mseal get applied to all 4 pages - 3 VMAs. */
359         ret = sys_mseal(ptr, size);
360         FAIL_TEST_IF_FALSE(!ret);
361
362         REPORT_TEST_PASS();
363 }
364
365 static void test_seal_split_start(void)
366 {
367         int ret;
368         void *ptr;
369         unsigned long page_size = getpagesize();
370         unsigned long size = 4 * page_size;
371
372         setup_single_address(size, &ptr);
373         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
374
375         /* use mprotect to split at middle */
376         ret = sys_mprotect(ptr, 2 * page_size, PROT_READ | PROT_WRITE);
377         FAIL_TEST_IF_FALSE(!ret);
378
379         /* seal the first page, this will split the VMA */
380         ret = sys_mseal(ptr, page_size);
381         FAIL_TEST_IF_FALSE(!ret);
382
383         /* add seal to the remain 3 pages */
384         ret = sys_mseal(ptr + page_size, 3 * page_size);
385         FAIL_TEST_IF_FALSE(!ret);
386
387         REPORT_TEST_PASS();
388 }
389
390 static void test_seal_split_end(void)
391 {
392         int ret;
393         void *ptr;
394         unsigned long page_size = getpagesize();
395         unsigned long size = 4 * page_size;
396
397         setup_single_address(size, &ptr);
398         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
399
400         /* use mprotect to split at middle */
401         ret = sys_mprotect(ptr, 2 * page_size, PROT_READ | PROT_WRITE);
402         FAIL_TEST_IF_FALSE(!ret);
403
404         /* seal the last page */
405         ret = sys_mseal(ptr + 3 * page_size, page_size);
406         FAIL_TEST_IF_FALSE(!ret);
407
408         /* Adding seals to the first 3 pages */
409         ret = sys_mseal(ptr, 3 * page_size);
410         FAIL_TEST_IF_FALSE(!ret);
411
412         REPORT_TEST_PASS();
413 }
414
415 static void test_seal_invalid_input(void)
416 {
417         void *ptr;
418         unsigned long page_size = getpagesize();
419         unsigned long size = 4 * page_size;
420         int ret;
421
422         setup_single_address(8 * page_size, &ptr);
423         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
424         ret = clean_single_address(ptr + 4 * page_size, 4 * page_size);
425         FAIL_TEST_IF_FALSE(!ret);
426
427         /* invalid flag */
428         ret = syscall(__NR_mseal, ptr, size, 0x20);
429         FAIL_TEST_IF_FALSE(ret < 0);
430
431         /* unaligned address */
432         ret = sys_mseal(ptr + 1, 2 * page_size);
433         FAIL_TEST_IF_FALSE(ret < 0);
434
435         /* length too big */
436         ret = sys_mseal(ptr, 5 * page_size);
437         FAIL_TEST_IF_FALSE(ret < 0);
438
439         /* length overflow */
440         ret = sys_mseal(ptr, UINT64_MAX/page_size);
441         FAIL_TEST_IF_FALSE(ret < 0);
442
443         /* start is not in a valid VMA */
444         ret = sys_mseal(ptr - page_size, 5 * page_size);
445         FAIL_TEST_IF_FALSE(ret < 0);
446
447         REPORT_TEST_PASS();
448 }
449
450 static void test_seal_zero_length(void)
451 {
452         void *ptr;
453         unsigned long page_size = getpagesize();
454         unsigned long size = 4 * page_size;
455         int ret;
456
457         setup_single_address(size, &ptr);
458         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
459
460         ret = sys_mprotect(ptr, 0, PROT_READ | PROT_WRITE);
461         FAIL_TEST_IF_FALSE(!ret);
462
463         /* seal 0 length will be OK, same as mprotect */
464         ret = sys_mseal(ptr, 0);
465         FAIL_TEST_IF_FALSE(!ret);
466
467         /* verify the 4 pages are not sealed by previous call. */
468         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
469         FAIL_TEST_IF_FALSE(!ret);
470
471         REPORT_TEST_PASS();
472 }
473
474 static void test_seal_zero_address(void)
475 {
476         void *ptr;
477         unsigned long page_size = getpagesize();
478         unsigned long size = 4 * page_size;
479         int ret;
480         int prot;
481
482         /* use mmap to change protection. */
483         ptr = mmap(0, size, PROT_NONE,
484                    MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
485         FAIL_TEST_IF_FALSE(ptr == 0);
486
487         size = get_vma_size(ptr, &prot);
488         FAIL_TEST_IF_FALSE(size == 4 * page_size);
489
490         ret = sys_mseal(ptr, size);
491         FAIL_TEST_IF_FALSE(!ret);
492
493         /* verify the 4 pages are sealed by previous call. */
494         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
495         FAIL_TEST_IF_FALSE(ret);
496
497         REPORT_TEST_PASS();
498 }
499
500 static void test_seal_twice(void)
501 {
502         int ret;
503         void *ptr;
504         unsigned long page_size = getpagesize();
505         unsigned long size = 4 * page_size;
506
507         setup_single_address(size, &ptr);
508         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
509
510         ret = sys_mseal(ptr, size);
511         FAIL_TEST_IF_FALSE(!ret);
512
513         /* apply the same seal will be OK. idempotent. */
514         ret = sys_mseal(ptr, size);
515         FAIL_TEST_IF_FALSE(!ret);
516
517         REPORT_TEST_PASS();
518 }
519
520 static void test_seal_mprotect(bool seal)
521 {
522         void *ptr;
523         unsigned long page_size = getpagesize();
524         unsigned long size = 4 * page_size;
525         int ret;
526
527         setup_single_address(size, &ptr);
528         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
529
530         if (seal) {
531                 ret = seal_single_address(ptr, size);
532                 FAIL_TEST_IF_FALSE(!ret);
533         }
534
535         ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
536         if (seal)
537                 FAIL_TEST_IF_FALSE(ret < 0);
538         else
539                 FAIL_TEST_IF_FALSE(!ret);
540
541         REPORT_TEST_PASS();
542 }
543
544 static void test_seal_start_mprotect(bool seal)
545 {
546         void *ptr;
547         unsigned long page_size = getpagesize();
548         unsigned long size = 4 * page_size;
549         int ret;
550
551         setup_single_address(size, &ptr);
552         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
553
554         if (seal) {
555                 ret = seal_single_address(ptr, page_size);
556                 FAIL_TEST_IF_FALSE(!ret);
557         }
558
559         /* the first page is sealed. */
560         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
561         if (seal)
562                 FAIL_TEST_IF_FALSE(ret < 0);
563         else
564                 FAIL_TEST_IF_FALSE(!ret);
565
566         /* pages after the first page is not sealed. */
567         ret = sys_mprotect(ptr + page_size, page_size * 3,
568                         PROT_READ | PROT_WRITE);
569         FAIL_TEST_IF_FALSE(!ret);
570
571         REPORT_TEST_PASS();
572 }
573
574 static void test_seal_end_mprotect(bool seal)
575 {
576         void *ptr;
577         unsigned long page_size = getpagesize();
578         unsigned long size = 4 * page_size;
579         int ret;
580
581         setup_single_address(size, &ptr);
582         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
583
584         if (seal) {
585                 ret = seal_single_address(ptr + page_size, 3 * page_size);
586                 FAIL_TEST_IF_FALSE(!ret);
587         }
588
589         /* first page is not sealed */
590         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
591         FAIL_TEST_IF_FALSE(!ret);
592
593         /* last 3 page are sealed */
594         ret = sys_mprotect(ptr + page_size, page_size * 3,
595                         PROT_READ | PROT_WRITE);
596         if (seal)
597                 FAIL_TEST_IF_FALSE(ret < 0);
598         else
599                 FAIL_TEST_IF_FALSE(!ret);
600
601         REPORT_TEST_PASS();
602 }
603
604 static void test_seal_mprotect_unalign_len(bool seal)
605 {
606         void *ptr;
607         unsigned long page_size = getpagesize();
608         unsigned long size = 4 * page_size;
609         int ret;
610
611         setup_single_address(size, &ptr);
612         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
613
614         if (seal) {
615                 ret = seal_single_address(ptr, page_size * 2 - 1);
616                 FAIL_TEST_IF_FALSE(!ret);
617         }
618
619         /* 2 pages are sealed. */
620         ret = sys_mprotect(ptr, page_size * 2, PROT_READ | PROT_WRITE);
621         if (seal)
622                 FAIL_TEST_IF_FALSE(ret < 0);
623         else
624                 FAIL_TEST_IF_FALSE(!ret);
625
626         ret = sys_mprotect(ptr + page_size * 2, page_size,
627                         PROT_READ | PROT_WRITE);
628         FAIL_TEST_IF_FALSE(!ret);
629
630         REPORT_TEST_PASS();
631 }
632
633 static void test_seal_mprotect_unalign_len_variant_2(bool seal)
634 {
635         void *ptr;
636         unsigned long page_size = getpagesize();
637         unsigned long size = 4 * page_size;
638         int ret;
639
640         setup_single_address(size, &ptr);
641         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
642         if (seal) {
643                 ret =  seal_single_address(ptr, page_size * 2 + 1);
644                 FAIL_TEST_IF_FALSE(!ret);
645         }
646
647         /* 3 pages are sealed. */
648         ret = sys_mprotect(ptr, page_size * 3, PROT_READ | PROT_WRITE);
649         if (seal)
650                 FAIL_TEST_IF_FALSE(ret < 0);
651         else
652                 FAIL_TEST_IF_FALSE(!ret);
653
654         ret = sys_mprotect(ptr + page_size * 3, page_size,
655                         PROT_READ | PROT_WRITE);
656         FAIL_TEST_IF_FALSE(!ret);
657
658         REPORT_TEST_PASS();
659 }
660
661 static void test_seal_mprotect_two_vma(bool seal)
662 {
663         void *ptr;
664         unsigned long page_size = getpagesize();
665         unsigned long size = 4 * page_size;
666         int ret;
667
668         setup_single_address(size, &ptr);
669         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
670
671         /* use mprotect to split */
672         ret = sys_mprotect(ptr, page_size * 2, PROT_READ | PROT_WRITE);
673         FAIL_TEST_IF_FALSE(!ret);
674
675         if (seal) {
676                 ret = seal_single_address(ptr, page_size * 4);
677                 FAIL_TEST_IF_FALSE(!ret);
678         }
679
680         ret = sys_mprotect(ptr, page_size * 2, PROT_READ | PROT_WRITE);
681         if (seal)
682                 FAIL_TEST_IF_FALSE(ret < 0);
683         else
684                 FAIL_TEST_IF_FALSE(!ret);
685
686         ret = sys_mprotect(ptr + page_size * 2, page_size * 2,
687                         PROT_READ | PROT_WRITE);
688         if (seal)
689                 FAIL_TEST_IF_FALSE(ret < 0);
690         else
691                 FAIL_TEST_IF_FALSE(!ret);
692
693         REPORT_TEST_PASS();
694 }
695
696 static void test_seal_mprotect_two_vma_with_split(bool seal)
697 {
698         void *ptr;
699         unsigned long page_size = getpagesize();
700         unsigned long size = 4 * page_size;
701         int ret;
702
703         setup_single_address(size, &ptr);
704         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
705
706         /* use mprotect to split as two vma. */
707         ret = sys_mprotect(ptr, page_size * 2, PROT_READ | PROT_WRITE);
708         FAIL_TEST_IF_FALSE(!ret);
709
710         /* mseal can apply across 2 vma, also split them. */
711         if (seal) {
712                 ret = seal_single_address(ptr + page_size, page_size * 2);
713                 FAIL_TEST_IF_FALSE(!ret);
714         }
715
716         /* the first page is not sealed. */
717         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
718         FAIL_TEST_IF_FALSE(!ret);
719
720         /* the second page is sealed. */
721         ret = sys_mprotect(ptr + page_size, page_size, PROT_READ | PROT_WRITE);
722         if (seal)
723                 FAIL_TEST_IF_FALSE(ret < 0);
724         else
725                 FAIL_TEST_IF_FALSE(!ret);
726
727         /* the third page is sealed. */
728         ret = sys_mprotect(ptr + 2 * page_size, page_size,
729                         PROT_READ | PROT_WRITE);
730         if (seal)
731                 FAIL_TEST_IF_FALSE(ret < 0);
732         else
733                 FAIL_TEST_IF_FALSE(!ret);
734
735         /* the fouth page is not sealed. */
736         ret = sys_mprotect(ptr + 3 * page_size, page_size,
737                         PROT_READ | PROT_WRITE);
738         FAIL_TEST_IF_FALSE(!ret);
739
740         REPORT_TEST_PASS();
741 }
742
743 static void test_seal_mprotect_partial_mprotect(bool seal)
744 {
745         void *ptr;
746         unsigned long page_size = getpagesize();
747         unsigned long size = 4 * page_size;
748         int ret;
749
750         setup_single_address(size, &ptr);
751         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
752
753         /* seal one page. */
754         if (seal) {
755                 ret = seal_single_address(ptr, page_size);
756                 FAIL_TEST_IF_FALSE(!ret);
757         }
758
759         /* mprotect first 2 page will fail, since the first page are sealed. */
760         ret = sys_mprotect(ptr, 2 * page_size, PROT_READ | PROT_WRITE);
761         if (seal)
762                 FAIL_TEST_IF_FALSE(ret < 0);
763         else
764                 FAIL_TEST_IF_FALSE(!ret);
765
766         REPORT_TEST_PASS();
767 }
768
769 static void test_seal_mprotect_partial_mprotect_tail(bool seal)
770 {
771         void *ptr;
772         unsigned long page_size = getpagesize();
773         unsigned long size = 2 * page_size;
774         int ret;
775         int prot;
776
777         /*
778          * Check if a partial mseal (that results in two vmas) works correctly.
779          * It might mprotect the first, but it'll never touch the second (msealed) vma.
780          */
781
782         setup_single_address(size, &ptr);
783         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
784
785         if (seal) {
786                 ret = sys_mseal(ptr + page_size, page_size);
787                 FAIL_TEST_IF_FALSE(!ret);
788         }
789
790         ret = sys_mprotect(ptr, size, PROT_EXEC);
791         if (seal)
792                 FAIL_TEST_IF_FALSE(ret < 0);
793         else
794                 FAIL_TEST_IF_FALSE(!ret);
795
796         if (seal) {
797                 FAIL_TEST_IF_FALSE(get_vma_size(ptr + page_size, &prot) > 0);
798                 FAIL_TEST_IF_FALSE(prot == 0x4);
799         }
800
801         REPORT_TEST_PASS();
802 }
803
804
805 static void test_seal_mprotect_two_vma_with_gap(bool seal)
806 {
807         void *ptr;
808         unsigned long page_size = getpagesize();
809         unsigned long size = 4 * page_size;
810         int ret;
811
812         setup_single_address(size, &ptr);
813         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
814
815         /* use mprotect to split. */
816         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
817         FAIL_TEST_IF_FALSE(!ret);
818
819         /* use mprotect to split. */
820         ret = sys_mprotect(ptr + 3 * page_size, page_size,
821                         PROT_READ | PROT_WRITE);
822         FAIL_TEST_IF_FALSE(!ret);
823
824         /* use munmap to free two pages in the middle */
825         ret = sys_munmap(ptr + page_size, 2 * page_size);
826         FAIL_TEST_IF_FALSE(!ret);
827
828         /* mprotect will fail, because there is a gap in the address. */
829         /* notes, internally mprotect still updated the first page. */
830         ret = sys_mprotect(ptr, 4 * page_size, PROT_READ);
831         FAIL_TEST_IF_FALSE(ret < 0);
832
833         /* mseal will fail as well. */
834         ret = sys_mseal(ptr, 4 * page_size);
835         FAIL_TEST_IF_FALSE(ret < 0);
836
837         /* the first page is not sealed. */
838         ret = sys_mprotect(ptr, page_size, PROT_READ);
839         FAIL_TEST_IF_FALSE(ret == 0);
840
841         /* the last page is not sealed. */
842         ret = sys_mprotect(ptr + 3 * page_size, page_size, PROT_READ);
843         FAIL_TEST_IF_FALSE(ret == 0);
844
845         REPORT_TEST_PASS();
846 }
847
848 static void test_seal_mprotect_split(bool seal)
849 {
850         void *ptr;
851         unsigned long page_size = getpagesize();
852         unsigned long size = 4 * page_size;
853         int ret;
854
855         setup_single_address(size, &ptr);
856         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
857
858         /* use mprotect to split. */
859         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
860         FAIL_TEST_IF_FALSE(!ret);
861
862         /* seal all 4 pages. */
863         if (seal) {
864                 ret = sys_mseal(ptr, 4 * page_size);
865                 FAIL_TEST_IF_FALSE(!ret);
866         }
867
868         /* mprotect is sealed. */
869         ret = sys_mprotect(ptr, 2 * page_size, PROT_READ);
870         if (seal)
871                 FAIL_TEST_IF_FALSE(ret < 0);
872         else
873                 FAIL_TEST_IF_FALSE(!ret);
874
875
876         ret = sys_mprotect(ptr + 2 * page_size, 2 * page_size, PROT_READ);
877         if (seal)
878                 FAIL_TEST_IF_FALSE(ret < 0);
879         else
880                 FAIL_TEST_IF_FALSE(!ret);
881
882         REPORT_TEST_PASS();
883 }
884
885 static void test_seal_mprotect_merge(bool seal)
886 {
887         void *ptr;
888         unsigned long page_size = getpagesize();
889         unsigned long size = 4 * page_size;
890         int ret;
891
892         setup_single_address(size, &ptr);
893         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
894
895         /* use mprotect to split one page. */
896         ret = sys_mprotect(ptr, page_size, PROT_READ | PROT_WRITE);
897         FAIL_TEST_IF_FALSE(!ret);
898
899         /* seal first two pages. */
900         if (seal) {
901                 ret = sys_mseal(ptr, 2 * page_size);
902                 FAIL_TEST_IF_FALSE(!ret);
903         }
904
905         /* 2 pages are sealed. */
906         ret = sys_mprotect(ptr, 2 * page_size, PROT_READ);
907         if (seal)
908                 FAIL_TEST_IF_FALSE(ret < 0);
909         else
910                 FAIL_TEST_IF_FALSE(!ret);
911
912         /* last 2 pages are not sealed. */
913         ret = sys_mprotect(ptr + 2 * page_size, 2 * page_size, PROT_READ);
914         FAIL_TEST_IF_FALSE(ret == 0);
915
916         REPORT_TEST_PASS();
917 }
918
919 static void test_seal_munmap(bool seal)
920 {
921         void *ptr;
922         unsigned long page_size = getpagesize();
923         unsigned long size = 4 * page_size;
924         int ret;
925
926         setup_single_address(size, &ptr);
927         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
928
929         if (seal) {
930                 ret = sys_mseal(ptr, size);
931                 FAIL_TEST_IF_FALSE(!ret);
932         }
933
934         /* 4 pages are sealed. */
935         ret = sys_munmap(ptr, size);
936         if (seal)
937                 FAIL_TEST_IF_FALSE(ret < 0);
938         else
939                 FAIL_TEST_IF_FALSE(!ret);
940
941         REPORT_TEST_PASS();
942 }
943
944 /*
945  * allocate 4 pages,
946  * use mprotect to split it as two VMAs
947  * seal the whole range
948  * munmap will fail on both
949  */
950 static void test_seal_munmap_two_vma(bool seal)
951 {
952         void *ptr;
953         unsigned long page_size = getpagesize();
954         unsigned long size = 4 * page_size;
955         int ret;
956
957         setup_single_address(size, &ptr);
958         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
959
960         /* use mprotect to split */
961         ret = sys_mprotect(ptr, page_size * 2, PROT_READ | PROT_WRITE);
962         FAIL_TEST_IF_FALSE(!ret);
963
964         if (seal) {
965                 ret = sys_mseal(ptr, size);
966                 FAIL_TEST_IF_FALSE(!ret);
967         }
968
969         ret = sys_munmap(ptr, page_size * 2);
970         if (seal)
971                 FAIL_TEST_IF_FALSE(ret < 0);
972         else
973                 FAIL_TEST_IF_FALSE(!ret);
974
975         ret = sys_munmap(ptr + page_size, page_size * 2);
976         if (seal)
977                 FAIL_TEST_IF_FALSE(ret < 0);
978         else
979                 FAIL_TEST_IF_FALSE(!ret);
980
981         REPORT_TEST_PASS();
982 }
983
984 /*
985  * allocate a VMA with 4 pages.
986  * munmap the middle 2 pages.
987  * seal the whole 4 pages, will fail.
988  * munmap the first page will be OK.
989  * munmap the last page will be OK.
990  */
991 static void test_seal_munmap_vma_with_gap(bool seal)
992 {
993         void *ptr;
994         unsigned long page_size = getpagesize();
995         unsigned long size = 4 * page_size;
996         int ret;
997
998         setup_single_address(size, &ptr);
999         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1000
1001         ret = sys_munmap(ptr + page_size, page_size * 2);
1002         FAIL_TEST_IF_FALSE(!ret);
1003
1004         if (seal) {
1005                 /* can't have gap in the middle. */
1006                 ret = sys_mseal(ptr, size);
1007                 FAIL_TEST_IF_FALSE(ret < 0);
1008         }
1009
1010         ret = sys_munmap(ptr, page_size);
1011         FAIL_TEST_IF_FALSE(!ret);
1012
1013         ret = sys_munmap(ptr + page_size * 2, page_size);
1014         FAIL_TEST_IF_FALSE(!ret);
1015
1016         ret = sys_munmap(ptr, size);
1017         FAIL_TEST_IF_FALSE(!ret);
1018
1019         REPORT_TEST_PASS();
1020 }
1021
1022 static void test_seal_munmap_partial_across_vmas(bool seal)
1023 {
1024         void *ptr;
1025         unsigned long page_size = getpagesize();
1026         unsigned long size = 2 * page_size;
1027         int ret;
1028         int prot;
1029
1030         setup_single_address(size, &ptr);
1031         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1032
1033         if (seal) {
1034                 ret = sys_mseal(ptr + page_size, page_size);
1035                 FAIL_TEST_IF_FALSE(!ret);
1036         }
1037
1038         ret = sys_munmap(ptr, size);
1039         if (seal)
1040                 FAIL_TEST_IF_FALSE(ret < 0);
1041         else
1042                 FAIL_TEST_IF_FALSE(!ret);
1043
1044         if (seal) {
1045                 FAIL_TEST_IF_FALSE(get_vma_size(ptr + page_size, &prot) > 0);
1046                 FAIL_TEST_IF_FALSE(prot == 0x4);
1047         }
1048
1049         REPORT_TEST_PASS();
1050 }
1051
1052 static void test_munmap_start_freed(bool seal)
1053 {
1054         void *ptr;
1055         unsigned long page_size = getpagesize();
1056         unsigned long size = 4 * page_size;
1057         int ret;
1058         int prot;
1059
1060         setup_single_address(size, &ptr);
1061         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1062
1063         /* unmap the first page. */
1064         ret = sys_munmap(ptr, page_size);
1065         FAIL_TEST_IF_FALSE(!ret);
1066
1067         /* seal the last 3 pages. */
1068         if (seal) {
1069                 ret = sys_mseal(ptr + page_size, 3 * page_size);
1070                 FAIL_TEST_IF_FALSE(!ret);
1071         }
1072
1073         /* unmap from the first page. */
1074         ret = sys_munmap(ptr, size);
1075         if (seal) {
1076                 FAIL_TEST_IF_FALSE(ret < 0);
1077
1078                 size = get_vma_size(ptr + page_size, &prot);
1079                 FAIL_TEST_IF_FALSE(size == page_size * 3);
1080         } else {
1081                 /* note: this will be OK, even the first page is */
1082                 /* already unmapped. */
1083                 FAIL_TEST_IF_FALSE(!ret);
1084
1085                 size = get_vma_size(ptr + page_size, &prot);
1086                 FAIL_TEST_IF_FALSE(size == 0);
1087         }
1088
1089         REPORT_TEST_PASS();
1090 }
1091
1092 static void test_munmap_end_freed(bool seal)
1093 {
1094         void *ptr;
1095         unsigned long page_size = getpagesize();
1096         unsigned long size = 4 * page_size;
1097         int ret;
1098
1099         setup_single_address(size, &ptr);
1100         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1101
1102         /* unmap last page. */
1103         ret = sys_munmap(ptr + page_size * 3, page_size);
1104         FAIL_TEST_IF_FALSE(!ret);
1105
1106         /* seal the first 3 pages. */
1107         if (seal) {
1108                 ret = sys_mseal(ptr, 3 * page_size);
1109                 FAIL_TEST_IF_FALSE(!ret);
1110         }
1111
1112         /* unmap all pages. */
1113         ret = sys_munmap(ptr, size);
1114         if (seal)
1115                 FAIL_TEST_IF_FALSE(ret < 0);
1116         else
1117                 FAIL_TEST_IF_FALSE(!ret);
1118
1119         REPORT_TEST_PASS();
1120 }
1121
1122 static void test_munmap_middle_freed(bool seal)
1123 {
1124         void *ptr;
1125         unsigned long page_size = getpagesize();
1126         unsigned long size = 4 * page_size;
1127         int ret;
1128         int prot;
1129
1130         setup_single_address(size, &ptr);
1131         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1132
1133         /* unmap 2 pages in the middle. */
1134         ret = sys_munmap(ptr + page_size, page_size * 2);
1135         FAIL_TEST_IF_FALSE(!ret);
1136
1137         /* seal the first page. */
1138         if (seal) {
1139                 ret = sys_mseal(ptr, page_size);
1140                 FAIL_TEST_IF_FALSE(!ret);
1141         }
1142
1143         /* munmap all 4 pages. */
1144         ret = sys_munmap(ptr, size);
1145         if (seal) {
1146                 FAIL_TEST_IF_FALSE(ret < 0);
1147
1148                 size = get_vma_size(ptr, &prot);
1149                 FAIL_TEST_IF_FALSE(size == page_size);
1150
1151                 size = get_vma_size(ptr + page_size * 3, &prot);
1152                 FAIL_TEST_IF_FALSE(size == page_size);
1153         } else {
1154                 FAIL_TEST_IF_FALSE(!ret);
1155
1156                 size = get_vma_size(ptr, &prot);
1157                 FAIL_TEST_IF_FALSE(size == 0);
1158
1159                 size = get_vma_size(ptr + page_size * 3, &prot);
1160                 FAIL_TEST_IF_FALSE(size == 0);
1161         }
1162
1163         REPORT_TEST_PASS();
1164 }
1165
1166 static void test_seal_mremap_shrink(bool seal)
1167 {
1168         void *ptr;
1169         unsigned long page_size = getpagesize();
1170         unsigned long size = 4 * page_size;
1171         int ret;
1172         void *ret2;
1173
1174         setup_single_address(size, &ptr);
1175         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1176
1177         if (seal) {
1178                 ret = sys_mseal(ptr, size);
1179                 FAIL_TEST_IF_FALSE(!ret);
1180         }
1181
1182         /* shrink from 4 pages to 2 pages. */
1183         ret2 = sys_mremap(ptr, size, 2 * page_size, 0, 0);
1184         if (seal) {
1185                 FAIL_TEST_IF_FALSE(ret2 == (void *) MAP_FAILED);
1186                 FAIL_TEST_IF_FALSE(errno == EPERM);
1187         } else {
1188                 FAIL_TEST_IF_FALSE(ret2 != (void *) MAP_FAILED);
1189
1190         }
1191
1192         REPORT_TEST_PASS();
1193 }
1194
1195 static void test_seal_mremap_expand(bool seal)
1196 {
1197         void *ptr;
1198         unsigned long page_size = getpagesize();
1199         unsigned long size = 4 * page_size;
1200         int ret;
1201         void *ret2;
1202
1203         setup_single_address(size, &ptr);
1204         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1205         /* ummap last 2 pages. */
1206         ret = sys_munmap(ptr + 2 * page_size, 2 * page_size);
1207         FAIL_TEST_IF_FALSE(!ret);
1208
1209         if (seal) {
1210                 ret = sys_mseal(ptr, 2 * page_size);
1211                 FAIL_TEST_IF_FALSE(!ret);
1212         }
1213
1214         /* expand from 2 page to 4 pages. */
1215         ret2 = sys_mremap(ptr, 2 * page_size, 4 * page_size, 0, 0);
1216         if (seal) {
1217                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1218                 FAIL_TEST_IF_FALSE(errno == EPERM);
1219         } else {
1220                 FAIL_TEST_IF_FALSE(ret2 == ptr);
1221
1222         }
1223
1224         REPORT_TEST_PASS();
1225 }
1226
1227 static void test_seal_mremap_move(bool seal)
1228 {
1229         void *ptr, *newPtr;
1230         unsigned long page_size = getpagesize();
1231         unsigned long size = page_size;
1232         int ret;
1233         void *ret2;
1234
1235         setup_single_address(size, &ptr);
1236         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1237         setup_single_address(size, &newPtr);
1238         FAIL_TEST_IF_FALSE(newPtr != (void *)-1);
1239         ret = clean_single_address(newPtr, size);
1240         FAIL_TEST_IF_FALSE(!ret);
1241
1242         if (seal) {
1243                 ret = sys_mseal(ptr, size);
1244                 FAIL_TEST_IF_FALSE(!ret);
1245         }
1246
1247         /* move from ptr to fixed address. */
1248         ret2 = sys_mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, newPtr);
1249         if (seal) {
1250                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1251                 FAIL_TEST_IF_FALSE(errno == EPERM);
1252         } else {
1253                 FAIL_TEST_IF_FALSE(ret2 != MAP_FAILED);
1254
1255         }
1256
1257         REPORT_TEST_PASS();
1258 }
1259
1260 static void test_seal_mmap_overwrite_prot(bool seal)
1261 {
1262         void *ptr;
1263         unsigned long page_size = getpagesize();
1264         unsigned long size = page_size;
1265         int ret;
1266         void *ret2;
1267
1268         setup_single_address(size, &ptr);
1269         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1270
1271         if (seal) {
1272                 ret = sys_mseal(ptr, size);
1273                 FAIL_TEST_IF_FALSE(!ret);
1274         }
1275
1276         /* use mmap to change protection. */
1277         ret2 = mmap(ptr, size, PROT_NONE,
1278                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1279         if (seal) {
1280                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1281                 FAIL_TEST_IF_FALSE(errno == EPERM);
1282         } else
1283                 FAIL_TEST_IF_FALSE(ret2 == ptr);
1284
1285         REPORT_TEST_PASS();
1286 }
1287
1288 static void test_seal_mmap_expand(bool seal)
1289 {
1290         void *ptr;
1291         unsigned long page_size = getpagesize();
1292         unsigned long size = 12 * page_size;
1293         int ret;
1294         void *ret2;
1295
1296         setup_single_address(size, &ptr);
1297         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1298         /* ummap last 4 pages. */
1299         ret = sys_munmap(ptr + 8 * page_size, 4 * page_size);
1300         FAIL_TEST_IF_FALSE(!ret);
1301
1302         if (seal) {
1303                 ret = sys_mseal(ptr, 8 * page_size);
1304                 FAIL_TEST_IF_FALSE(!ret);
1305         }
1306
1307         /* use mmap to expand. */
1308         ret2 = mmap(ptr, size, PROT_READ,
1309                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1310         if (seal) {
1311                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1312                 FAIL_TEST_IF_FALSE(errno == EPERM);
1313         } else
1314                 FAIL_TEST_IF_FALSE(ret2 == ptr);
1315
1316         REPORT_TEST_PASS();
1317 }
1318
1319 static void test_seal_mmap_shrink(bool seal)
1320 {
1321         void *ptr;
1322         unsigned long page_size = getpagesize();
1323         unsigned long size = 12 * page_size;
1324         int ret;
1325         void *ret2;
1326
1327         setup_single_address(size, &ptr);
1328         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1329
1330         if (seal) {
1331                 ret = sys_mseal(ptr, size);
1332                 FAIL_TEST_IF_FALSE(!ret);
1333         }
1334
1335         /* use mmap to shrink. */
1336         ret2 = mmap(ptr, 8 * page_size, PROT_READ,
1337                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
1338         if (seal) {
1339                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1340                 FAIL_TEST_IF_FALSE(errno == EPERM);
1341         } else
1342                 FAIL_TEST_IF_FALSE(ret2 == ptr);
1343
1344         REPORT_TEST_PASS();
1345 }
1346
1347 static void test_seal_mremap_shrink_fixed(bool seal)
1348 {
1349         void *ptr;
1350         void *newAddr;
1351         unsigned long page_size = getpagesize();
1352         unsigned long size = 4 * page_size;
1353         int ret;
1354         void *ret2;
1355
1356         setup_single_address(size, &ptr);
1357         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1358         setup_single_address(size, &newAddr);
1359         FAIL_TEST_IF_FALSE(newAddr != (void *)-1);
1360
1361         if (seal) {
1362                 ret = sys_mseal(ptr, size);
1363                 FAIL_TEST_IF_FALSE(!ret);
1364         }
1365
1366         /* mremap to move and shrink to fixed address */
1367         ret2 = sys_mremap(ptr, size, 2 * page_size, MREMAP_MAYMOVE | MREMAP_FIXED,
1368                         newAddr);
1369         if (seal) {
1370                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1371                 FAIL_TEST_IF_FALSE(errno == EPERM);
1372         } else
1373                 FAIL_TEST_IF_FALSE(ret2 == newAddr);
1374
1375         REPORT_TEST_PASS();
1376 }
1377
1378 static void test_seal_mremap_expand_fixed(bool seal)
1379 {
1380         void *ptr;
1381         void *newAddr;
1382         unsigned long page_size = getpagesize();
1383         unsigned long size = 4 * page_size;
1384         int ret;
1385         void *ret2;
1386
1387         setup_single_address(page_size, &ptr);
1388         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1389         setup_single_address(size, &newAddr);
1390         FAIL_TEST_IF_FALSE(newAddr != (void *)-1);
1391
1392         if (seal) {
1393                 ret = sys_mseal(newAddr, size);
1394                 FAIL_TEST_IF_FALSE(!ret);
1395         }
1396
1397         /* mremap to move and expand to fixed address */
1398         ret2 = sys_mremap(ptr, page_size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
1399                         newAddr);
1400         if (seal) {
1401                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1402                 FAIL_TEST_IF_FALSE(errno == EPERM);
1403         } else
1404                 FAIL_TEST_IF_FALSE(ret2 == newAddr);
1405
1406         REPORT_TEST_PASS();
1407 }
1408
1409 static void test_seal_mremap_move_fixed(bool seal)
1410 {
1411         void *ptr;
1412         void *newAddr;
1413         unsigned long page_size = getpagesize();
1414         unsigned long size = 4 * page_size;
1415         int ret;
1416         void *ret2;
1417
1418         setup_single_address(size, &ptr);
1419         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1420         setup_single_address(size, &newAddr);
1421         FAIL_TEST_IF_FALSE(newAddr != (void *)-1);
1422
1423         if (seal) {
1424                 ret = sys_mseal(newAddr, size);
1425                 FAIL_TEST_IF_FALSE(!ret);
1426         }
1427
1428         /* mremap to move to fixed address */
1429         ret2 = sys_mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, newAddr);
1430         if (seal) {
1431                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1432                 FAIL_TEST_IF_FALSE(errno == EPERM);
1433         } else
1434                 FAIL_TEST_IF_FALSE(ret2 == newAddr);
1435
1436         REPORT_TEST_PASS();
1437 }
1438
1439 static void test_seal_mremap_move_fixed_zero(bool seal)
1440 {
1441         void *ptr;
1442         unsigned long page_size = getpagesize();
1443         unsigned long size = 4 * page_size;
1444         int ret;
1445         void *ret2;
1446
1447         setup_single_address(size, &ptr);
1448         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1449
1450         if (seal) {
1451                 ret = sys_mseal(ptr, size);
1452                 FAIL_TEST_IF_FALSE(!ret);
1453         }
1454
1455         /*
1456          * MREMAP_FIXED can move the mapping to zero address
1457          */
1458         ret2 = sys_mremap(ptr, size, 2 * page_size, MREMAP_MAYMOVE | MREMAP_FIXED,
1459                         0);
1460         if (seal) {
1461                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1462                 FAIL_TEST_IF_FALSE(errno == EPERM);
1463         } else {
1464                 FAIL_TEST_IF_FALSE(ret2 == 0);
1465         }
1466
1467         REPORT_TEST_PASS();
1468 }
1469
1470 static void test_seal_mremap_move_dontunmap(bool seal)
1471 {
1472         void *ptr;
1473         unsigned long page_size = getpagesize();
1474         unsigned long size = 4 * page_size;
1475         int ret;
1476         void *ret2;
1477
1478         setup_single_address(size, &ptr);
1479         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1480
1481         if (seal) {
1482                 ret = sys_mseal(ptr, size);
1483                 FAIL_TEST_IF_FALSE(!ret);
1484         }
1485
1486         /* mremap to move, and don't unmap src addr. */
1487         ret2 = sys_mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_DONTUNMAP, 0);
1488         if (seal) {
1489                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1490                 FAIL_TEST_IF_FALSE(errno == EPERM);
1491         } else {
1492                 /* kernel will allocate a new address */
1493                 FAIL_TEST_IF_FALSE(ret2 != MAP_FAILED);
1494         }
1495
1496         REPORT_TEST_PASS();
1497 }
1498
1499 static void test_seal_mremap_move_dontunmap_anyaddr(bool seal)
1500 {
1501         void *ptr, *ptr2;
1502         unsigned long page_size = getpagesize();
1503         unsigned long size = 4 * page_size;
1504         int ret;
1505         void *ret2;
1506
1507         setup_single_address(size, &ptr);
1508         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1509
1510         if (seal) {
1511                 ret = sys_mseal(ptr, size);
1512                 FAIL_TEST_IF_FALSE(!ret);
1513         }
1514
1515         /*
1516          * The new address is any address that not allocated.
1517          * use allocate/free to similate that.
1518          */
1519         setup_single_address(size, &ptr2);
1520         FAIL_TEST_IF_FALSE(ptr2 != (void *)-1);
1521         ret = sys_munmap(ptr2, size);
1522         FAIL_TEST_IF_FALSE(!ret);
1523
1524         /*
1525          * remap to any address.
1526          */
1527         ret2 = sys_mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
1528                         (void *) ptr2);
1529         if (seal) {
1530                 FAIL_TEST_IF_FALSE(ret2 == MAP_FAILED);
1531                 FAIL_TEST_IF_FALSE(errno == EPERM);
1532         } else {
1533                 /* remap success and return ptr2 */
1534                 FAIL_TEST_IF_FALSE(ret2 ==  ptr2);
1535         }
1536
1537         REPORT_TEST_PASS();
1538 }
1539
1540 static void test_seal_merge_and_split(void)
1541 {
1542         void *ptr;
1543         unsigned long page_size = getpagesize();
1544         unsigned long size;
1545         int ret;
1546         int prot;
1547
1548         /* (24 RO) */
1549         setup_single_address(24 * page_size, &ptr);
1550         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1551
1552         /* use mprotect(NONE) to set out boundary */
1553         /* (1 NONE) (22 RO) (1 NONE) */
1554         ret = sys_mprotect(ptr, page_size, PROT_NONE);
1555         FAIL_TEST_IF_FALSE(!ret);
1556         ret = sys_mprotect(ptr + 23 * page_size, page_size, PROT_NONE);
1557         FAIL_TEST_IF_FALSE(!ret);
1558         size = get_vma_size(ptr + page_size, &prot);
1559         FAIL_TEST_IF_FALSE(size == 22 * page_size);
1560         FAIL_TEST_IF_FALSE(prot == 4);
1561
1562         /* use mseal to split from beginning */
1563         /* (1 NONE) (1 RO_SEAL) (21 RO) (1 NONE) */
1564         ret = sys_mseal(ptr + page_size, page_size);
1565         FAIL_TEST_IF_FALSE(!ret);
1566         size = get_vma_size(ptr + page_size, &prot);
1567         FAIL_TEST_IF_FALSE(size == page_size);
1568         FAIL_TEST_IF_FALSE(prot == 0x4);
1569         size = get_vma_size(ptr + 2 * page_size, &prot);
1570         FAIL_TEST_IF_FALSE(size == 21 * page_size);
1571         FAIL_TEST_IF_FALSE(prot == 0x4);
1572
1573         /* use mseal to split from the end. */
1574         /* (1 NONE) (1 RO_SEAL) (20 RO) (1 RO_SEAL) (1 NONE) */
1575         ret = sys_mseal(ptr + 22 * page_size, page_size);
1576         FAIL_TEST_IF_FALSE(!ret);
1577         size = get_vma_size(ptr + 22 * page_size, &prot);
1578         FAIL_TEST_IF_FALSE(size == page_size);
1579         FAIL_TEST_IF_FALSE(prot == 0x4);
1580         size = get_vma_size(ptr + 2 * page_size, &prot);
1581         FAIL_TEST_IF_FALSE(size == 20 * page_size);
1582         FAIL_TEST_IF_FALSE(prot == 0x4);
1583
1584         /* merge with prev. */
1585         /* (1 NONE) (2 RO_SEAL) (19 RO) (1 RO_SEAL) (1 NONE) */
1586         ret = sys_mseal(ptr + 2 * page_size, page_size);
1587         FAIL_TEST_IF_FALSE(!ret);
1588         size = get_vma_size(ptr +  page_size, &prot);
1589         FAIL_TEST_IF_FALSE(size ==  2 * page_size);
1590         FAIL_TEST_IF_FALSE(prot == 0x4);
1591
1592         /* merge with after. */
1593         /* (1 NONE) (2 RO_SEAL) (18 RO) (2 RO_SEALS) (1 NONE) */
1594         ret = sys_mseal(ptr + 21 * page_size, page_size);
1595         FAIL_TEST_IF_FALSE(!ret);
1596         size = get_vma_size(ptr +  21 * page_size, &prot);
1597         FAIL_TEST_IF_FALSE(size ==  2 * page_size);
1598         FAIL_TEST_IF_FALSE(prot == 0x4);
1599
1600         /* split and merge from prev */
1601         /* (1 NONE) (3 RO_SEAL) (17 RO) (2 RO_SEALS) (1 NONE) */
1602         ret = sys_mseal(ptr + 2 * page_size, 2 * page_size);
1603         FAIL_TEST_IF_FALSE(!ret);
1604         size = get_vma_size(ptr +  1 * page_size, &prot);
1605         FAIL_TEST_IF_FALSE(size ==  3 * page_size);
1606         FAIL_TEST_IF_FALSE(prot == 0x4);
1607         ret = sys_munmap(ptr + page_size,  page_size);
1608         FAIL_TEST_IF_FALSE(ret < 0);
1609         ret = sys_mprotect(ptr + 2 * page_size, page_size,  PROT_NONE);
1610         FAIL_TEST_IF_FALSE(ret < 0);
1611
1612         /* split and merge from next */
1613         /* (1 NONE) (3 RO_SEAL) (16 RO) (3 RO_SEALS) (1 NONE) */
1614         ret = sys_mseal(ptr + 20 * page_size, 2 * page_size);
1615         FAIL_TEST_IF_FALSE(!ret);
1616         FAIL_TEST_IF_FALSE(prot == 0x4);
1617         size = get_vma_size(ptr +  20 * page_size, &prot);
1618         FAIL_TEST_IF_FALSE(size ==  3 * page_size);
1619         FAIL_TEST_IF_FALSE(prot == 0x4);
1620
1621         /* merge from middle of prev and middle of next. */
1622         /* (1 NONE) (22 RO_SEAL) (1 NONE) */
1623         ret = sys_mseal(ptr + 2 * page_size, 20 * page_size);
1624         FAIL_TEST_IF_FALSE(!ret);
1625         size = get_vma_size(ptr +  page_size, &prot);
1626         FAIL_TEST_IF_FALSE(size ==  22 * page_size);
1627         FAIL_TEST_IF_FALSE(prot == 0x4);
1628
1629         REPORT_TEST_PASS();
1630 }
1631
1632 static void test_seal_discard_ro_anon_on_rw(bool seal)
1633 {
1634         void *ptr;
1635         unsigned long page_size = getpagesize();
1636         unsigned long size = 4 * page_size;
1637         int ret;
1638
1639         setup_single_address_rw(size, &ptr);
1640         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1641
1642         if (seal) {
1643                 ret = sys_mseal(ptr, size);
1644                 FAIL_TEST_IF_FALSE(!ret);
1645         }
1646
1647         /* sealing doesn't take effect on RW memory. */
1648         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1649         FAIL_TEST_IF_FALSE(!ret);
1650
1651         /* base seal still apply. */
1652         ret = sys_munmap(ptr, size);
1653         if (seal)
1654                 FAIL_TEST_IF_FALSE(ret < 0);
1655         else
1656                 FAIL_TEST_IF_FALSE(!ret);
1657
1658         REPORT_TEST_PASS();
1659 }
1660
1661 static void test_seal_discard_ro_anon_on_pkey(bool seal)
1662 {
1663         void *ptr;
1664         unsigned long page_size = getpagesize();
1665         unsigned long size = 4 * page_size;
1666         int ret;
1667         int pkey;
1668
1669         SKIP_TEST_IF_FALSE(pkey_supported());
1670
1671         setup_single_address_rw(size, &ptr);
1672         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1673
1674         pkey = sys_pkey_alloc(0, 0);
1675         FAIL_TEST_IF_FALSE(pkey > 0);
1676
1677         ret = sys_mprotect_pkey((void *)ptr, size, PROT_READ | PROT_WRITE, pkey);
1678         FAIL_TEST_IF_FALSE(!ret);
1679
1680         if (seal) {
1681                 ret = sys_mseal(ptr, size);
1682                 FAIL_TEST_IF_FALSE(!ret);
1683         }
1684
1685         /* sealing doesn't take effect if PKRU allow write. */
1686         set_pkey(pkey, 0);
1687         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1688         FAIL_TEST_IF_FALSE(!ret);
1689
1690         /* sealing will take effect if PKRU deny write. */
1691         set_pkey(pkey, PKEY_DISABLE_WRITE);
1692         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1693         if (seal)
1694                 FAIL_TEST_IF_FALSE(ret < 0);
1695         else
1696                 FAIL_TEST_IF_FALSE(!ret);
1697
1698         /* base seal still apply. */
1699         ret = sys_munmap(ptr, size);
1700         if (seal)
1701                 FAIL_TEST_IF_FALSE(ret < 0);
1702         else
1703                 FAIL_TEST_IF_FALSE(!ret);
1704
1705         REPORT_TEST_PASS();
1706 }
1707
1708 static void test_seal_discard_ro_anon_on_filebacked(bool seal)
1709 {
1710         void *ptr;
1711         unsigned long page_size = getpagesize();
1712         unsigned long size = 4 * page_size;
1713         int ret;
1714         int fd;
1715         unsigned long mapflags = MAP_PRIVATE;
1716
1717         fd = memfd_create("test", 0);
1718         FAIL_TEST_IF_FALSE(fd > 0);
1719
1720         ret = fallocate(fd, 0, 0, size);
1721         FAIL_TEST_IF_FALSE(!ret);
1722
1723         ptr = mmap(NULL, size, PROT_READ, mapflags, fd, 0);
1724         FAIL_TEST_IF_FALSE(ptr != MAP_FAILED);
1725
1726         if (seal) {
1727                 ret = sys_mseal(ptr, size);
1728                 FAIL_TEST_IF_FALSE(!ret);
1729         }
1730
1731         /* sealing doesn't apply for file backed mapping. */
1732         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1733         FAIL_TEST_IF_FALSE(!ret);
1734
1735         ret = sys_munmap(ptr, size);
1736         if (seal)
1737                 FAIL_TEST_IF_FALSE(ret < 0);
1738         else
1739                 FAIL_TEST_IF_FALSE(!ret);
1740         close(fd);
1741
1742         REPORT_TEST_PASS();
1743 }
1744
1745 static void test_seal_discard_ro_anon_on_shared(bool seal)
1746 {
1747         void *ptr;
1748         unsigned long page_size = getpagesize();
1749         unsigned long size = 4 * page_size;
1750         int ret;
1751         unsigned long mapflags = MAP_ANONYMOUS | MAP_SHARED;
1752
1753         ptr = mmap(NULL, size, PROT_READ, mapflags, -1, 0);
1754         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1755
1756         if (seal) {
1757                 ret = sys_mseal(ptr, size);
1758                 FAIL_TEST_IF_FALSE(!ret);
1759         }
1760
1761         /* sealing doesn't apply for shared mapping. */
1762         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1763         FAIL_TEST_IF_FALSE(!ret);
1764
1765         ret = sys_munmap(ptr, size);
1766         if (seal)
1767                 FAIL_TEST_IF_FALSE(ret < 0);
1768         else
1769                 FAIL_TEST_IF_FALSE(!ret);
1770
1771         REPORT_TEST_PASS();
1772 }
1773
1774 static void test_seal_discard_ro_anon(bool seal)
1775 {
1776         void *ptr;
1777         unsigned long page_size = getpagesize();
1778         unsigned long size = 4 * page_size;
1779         int ret;
1780
1781         setup_single_address(size, &ptr);
1782         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1783
1784         if (seal) {
1785                 ret = seal_single_address(ptr, size);
1786                 FAIL_TEST_IF_FALSE(!ret);
1787         }
1788
1789         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1790         if (seal)
1791                 FAIL_TEST_IF_FALSE(ret < 0);
1792         else
1793                 FAIL_TEST_IF_FALSE(!ret);
1794
1795         ret = sys_munmap(ptr, size);
1796         if (seal)
1797                 FAIL_TEST_IF_FALSE(ret < 0);
1798         else
1799                 FAIL_TEST_IF_FALSE(!ret);
1800
1801         REPORT_TEST_PASS();
1802 }
1803
1804 static void test_seal_discard_across_vmas(bool seal)
1805 {
1806         void *ptr;
1807         unsigned long page_size = getpagesize();
1808         unsigned long size = 2 * page_size;
1809         int ret;
1810
1811         setup_single_address(size, &ptr);
1812         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1813
1814         if (seal) {
1815                 ret = seal_single_address(ptr + page_size, page_size);
1816                 FAIL_TEST_IF_FALSE(!ret);
1817         }
1818
1819         ret = sys_madvise(ptr, size, MADV_DONTNEED);
1820         if (seal)
1821                 FAIL_TEST_IF_FALSE(ret < 0);
1822         else
1823                 FAIL_TEST_IF_FALSE(!ret);
1824
1825         ret = sys_munmap(ptr, size);
1826         if (seal)
1827                 FAIL_TEST_IF_FALSE(ret < 0);
1828         else
1829                 FAIL_TEST_IF_FALSE(!ret);
1830
1831         REPORT_TEST_PASS();
1832 }
1833
1834
1835 static void test_seal_madvise_nodiscard(bool seal)
1836 {
1837         void *ptr;
1838         unsigned long page_size = getpagesize();
1839         unsigned long size = 4 * page_size;
1840         int ret;
1841
1842         setup_single_address(size, &ptr);
1843         FAIL_TEST_IF_FALSE(ptr != (void *)-1);
1844
1845         if (seal) {
1846                 ret = seal_single_address(ptr, size);
1847                 FAIL_TEST_IF_FALSE(!ret);
1848         }
1849
1850         /*
1851          * Test a random madvise flag like MADV_RANDOM that does not touch page
1852          * contents (and thus should work for msealed VMAs). RANDOM also happens to
1853          * share bits with other discard-ish flags like REMOVE.
1854          */
1855         ret = sys_madvise(ptr, size, MADV_RANDOM);
1856         FAIL_TEST_IF_FALSE(!ret);
1857
1858         ret = sys_munmap(ptr, size);
1859         if (seal)
1860                 FAIL_TEST_IF_FALSE(ret < 0);
1861         else
1862                 FAIL_TEST_IF_FALSE(!ret);
1863
1864         REPORT_TEST_PASS();
1865 }
1866
1867 int main(int argc, char **argv)
1868 {
1869         bool test_seal = seal_support();
1870
1871         ksft_print_header();
1872
1873         if (!test_seal)
1874                 ksft_exit_skip("sealing not supported, check CONFIG_64BIT\n");
1875
1876         if (!pkey_supported())
1877                 ksft_print_msg("PKEY not supported\n");
1878
1879         ksft_set_plan(88);
1880
1881         test_seal_addseal();
1882         test_seal_unmapped_start();
1883         test_seal_unmapped_middle();
1884         test_seal_unmapped_end();
1885         test_seal_multiple_vmas();
1886         test_seal_split_start();
1887         test_seal_split_end();
1888         test_seal_invalid_input();
1889         test_seal_zero_length();
1890         test_seal_twice();
1891
1892         test_seal_mprotect(false);
1893         test_seal_mprotect(true);
1894
1895         test_seal_start_mprotect(false);
1896         test_seal_start_mprotect(true);
1897
1898         test_seal_end_mprotect(false);
1899         test_seal_end_mprotect(true);
1900
1901         test_seal_mprotect_unalign_len(false);
1902         test_seal_mprotect_unalign_len(true);
1903
1904         test_seal_mprotect_unalign_len_variant_2(false);
1905         test_seal_mprotect_unalign_len_variant_2(true);
1906
1907         test_seal_mprotect_two_vma(false);
1908         test_seal_mprotect_two_vma(true);
1909
1910         test_seal_mprotect_two_vma_with_split(false);
1911         test_seal_mprotect_two_vma_with_split(true);
1912
1913         test_seal_mprotect_partial_mprotect(false);
1914         test_seal_mprotect_partial_mprotect(true);
1915
1916         test_seal_mprotect_two_vma_with_gap(false);
1917         test_seal_mprotect_two_vma_with_gap(true);
1918
1919         test_seal_mprotect_merge(false);
1920         test_seal_mprotect_merge(true);
1921
1922         test_seal_mprotect_split(false);
1923         test_seal_mprotect_split(true);
1924
1925         test_seal_mprotect_partial_mprotect_tail(false);
1926         test_seal_mprotect_partial_mprotect_tail(true);
1927
1928         test_seal_munmap(false);
1929         test_seal_munmap(true);
1930         test_seal_munmap_two_vma(false);
1931         test_seal_munmap_two_vma(true);
1932         test_seal_munmap_vma_with_gap(false);
1933         test_seal_munmap_vma_with_gap(true);
1934         test_seal_munmap_partial_across_vmas(false);
1935         test_seal_munmap_partial_across_vmas(true);
1936
1937         test_munmap_start_freed(false);
1938         test_munmap_start_freed(true);
1939         test_munmap_middle_freed(false);
1940         test_munmap_middle_freed(true);
1941         test_munmap_end_freed(false);
1942         test_munmap_end_freed(true);
1943
1944         test_seal_mremap_shrink(false);
1945         test_seal_mremap_shrink(true);
1946         test_seal_mremap_expand(false);
1947         test_seal_mremap_expand(true);
1948         test_seal_mremap_move(false);
1949         test_seal_mremap_move(true);
1950
1951         test_seal_mremap_shrink_fixed(false);
1952         test_seal_mremap_shrink_fixed(true);
1953         test_seal_mremap_expand_fixed(false);
1954         test_seal_mremap_expand_fixed(true);
1955         test_seal_mremap_move_fixed(false);
1956         test_seal_mremap_move_fixed(true);
1957         test_seal_mremap_move_dontunmap(false);
1958         test_seal_mremap_move_dontunmap(true);
1959         test_seal_mremap_move_fixed_zero(false);
1960         test_seal_mremap_move_fixed_zero(true);
1961         test_seal_mremap_move_dontunmap_anyaddr(false);
1962         test_seal_mremap_move_dontunmap_anyaddr(true);
1963         test_seal_madvise_nodiscard(false);
1964         test_seal_madvise_nodiscard(true);
1965         test_seal_discard_ro_anon(false);
1966         test_seal_discard_ro_anon(true);
1967         test_seal_discard_across_vmas(false);
1968         test_seal_discard_across_vmas(true);
1969         test_seal_discard_ro_anon_on_rw(false);
1970         test_seal_discard_ro_anon_on_rw(true);
1971         test_seal_discard_ro_anon_on_shared(false);
1972         test_seal_discard_ro_anon_on_shared(true);
1973         test_seal_discard_ro_anon_on_filebacked(false);
1974         test_seal_discard_ro_anon_on_filebacked(true);
1975         test_seal_mmap_overwrite_prot(false);
1976         test_seal_mmap_overwrite_prot(true);
1977         test_seal_mmap_expand(false);
1978         test_seal_mmap_expand(true);
1979         test_seal_mmap_shrink(false);
1980         test_seal_mmap_shrink(true);
1981
1982         test_seal_merge_and_split();
1983         test_seal_zero_address();
1984
1985         test_seal_discard_ro_anon_on_pkey(false);
1986         test_seal_discard_ro_anon_on_pkey(true);
1987
1988         ksft_finished();
1989 }
This page took 0.13458 seconds and 4 git commands to generate.