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 
dump_maps(void)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 
main(void)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 }
207