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
17static 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
25static 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(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(msg: "Error: munmap failed\n");
37
38 return (unsigned long)addr;
39}
40
41int 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(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(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(msg: "Error: munmap failed!?\n");
69 }
70 ksft_test_result_pass(msg: "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(msg: "Error: first mmap() failed unexpectedly\n");
78 }
79 ksft_test_result_pass(msg: "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(msg: "Error:1: mmap() succeeded when it shouldn't have\n");
95 }
96 ksft_test_result_pass(msg: "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(msg: "Error:2: mmap() succeeded when it shouldn't have\n");
113 }
114 ksft_test_result_pass(msg: "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(msg: "Error:3: mmap() succeeded when it shouldn't have\n");
130 }
131 ksft_test_result_pass(msg: "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(msg: "Error:4: mmap() succeeded when it shouldn't have\n");
147 }
148 ksft_test_result_pass(msg: "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(msg: "Error:5: mmap() failed when it shouldn't have\n");
164 }
165 ksft_test_result_pass(msg: "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(msg: "Error:6: mmap() failed when it shouldn't have\n");
181 }
182 ksft_test_result_pass(msg: "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(msg: "Error: munmap failed!?\n");
189 }
190 ksft_test_result_pass(msg: "Base Address unmap() successful\n");
191
192 ksft_finished();
193}
194

source code of linux/tools/testing/selftests/mm/map_fixed_noreplace.c