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