xref: /linux/tools/testing/selftests/mm/map_fixed_noreplace.c (revision d6053666ef2b6631ef8f265f49ff2cc0f4d45c50)
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 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 
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 
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