Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/vm/mmap_test.c
39507 views
1
/*-
2
* Copyright (c) 2009 Simon L. Nielsen <[email protected]>,
3
* Bjoern A. Zeeb <[email protected]>
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/mman.h>
29
#include <sys/sysctl.h>
30
31
#include <atf-c.h>
32
#include <errno.h>
33
#include <fcntl.h>
34
#include <stdarg.h>
35
#include <stdbool.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
static const struct {
40
void *addr;
41
int ok[2]; /* Depending on security.bsd.map_at_zero {0, !=0}. */
42
} map_at_zero_tests[] = {
43
{ (void *)0, { 0, 1 } }, /* Test sysctl. */
44
{ (void *)1, { 0, 0 } },
45
{ (void *)(PAGE_SIZE - 1), { 0, 0 } },
46
{ (void *)PAGE_SIZE, { 1, 1 } },
47
{ (void *)-1, { 0, 0 } },
48
{ (void *)(-PAGE_SIZE), { 0, 0 } },
49
{ (void *)(-1 - PAGE_SIZE), { 0, 0 } },
50
{ (void *)(-1 - PAGE_SIZE - 1), { 0, 0 } },
51
{ (void *)(0x1000 * PAGE_SIZE), { 1, 1 } },
52
};
53
54
#define MAP_AT_ZERO "security.bsd.map_at_zero"
55
56
#ifdef __LP64__
57
#define ALLOW_WX "kern.elf64.allow_wx"
58
#else
59
#define ALLOW_WX "kern.elf32.allow_wx"
60
#endif
61
62
ATF_TC_WITHOUT_HEAD(mmap__map_at_zero);
63
ATF_TC_BODY(mmap__map_at_zero, tc)
64
{
65
void *p;
66
size_t len;
67
unsigned int i;
68
int map_at_zero;
69
bool allow_wx;
70
int prot_flags;
71
72
len = sizeof(map_at_zero);
73
if (sysctlbyname(MAP_AT_ZERO, &map_at_zero, &len, NULL, 0) == -1) {
74
atf_tc_skip("sysctl for %s failed: %s\n", MAP_AT_ZERO,
75
strerror(errno));
76
return;
77
}
78
79
len = sizeof(allow_wx);
80
if (sysctlbyname(ALLOW_WX, &allow_wx, &len, NULL, 0) == -1) {
81
if (errno == ENOENT) {
82
/* Allow W+X if sysctl isn't present */
83
allow_wx = true;
84
} else {
85
atf_tc_skip("sysctl for %s failed: %s\n", ALLOW_WX,
86
strerror(errno));
87
return;
88
}
89
}
90
91
/* Normalize to 0 or 1 for array access. */
92
map_at_zero = !!map_at_zero;
93
94
for (i = 0; i < nitems(map_at_zero_tests); i++) {
95
prot_flags = PROT_READ | PROT_WRITE;
96
if (allow_wx)
97
prot_flags |= PROT_EXEC;
98
p = mmap((void *)map_at_zero_tests[i].addr, PAGE_SIZE,
99
prot_flags, MAP_ANON | MAP_FIXED, -1, 0);
100
if (p == MAP_FAILED) {
101
ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 0,
102
"mmap(%p, ...) failed", map_at_zero_tests[i].addr);
103
} else {
104
ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 1,
105
"mmap(%p, ...) succeeded: p=%p\n",
106
map_at_zero_tests[i].addr, p);
107
}
108
}
109
}
110
111
static void
112
checked_mmap(int prot, int flags, int fd, int error, const char *msg)
113
{
114
void *p;
115
int pagesize;
116
117
ATF_REQUIRE((pagesize = getpagesize()) > 0);
118
p = mmap(NULL, pagesize, prot, flags, fd, 0);
119
if (p == MAP_FAILED) {
120
if (error == 0)
121
ATF_CHECK_MSG(0, "%s failed with errno %d", msg,
122
errno);
123
else
124
ATF_CHECK_EQ_MSG(error, errno,
125
"%s failed with wrong errno %d (expected %d)", msg,
126
errno, error);
127
} else {
128
ATF_CHECK_MSG(error == 0, "%s succeeded", msg);
129
munmap(p, pagesize);
130
}
131
}
132
133
ATF_TC_WITHOUT_HEAD(mmap__bad_arguments);
134
ATF_TC_BODY(mmap__bad_arguments, tc)
135
{
136
int devstatfd, pagesize, shmfd, zerofd;
137
138
ATF_REQUIRE((pagesize = getpagesize()) > 0);
139
ATF_REQUIRE((devstatfd = open("/dev/devstat", O_RDONLY)) >= 0);
140
ATF_REQUIRE((shmfd = shm_open(SHM_ANON, O_RDWR, 0644)) >= 0);
141
ATF_REQUIRE(ftruncate(shmfd, pagesize) == 0);
142
ATF_REQUIRE((zerofd = open("/dev/zero", O_RDONLY)) >= 0);
143
144
/* These should work. */
145
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON, -1, 0,
146
"simple MAP_ANON");
147
checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0,
148
"simple shm fd shared");
149
checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, shmfd, 0,
150
"simple shm fd private");
151
checked_mmap(PROT_READ, MAP_SHARED, zerofd, 0,
152
"simple /dev/zero shared");
153
checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, zerofd, 0,
154
"simple /dev/zero private");
155
checked_mmap(PROT_READ, MAP_SHARED, devstatfd, 0,
156
"simple /dev/devstat shared");
157
158
/* Extra PROT flags. */
159
checked_mmap(PROT_READ | PROT_WRITE | 0x100000, MAP_ANON, -1, EINVAL,
160
"MAP_ANON with extra PROT flags");
161
checked_mmap(0xffff, MAP_SHARED, shmfd, EINVAL,
162
"shm fd with garbage PROT");
163
164
/* Undefined flag. */
165
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_RESERVED0080, -1,
166
EINVAL, "Undefined flag");
167
168
/* Both MAP_SHARED and MAP_PRIVATE */
169
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE |
170
MAP_SHARED, -1, EINVAL, "MAP_ANON with both SHARED and PRIVATE");
171
checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_SHARED, shmfd,
172
EINVAL, "shm fd with both SHARED and PRIVATE");
173
174
/* At least one of MAP_SHARED or MAP_PRIVATE without ANON */
175
checked_mmap(PROT_READ | PROT_WRITE, 0, shmfd, EINVAL,
176
"shm fd without sharing flag");
177
178
/* MAP_ANON with either sharing flag (impacts fork). */
179
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0,
180
"shared MAP_ANON");
181
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0,
182
"private MAP_ANON");
183
184
/* MAP_ANON should require an fd of -1. */
185
checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, EINVAL,
186
"MAP_ANON with fd != -1");
187
188
/* Writable MAP_SHARED should fail on read-only descriptors. */
189
checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, zerofd, EACCES,
190
"MAP_SHARED of read-only /dev/zero");
191
192
/*
193
* Character devices other than /dev/zero do not support private
194
* mappings.
195
*/
196
checked_mmap(PROT_READ, MAP_PRIVATE, devstatfd, EINVAL,
197
"MAP_PRIVATE of /dev/devstat");
198
199
close(devstatfd);
200
close(shmfd);
201
close(zerofd);
202
}
203
204
ATF_TC_WITHOUT_HEAD(mmap__dev_zero_private);
205
ATF_TC_BODY(mmap__dev_zero_private, tc)
206
{
207
char *p1, *p2, *p3;
208
int fd, i, pagesize;
209
210
ATF_REQUIRE((pagesize = getpagesize()) > 0);
211
ATF_REQUIRE((fd = open("/dev/zero", O_RDONLY)) >= 0);
212
213
p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
214
ATF_REQUIRE(p1 != MAP_FAILED);
215
216
p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
217
ATF_REQUIRE(p2 != MAP_FAILED);
218
219
for (i = 0; i < pagesize; i++)
220
ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%d] is %x", i, p1[i]);
221
222
ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0);
223
224
p1[0] = 1;
225
226
ATF_REQUIRE(p2[0] == 0);
227
228
p2[0] = 2;
229
230
ATF_REQUIRE(p1[0] == 1);
231
232
p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
233
ATF_REQUIRE(p3 != MAP_FAILED);
234
235
ATF_REQUIRE(p3[0] == 0);
236
237
munmap(p1, pagesize);
238
munmap(p2, pagesize);
239
munmap(p3, pagesize);
240
close(fd);
241
}
242
243
ATF_TC_WITHOUT_HEAD(mmap__dev_zero_shared);
244
ATF_TC_BODY(mmap__dev_zero_shared, tc)
245
{
246
char *p1, *p2, *p3;
247
int fd, i, pagesize;
248
249
ATF_REQUIRE((pagesize = getpagesize()) > 0);
250
ATF_REQUIRE((fd = open("/dev/zero", O_RDWR)) >= 0);
251
252
p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
253
ATF_REQUIRE(p1 != MAP_FAILED);
254
255
p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
256
ATF_REQUIRE(p2 != MAP_FAILED);
257
258
for (i = 0; i < pagesize; i++)
259
ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%d] is %x", i, p1[i]);
260
261
ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0);
262
263
p1[0] = 1;
264
265
ATF_REQUIRE(p2[0] == 0);
266
267
p2[0] = 2;
268
269
ATF_REQUIRE(p1[0] == 1);
270
271
p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
272
0);
273
ATF_REQUIRE(p3 != MAP_FAILED);
274
275
ATF_REQUIRE(p3[0] == 0);
276
277
munmap(p1, pagesize);
278
munmap(p2, pagesize);
279
munmap(p3, pagesize);
280
close(fd);
281
}
282
283
ATF_TC_WITHOUT_HEAD(mmap__write_only);
284
ATF_TC_BODY(mmap__write_only, tc)
285
{
286
void *p;
287
int pagesize;
288
289
ATF_REQUIRE((pagesize = getpagesize()) > 0);
290
p = mmap(NULL, pagesize, PROT_WRITE, MAP_ANON, -1, 0);
291
ATF_REQUIRE(p != MAP_FAILED);
292
293
*(volatile uint32_t *)p = 0x12345678;
294
295
munmap(p, pagesize);
296
}
297
298
ATF_TC_WITHOUT_HEAD(mmap__maxprot_basic);
299
ATF_TC_BODY(mmap__maxprot_basic, tc)
300
{
301
void *p;
302
int error, pagesize;
303
304
ATF_REQUIRE((pagesize = getpagesize()) > 0);
305
306
p = mmap(NULL, pagesize, PROT_READ | PROT_MAX(PROT_READ),
307
MAP_ANON, -1, 0);
308
ATF_REQUIRE(p != MAP_FAILED);
309
310
error = mprotect(p, pagesize, PROT_WRITE);
311
ATF_REQUIRE_ERRNO(EACCES, error == -1);
312
error = mprotect(p, pagesize, PROT_READ | PROT_WRITE);
313
ATF_REQUIRE_ERRNO(EACCES, error == -1);
314
error = mprotect(p, pagesize, PROT_READ | PROT_EXEC);
315
ATF_REQUIRE_ERRNO(EACCES, error == -1);
316
317
ATF_REQUIRE(munmap(p, pagesize) == 0);
318
}
319
320
/* Make sure that PROT_MAX applies as expected to mappings of shm objects */
321
ATF_TC_WITHOUT_HEAD(mmap__maxprot_shm);
322
ATF_TC_BODY(mmap__maxprot_shm, tc)
323
{
324
void *p;
325
int error, fd, pagesize;
326
327
ATF_REQUIRE((pagesize = getpagesize()) > 0);
328
329
fd = shm_open(SHM_ANON, O_RDWR, 0644);
330
ATF_REQUIRE(fd >= 0);
331
332
error = ftruncate(fd, pagesize);
333
ATF_REQUIRE(error == 0);
334
335
p = mmap(NULL, pagesize, PROT_READ | PROT_MAX(PROT_READ),
336
MAP_PRIVATE, fd, 0);
337
ATF_REQUIRE(p != MAP_FAILED);
338
339
error = mprotect(p, pagesize, PROT_WRITE);
340
ATF_REQUIRE_ERRNO(EACCES, error == -1);
341
error = mprotect(p, pagesize, PROT_READ | PROT_WRITE);
342
ATF_REQUIRE_ERRNO(EACCES, error == -1);
343
error = mprotect(p, pagesize, PROT_READ | PROT_EXEC);
344
ATF_REQUIRE_ERRNO(EACCES, error == -1);
345
346
ATF_REQUIRE(munmap(p, pagesize) == 0);
347
348
/* Again, this time with a shared mapping. */
349
p = mmap(NULL, pagesize, PROT_READ | PROT_MAX(PROT_READ),
350
MAP_SHARED, fd, 0);
351
ATF_REQUIRE(p != MAP_FAILED);
352
353
error = mprotect(p, pagesize, PROT_WRITE);
354
ATF_REQUIRE_ERRNO(EACCES, error == -1);
355
error = mprotect(p, pagesize, PROT_READ | PROT_WRITE);
356
ATF_REQUIRE_ERRNO(EACCES, error == -1);
357
error = mprotect(p, pagesize, PROT_READ | PROT_EXEC);
358
ATF_REQUIRE_ERRNO(EACCES, error == -1);
359
360
ATF_REQUIRE(munmap(p, pagesize) == 0);
361
362
ATF_REQUIRE(close(fd) == 0);
363
}
364
365
ATF_TP_ADD_TCS(tp)
366
{
367
ATF_TP_ADD_TC(tp, mmap__map_at_zero);
368
ATF_TP_ADD_TC(tp, mmap__bad_arguments);
369
ATF_TP_ADD_TC(tp, mmap__dev_zero_private);
370
ATF_TP_ADD_TC(tp, mmap__dev_zero_shared);
371
ATF_TP_ADD_TC(tp, mmap__write_only);
372
ATF_TP_ADD_TC(tp, mmap__maxprot_basic);
373
ATF_TP_ADD_TC(tp, mmap__maxprot_shm);
374
375
return (atf_no_error());
376
}
377
378