diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2018-10-26 18:10:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-26 19:38:15 -0400 |
commit | 91cbacc34512e37c9bb89125ca4b224ca6459245 (patch) | |
tree | 50cc12ba385ea0b15a2f73dcbba93d50183eee51 | |
parent | 7eef5f97c1f94c7b72520b42d372037e97a81b95 (diff) |
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>
-rw-r--r-- | tools/testing/selftests/vm/.gitignore | 1 | ||||
-rw-r--r-- | tools/testing/selftests/vm/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/vm/map_fixed_noreplace.c | 206 |
3 files changed, 208 insertions, 0 deletions
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore index af5ff83f6d7f..31b3c98b6d34 100644 --- a/tools/testing/selftests/vm/.gitignore +++ b/tools/testing/selftests/vm/.gitignore | |||
@@ -13,3 +13,4 @@ mlock-random-test | |||
13 | virtual_address_range | 13 | virtual_address_range |
14 | gup_benchmark | 14 | gup_benchmark |
15 | va_128TBswitch | 15 | va_128TBswitch |
16 | map_fixed_noreplace | ||
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index e94b7b14bcb2..6e67e726e5a5 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -12,6 +12,7 @@ TEST_GEN_FILES += gup_benchmark | |||
12 | TEST_GEN_FILES += hugepage-mmap | 12 | TEST_GEN_FILES += hugepage-mmap |
13 | TEST_GEN_FILES += hugepage-shm | 13 | TEST_GEN_FILES += hugepage-shm |
14 | TEST_GEN_FILES += map_hugetlb | 14 | TEST_GEN_FILES += map_hugetlb |
15 | TEST_GEN_FILES += map_fixed_noreplace | ||
15 | TEST_GEN_FILES += map_populate | 16 | TEST_GEN_FILES += map_populate |
16 | TEST_GEN_FILES += mlock-random-test | 17 | TEST_GEN_FILES += mlock-random-test |
17 | TEST_GEN_FILES += mlock2-tests | 18 | TEST_GEN_FILES += mlock2-tests |
diff --git a/tools/testing/selftests/vm/map_fixed_noreplace.c b/tools/testing/selftests/vm/map_fixed_noreplace.c new file mode 100644 index 000000000000..d91bde511268 --- /dev/null +++ b/tools/testing/selftests/vm/map_fixed_noreplace.c | |||
@@ -0,0 +1,206 @@ | |||
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 | } | ||