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