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