Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools/testing/selftests/vm/map_fixed_noreplace.c: add test for MAP_FIXED_NOREPLACE

Add a test for MAP_FIXED_NOREPLACE, based on some code originally by Jann
Horn. This would have caught the overlap bug reported by Daniel Micay.

I originally suggested to Michal that we create MAP_FIXED_NOREPLACE, but
instead of writing a selftest I spent my time bike-shedding whether it
should be called MAP_FIXED_SAFE/NOCLOBBER/WEAK/NEW .. mea culpa.

Link: http://lkml.kernel.org/r/20181013133929.28653-1-mpe@ellerman.id.au
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Khalid Aziz <khalid.aziz@oracle.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Jann Horn <jannh@google.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com>
Cc: Joel Stanley <joel@jms.id.au>
Cc: Jason Evans <jasone@google.com>
Cc: David Goldblatt <davidtgoldblatt@gmail.com>
Cc: Daniel Micay <danielmicay@gmail.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Ellerman and committed by
Linus Torvalds
91cbacc3 7eef5f97

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