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