1 // SPDX-License-Identifier: GPL-2.0 2 3 /* 4 * Test that MAP_FIXED_NOREPLACE works. 5 * 6 * Copyright 2018, Jann Horn <jannh@google.com> 7 * Copyright 2018, Michael Ellerman, IBM Corporation. 8 */ 9 10 #include <sys/mman.h> 11 #include <errno.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <unistd.h> 15 16 #ifndef MAP_FIXED_NOREPLACE 17 #define MAP_FIXED_NOREPLACE 0x100000 18 #endif 19 20 static void dump_maps(void) 21 { 22 char cmd[32]; 23 24 snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); 25 system(cmd); 26 } 27 28 static unsigned long find_base_addr(unsigned long size) 29 { 30 void *addr; 31 unsigned long flags; 32 33 flags = MAP_PRIVATE | MAP_ANONYMOUS; 34 addr = mmap(NULL, size, PROT_NONE, flags, -1, 0); 35 if (addr == MAP_FAILED) { 36 printf("Error: couldn't map the space we need for the test\n"); 37 return 0; 38 } 39 40 if (munmap(addr, size) != 0) { 41 printf("Error: couldn't map the space we need for the test\n"); 42 return 0; 43 } 44 return (unsigned long)addr; 45 } 46 47 int main(void) 48 { 49 unsigned long base_addr; 50 unsigned long flags, addr, size, page_size; 51 char *p; 52 53 page_size = sysconf(_SC_PAGE_SIZE); 54 55 //let's find a base addr that is free before we start the tests 56 size = 5 * page_size; 57 base_addr = find_base_addr(size); 58 if (!base_addr) { 59 printf("Error: couldn't map the space we need for the test\n"); 60 return 1; 61 } 62 63 flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE; 64 65 // Check we can map all the areas we need below 66 errno = 0; 67 addr = base_addr; 68 size = 5 * page_size; 69 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 70 71 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 72 73 if (p == MAP_FAILED) { 74 dump_maps(); 75 printf("Error: couldn't map the space we need for the test\n"); 76 return 1; 77 } 78 79 errno = 0; 80 if (munmap((void *)addr, 5 * page_size) != 0) { 81 dump_maps(); 82 printf("Error: munmap failed!?\n"); 83 return 1; 84 } 85 printf("unmap() successful\n"); 86 87 errno = 0; 88 addr = base_addr + page_size; 89 size = 3 * page_size; 90 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 91 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 92 93 if (p == MAP_FAILED) { 94 dump_maps(); 95 printf("Error: first mmap() failed unexpectedly\n"); 96 return 1; 97 } 98 99 /* 100 * Exact same mapping again: 101 * base | free | new 102 * +1 | mapped | new 103 * +2 | mapped | new 104 * +3 | mapped | new 105 * +4 | free | new 106 */ 107 errno = 0; 108 addr = base_addr; 109 size = 5 * page_size; 110 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 111 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 112 113 if (p != MAP_FAILED) { 114 dump_maps(); 115 printf("Error:1: mmap() succeeded when it shouldn't have\n"); 116 return 1; 117 } 118 119 /* 120 * Second mapping contained within first: 121 * 122 * base | free | 123 * +1 | mapped | 124 * +2 | mapped | new 125 * +3 | mapped | 126 * +4 | free | 127 */ 128 errno = 0; 129 addr = base_addr + (2 * page_size); 130 size = page_size; 131 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 132 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 133 134 if (p != MAP_FAILED) { 135 dump_maps(); 136 printf("Error:2: mmap() succeeded when it shouldn't have\n"); 137 return 1; 138 } 139 140 /* 141 * Overlap end of existing mapping: 142 * base | free | 143 * +1 | mapped | 144 * +2 | mapped | 145 * +3 | mapped | new 146 * +4 | free | new 147 */ 148 errno = 0; 149 addr = base_addr + (3 * page_size); 150 size = 2 * page_size; 151 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 152 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 153 154 if (p != MAP_FAILED) { 155 dump_maps(); 156 printf("Error:3: mmap() succeeded when it shouldn't have\n"); 157 return 1; 158 } 159 160 /* 161 * Overlap start of existing mapping: 162 * base | free | new 163 * +1 | mapped | new 164 * +2 | mapped | 165 * +3 | mapped | 166 * +4 | free | 167 */ 168 errno = 0; 169 addr = base_addr; 170 size = 2 * page_size; 171 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 172 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 173 174 if (p != MAP_FAILED) { 175 dump_maps(); 176 printf("Error:4: mmap() succeeded when it shouldn't have\n"); 177 return 1; 178 } 179 180 /* 181 * Adjacent to start of existing mapping: 182 * base | free | new 183 * +1 | mapped | 184 * +2 | mapped | 185 * +3 | mapped | 186 * +4 | free | 187 */ 188 errno = 0; 189 addr = base_addr; 190 size = page_size; 191 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 192 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 193 194 if (p == MAP_FAILED) { 195 dump_maps(); 196 printf("Error:5: mmap() failed when it shouldn't have\n"); 197 return 1; 198 } 199 200 /* 201 * Adjacent to end of existing mapping: 202 * base | free | 203 * +1 | mapped | 204 * +2 | mapped | 205 * +3 | mapped | 206 * +4 | free | new 207 */ 208 errno = 0; 209 addr = base_addr + (4 * page_size); 210 size = page_size; 211 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 212 printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 213 214 if (p == MAP_FAILED) { 215 dump_maps(); 216 printf("Error:6: mmap() failed when it shouldn't have\n"); 217 return 1; 218 } 219 220 addr = base_addr; 221 size = 5 * page_size; 222 if (munmap((void *)addr, size) != 0) { 223 dump_maps(); 224 printf("Error: munmap failed!?\n"); 225 return 1; 226 } 227 printf("unmap() successful\n"); 228 229 printf("OK\n"); 230 return 0; 231 } 232