1990 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#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 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 93static 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 102static 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 112static 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 119static 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#endif131 return pkey_reg;132}133 134static 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#endif144}145 146static unsigned long pkey_bit_position(int pkey)147{148 return pkey * PKEY_BITS_PER_PKEY;149}150 151static 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 162static 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 170static 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 178static 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 187static int clean_single_address(void *ptr, int size)188{189 int ret;190 ret = munmap(ptr, size);191 return ret;192}193 194static int seal_single_address(void *ptr, int size)195{196 int ret;197 ret = sys_mseal(ptr, size);198 return ret;199}200 201bool 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 218bool 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#endif226 return false;227}228 229static 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 245static 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 273static 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 305static 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 334static 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 365static 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 390static 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 415static 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 450static 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 474static 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 500static 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 520static 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 else539 FAIL_TEST_IF_FALSE(!ret);540 541 REPORT_TEST_PASS();542}543 544static 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 else564 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 574static 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 else599 FAIL_TEST_IF_FALSE(!ret);600 601 REPORT_TEST_PASS();602}603 604static 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 else624 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 633static 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 else652 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 661static 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 else684 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 else691 FAIL_TEST_IF_FALSE(!ret);692 693 REPORT_TEST_PASS();694}695 696static 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 else725 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 else733 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 743static 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 else764 FAIL_TEST_IF_FALSE(!ret);765 766 REPORT_TEST_PASS();767}768 769static 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 else794 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 805static 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 848static 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 else873 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 else880 FAIL_TEST_IF_FALSE(!ret);881 882 REPORT_TEST_PASS();883}884 885static 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 else910 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 919static 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 else939 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 VMAs947 * seal the whole range948 * munmap will fail on both949 */950static 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 else973 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 else979 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 */991static 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 1022static 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 else1042 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 1052static 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 1092static 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 else1117 FAIL_TEST_IF_FALSE(!ret);1118 1119 REPORT_TEST_PASS();1120}1121 1122static 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 1166static 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 1195static 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 1227static 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 1260static 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 } else1283 FAIL_TEST_IF_FALSE(ret2 == ptr);1284 1285 REPORT_TEST_PASS();1286}1287 1288static 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 } else1314 FAIL_TEST_IF_FALSE(ret2 == ptr);1315 1316 REPORT_TEST_PASS();1317}1318 1319static 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 } else1342 FAIL_TEST_IF_FALSE(ret2 == ptr);1343 1344 REPORT_TEST_PASS();1345}1346 1347static 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 } else1373 FAIL_TEST_IF_FALSE(ret2 == newAddr);1374 1375 REPORT_TEST_PASS();1376}1377 1378static 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 } else1404 FAIL_TEST_IF_FALSE(ret2 == newAddr);1405 1406 REPORT_TEST_PASS();1407}1408 1409static 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 } else1434 FAIL_TEST_IF_FALSE(ret2 == newAddr);1435 1436 REPORT_TEST_PASS();1437}1438 1439static 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 address1457 */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 1470static 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 1499static 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 1540static 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 1632static 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 else1656 FAIL_TEST_IF_FALSE(!ret);1657 1658 REPORT_TEST_PASS();1659}1660 1661static 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 else1696 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 else1703 FAIL_TEST_IF_FALSE(!ret);1704 1705 REPORT_TEST_PASS();1706}1707 1708static 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 else1739 FAIL_TEST_IF_FALSE(!ret);1740 close(fd);1741 1742 REPORT_TEST_PASS();1743}1744 1745static 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 else1769 FAIL_TEST_IF_FALSE(!ret);1770 1771 REPORT_TEST_PASS();1772}1773 1774static 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 else1793 FAIL_TEST_IF_FALSE(!ret);1794 1795 ret = sys_munmap(ptr, size);1796 if (seal)1797 FAIL_TEST_IF_FALSE(ret < 0);1798 else1799 FAIL_TEST_IF_FALSE(!ret);1800 1801 REPORT_TEST_PASS();1802}1803 1804static 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 else1823 FAIL_TEST_IF_FALSE(!ret);1824 1825 ret = sys_munmap(ptr, size);1826 if (seal)1827 FAIL_TEST_IF_FALSE(ret < 0);1828 else1829 FAIL_TEST_IF_FALSE(!ret);1830 1831 REPORT_TEST_PASS();1832}1833 1834 1835static 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 page1852 * contents (and thus should work for msealed VMAs). RANDOM also happens to1853 * 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 else1862 FAIL_TEST_IF_FALSE(!ret);1863 1864 REPORT_TEST_PASS();1865}1866 1867int 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}1990