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_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 71 72 addr = base_addr + page_size; 73 size = 3 * page_size; 74 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 75 if (p == MAP_FAILED) { 76 dump_maps(); 77 ksft_exit_fail_msg("Error: first mmap() failed unexpectedly\n"); 78 } 79 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 80 81 /* 82 * Exact same mapping again: 83 * base | free | new 84 * +1 | mapped | new 85 * +2 | mapped | new 86 * +3 | mapped | new 87 * +4 | free | new 88 */ 89 addr = base_addr; 90 size = 5 * page_size; 91 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 92 if (p != MAP_FAILED) { 93 dump_maps(); 94 ksft_exit_fail_msg("Error:1: mmap() succeeded when it shouldn't have\n"); 95 } 96 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 97 98 /* 99 * Second mapping contained within first: 100 * 101 * base | free | 102 * +1 | mapped | 103 * +2 | mapped | new 104 * +3 | mapped | 105 * +4 | free | 106 */ 107 addr = base_addr + (2 * page_size); 108 size = page_size; 109 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 110 if (p != MAP_FAILED) { 111 dump_maps(); 112 ksft_exit_fail_msg("Error:2: mmap() succeeded when it shouldn't have\n"); 113 } 114 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 115 116 /* 117 * Overlap end of existing mapping: 118 * base | free | 119 * +1 | mapped | 120 * +2 | mapped | 121 * +3 | mapped | new 122 * +4 | free | new 123 */ 124 addr = base_addr + (3 * page_size); 125 size = 2 * page_size; 126 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 127 if (p != MAP_FAILED) { 128 dump_maps(); 129 ksft_exit_fail_msg("Error:3: mmap() succeeded when it shouldn't have\n"); 130 } 131 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 132 133 /* 134 * Overlap start of existing mapping: 135 * base | free | new 136 * +1 | mapped | new 137 * +2 | mapped | 138 * +3 | mapped | 139 * +4 | free | 140 */ 141 addr = base_addr; 142 size = 2 * page_size; 143 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 144 if (p != MAP_FAILED) { 145 dump_maps(); 146 ksft_exit_fail_msg("Error:4: mmap() succeeded when it shouldn't have\n"); 147 } 148 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 149 150 /* 151 * Adjacent to start of existing mapping: 152 * base | free | new 153 * +1 | mapped | 154 * +2 | mapped | 155 * +3 | mapped | 156 * +4 | free | 157 */ 158 addr = base_addr; 159 size = page_size; 160 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 161 if (p == MAP_FAILED) { 162 dump_maps(); 163 ksft_exit_fail_msg("Error:5: mmap() failed when it shouldn't have\n"); 164 } 165 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 166 167 /* 168 * Adjacent to end of existing mapping: 169 * base | free | 170 * +1 | mapped | 171 * +2 | mapped | 172 * +3 | mapped | 173 * +4 | free | new 174 */ 175 addr = base_addr + (4 * page_size); 176 size = page_size; 177 p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); 178 if (p == MAP_FAILED) { 179 dump_maps(); 180 ksft_exit_fail_msg("Error:6: mmap() failed when it shouldn't have\n"); 181 } 182 ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); 183 184 addr = base_addr; 185 size = 5 * page_size; 186 if (munmap((void *)addr, size) != 0) { 187 dump_maps(); 188 ksft_exit_fail_msg("Error: munmap failed!?\n"); 189 } 190 ksft_test_result_pass("Base Address unmap() successful\n"); 191 192 ksft_finished(); 193 } 194