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