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