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