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