xref: /linux/tools/testing/selftests/mm/map_fixed_noreplace.c (revision 1f20a5769446a1acae67ac9e63d07a594829a789)
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 #include "../kselftest.h"
16 
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 
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 
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_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
71 
72 	addr = base_addr + page_size;
73 	size = 3 * page_size;
74 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
75 	if (p == MAP_FAILED) {
76 		dump_maps();
77 		ksft_exit_fail_msg("Error: first mmap() failed unexpectedly\n");
78 	}
79 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
80 
81 	/*
82 	 * Exact same mapping again:
83 	 *   base |  free  | new
84 	 *     +1 | mapped | new
85 	 *     +2 | mapped | new
86 	 *     +3 | mapped | new
87 	 *     +4 |  free  | new
88 	 */
89 	addr = base_addr;
90 	size = 5 * page_size;
91 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
92 	if (p != MAP_FAILED) {
93 		dump_maps();
94 		ksft_exit_fail_msg("Error:1: mmap() succeeded when it shouldn't have\n");
95 	}
96 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
97 
98 	/*
99 	 * Second mapping contained within first:
100 	 *
101 	 *   base |  free  |
102 	 *     +1 | mapped |
103 	 *     +2 | mapped | new
104 	 *     +3 | mapped |
105 	 *     +4 |  free  |
106 	 */
107 	addr = base_addr + (2 * page_size);
108 	size = page_size;
109 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
110 	if (p != MAP_FAILED) {
111 		dump_maps();
112 		ksft_exit_fail_msg("Error:2: mmap() succeeded when it shouldn't have\n");
113 	}
114 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
115 
116 	/*
117 	 * Overlap end of existing mapping:
118 	 *   base |  free  |
119 	 *     +1 | mapped |
120 	 *     +2 | mapped |
121 	 *     +3 | mapped | new
122 	 *     +4 |  free  | new
123 	 */
124 	addr = base_addr + (3 * page_size);
125 	size = 2 * page_size;
126 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
127 	if (p != MAP_FAILED) {
128 		dump_maps();
129 		ksft_exit_fail_msg("Error:3: mmap() succeeded when it shouldn't have\n");
130 	}
131 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
132 
133 	/*
134 	 * Overlap start of existing mapping:
135 	 *   base |  free  | new
136 	 *     +1 | mapped | new
137 	 *     +2 | mapped |
138 	 *     +3 | mapped |
139 	 *     +4 |  free  |
140 	 */
141 	addr = base_addr;
142 	size = 2 * page_size;
143 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
144 	if (p != MAP_FAILED) {
145 		dump_maps();
146 		ksft_exit_fail_msg("Error:4: mmap() succeeded when it shouldn't have\n");
147 	}
148 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
149 
150 	/*
151 	 * Adjacent to start of existing mapping:
152 	 *   base |  free  | new
153 	 *     +1 | mapped |
154 	 *     +2 | mapped |
155 	 *     +3 | mapped |
156 	 *     +4 |  free  |
157 	 */
158 	addr = base_addr;
159 	size = page_size;
160 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
161 	if (p == MAP_FAILED) {
162 		dump_maps();
163 		ksft_exit_fail_msg("Error:5: mmap() failed when it shouldn't have\n");
164 	}
165 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
166 
167 	/*
168 	 * Adjacent to end of existing mapping:
169 	 *   base |  free  |
170 	 *     +1 | mapped |
171 	 *     +2 | mapped |
172 	 *     +3 | mapped |
173 	 *     +4 |  free  |  new
174 	 */
175 	addr = base_addr + (4 * page_size);
176 	size = page_size;
177 	p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
178 	if (p == MAP_FAILED) {
179 		dump_maps();
180 		ksft_exit_fail_msg("Error:6: mmap() failed when it shouldn't have\n");
181 	}
182 	ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
183 
184 	addr = base_addr;
185 	size = 5 * page_size;
186 	if (munmap((void *)addr, size) != 0) {
187 		dump_maps();
188 		ksft_exit_fail_msg("Error: munmap failed!?\n");
189 	}
190 	ksft_test_result_pass("Base Address unmap() successful\n");
191 
192 	ksft_finished();
193 }
194