1 /* 2 * Copyright 2023, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <fcntl.h> 10 #include <sys/mman.h> 11 #include <unistd.h> 12 #include <OS.h> 13 14 15 int gTestFd = -1; 16 17 18 int 19 map_negative_offset_test() 20 { 21 // should fail (negative offset) 22 void* ptr = mmap(NULL, B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, -4096); 23 if (ptr != MAP_FAILED) { 24 printf("map-negative-offset unexpectedly succeeded!\n"); 25 return -1; 26 } 27 return 0; 28 } 29 30 31 int 32 map_cut_compare_test() 33 { 34 uint8* ptr1 = (uint8*)mmap(NULL, 16 * B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, 0); 35 uint8 chunk[128]; 36 memcpy(chunk, &ptr1[3 * B_PAGE_SIZE], sizeof(chunk)); 37 38 // now cut the area 39 uint8* ptr2 = (uint8*)mmap(&ptr1[B_PAGE_SIZE], B_PAGE_SIZE, 40 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); 41 42 // validate that the area after the cut still has the expected data 43 int status = memcmp(&ptr1[3 * B_PAGE_SIZE], chunk, sizeof(chunk)); 44 if (status != 0) { 45 printf("map-cut-compare test failed!\n"); 46 return status; 47 } 48 return 0; 49 } 50 51 52 int 53 map_protect_cut_test() 54 { 55 uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, 56 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 57 58 // make the tail accessible 59 mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE); 60 61 // store any value 62 ptr[B_PAGE_SIZE * 3] = 'a'; 63 64 // cut the area in the middle, before the accessible tail 65 mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_READ | PROT_WRITE, 66 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 67 68 // validate that this does not crash 69 if (ptr[B_PAGE_SIZE * 3] != 'a') { 70 printf("map-protect-cut test failed!\n"); 71 return -1; 72 } 73 return 0; 74 } 75 76 77 int 78 map_cut_fork_test() 79 { 80 char name[24]; 81 sprintf(name, "/shm-mmap-cut-fork-test-%d", getpid()); 82 name[sizeof(name) - 1] = '\0'; 83 shm_unlink(name); 84 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); 85 shm_unlink(name); 86 87 if (fd < 0) { 88 printf("failed to create temporary file!\n"); 89 return fd; 90 } 91 92 ftruncate(fd, B_PAGE_SIZE * 4); 93 94 uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, MAP_PRIVATE, 95 fd, 0); 96 97 // make the head accessible and also force the kernel to allocate the 98 // page_protections array 99 mprotect(ptr, B_PAGE_SIZE, PROT_READ | PROT_WRITE); 100 101 // store any value 102 ptr[0] = 'a'; 103 104 // cut the area in the middle 105 mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_NONE, 106 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 107 108 // validate that the fork does not crash the kernel 109 int pid = fork(); 110 111 if (pid == 0) 112 { 113 exit(0); 114 } 115 else if (pid < 0) 116 { 117 printf("failed to fork the test process!\n"); 118 return pid; 119 } 120 121 int status; 122 waitpid(pid, &status, 0); 123 124 // validate that this does not crash 125 if (ptr[0] != 'a') { 126 printf("map-cut-fork test failed!\n"); 127 return -1; 128 } 129 return 0; 130 } 131 132 133 int 134 main() 135 { 136 gTestFd = open("/boot/system/lib/libroot.so", O_CLOEXEC | O_RDONLY); 137 if (gTestFd < 0) 138 return -1; 139 140 int status; 141 142 if ((status = map_negative_offset_test()) != 0) 143 return status; 144 145 if ((status = map_cut_compare_test()) != 0) 146 return status; 147 148 if ((status = map_protect_cut_test()) != 0) 149 return status; 150 151 if ((status = map_cut_fork_test()) != 0) 152 return status; 153 154 return 0; 155 } 156