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 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 
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 
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