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