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