summaryrefslogtreecommitdiff
path: root/src/regress/lib/libc/sys/t_mmap.c
diff options
context:
space:
mode:
authorbluhm <>2019-11-19 19:57:04 +0000
committerbluhm <>2019-11-19 19:57:04 +0000
commit9185f840eda265016178aeb0dcdba964f8f6f3e2 (patch)
treeda100b3712514c566fe948116f7926ad7f725401 /src/regress/lib/libc/sys/t_mmap.c
parent6a6fe688152b422f3d65c970dad56e7d9d28b1ee (diff)
downloadopenbsd-9185f840eda265016178aeb0dcdba964f8f6f3e2.tar.gz
openbsd-9185f840eda265016178aeb0dcdba964f8f6f3e2.tar.bz2
openbsd-9185f840eda265016178aeb0dcdba964f8f6f3e2.zip
Import NetBSD system call regression tests. They were written with
ATF (Automated Testing Framework), so we use a small wrapper to map it to our bsd.regress.mk framework. Only half of the 80 NetBSD tests have been taken, the others need more work to adapt. Of them 34 syscall tests pass. Moritz Buhl ported the tests to OpenBSD.
Diffstat (limited to 'src/regress/lib/libc/sys/t_mmap.c')
-rw-r--r--src/regress/lib/libc/sys/t_mmap.c584
1 files changed, 584 insertions, 0 deletions
diff --git a/src/regress/lib/libc/sys/t_mmap.c b/src/regress/lib/libc/sys/t_mmap.c
new file mode 100644
index 0000000000..6dbfae5bb1
--- /dev/null
+++ b/src/regress/lib/libc/sys/t_mmap.c
@@ -0,0 +1,584 @@
1/* $OpenBSD: t_mmap.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */
2/* $NetBSD: t_mmap.c,v 1.13 2017/05/23 13:04:29 christos Exp $ */
3
4/*-
5 * Copyright (c) 2011 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jukka Ruohonen.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*-
34 * Copyright (c)2004 YAMAMOTO Takashi,
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59#include "macros.h"
60
61#include <sys/cdefs.h>
62__RCSID("$NetBSD: t_mmap.c,v 1.13 2017/05/23 13:04:29 christos Exp $");
63
64#include <sys/param.h>
65#include <sys/disklabel.h>
66#include <sys/mman.h>
67#include <sys/stat.h>
68#include <sys/socket.h>
69#include <sys/sysctl.h>
70#include <sys/wait.h>
71
72#include "atf-c.h"
73#include <errno.h>
74#include <fcntl.h>
75#include <signal.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <unistd.h>
80#include <paths.h>
81
82static long page = 0;
83static char path[] = "mmap";
84static void map_check(void *, int);
85static void map_sighandler(int);
86static void testloan(void *, void *, char, int);
87
88#define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */
89
90static void
91map_check(void *map, int flag)
92{
93
94 if (flag != 0) {
95 ATF_REQUIRE(map == MAP_FAILED);
96 return;
97 }
98
99 ATF_REQUIRE(map != MAP_FAILED);
100 ATF_REQUIRE(munmap(map, page) == 0);
101}
102
103void
104testloan(void *vp, void *vp2, char pat, int docheck)
105{
106 char buf[BUFSIZE];
107 char backup[BUFSIZE];
108 ssize_t nwritten;
109 ssize_t nread;
110 int fds[2];
111 int val;
112
113 val = BUFSIZE;
114
115 if (docheck != 0)
116 (void)memcpy(backup, vp, BUFSIZE);
117
118 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0)
119 atf_tc_fail("socketpair() failed");
120
121 val = BUFSIZE;
122
123 if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
124 atf_tc_fail("setsockopt() failed, SO_RCVBUF");
125
126 val = BUFSIZE;
127
128 if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
129 atf_tc_fail("setsockopt() failed, SO_SNDBUF");
130
131 if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0)
132 atf_tc_fail("fcntl() failed");
133
134 nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page);
135
136 if (nwritten == -1)
137 atf_tc_fail("write() failed");
138
139 /* Break loan. */
140 (void)memset(vp2, pat, BUFSIZE);
141
142 nread = read(fds[1], buf + page, BUFSIZE - page);
143
144 if (nread == -1)
145 atf_tc_fail("read() failed");
146
147 if (nread != nwritten)
148 atf_tc_fail("too short read");
149
150 if (docheck != 0 && memcmp(backup, buf + page, nread) != 0)
151 atf_tc_fail("data mismatch");
152
153 ATF_REQUIRE(close(fds[0]) == 0);
154 ATF_REQUIRE(close(fds[1]) == 0);
155}
156
157static void
158map_sighandler(int signo)
159{
160 _exit(signo);
161}
162
163ATF_TC(mmap_block);
164ATF_TC_HEAD(mmap_block, tc)
165{
166 atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device");
167 atf_tc_set_md_var(tc, "require.user", "root");
168}
169
170ATF_TC_BODY(mmap_block, tc)
171{
172 static const int mib[] = { CTL_HW, HW_DISKNAMES };
173 static const unsigned int miblen = __arraycount(mib);
174 char *map, *dk, *drives, dev[PATH_MAX];
175 size_t len;
176 int fd = -1;
177
178 atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)");
179
180 ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0);
181 drives = malloc(len);
182 ATF_REQUIRE(drives != NULL);
183 ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0);
184 for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) {
185 if (strncmp(dk, "dk", 2) == 0)
186 snprintf(dev, sizeof(dev), _PATH_DEV "%s", dk);
187 else
188 snprintf(dev, sizeof(dev), _PATH_DEV "%s%c", dk,
189 'a' + RAW_PART);
190 fprintf(stderr, "trying: %s\n", dev);
191
192 if ((fd = open(dev, O_RDONLY)) >= 0) {
193 (void)fprintf(stderr, "using %s\n", dev);
194 break;
195 } else
196 (void)fprintf(stderr, "%s: %s\n", dev, strerror(errno));
197 }
198 free(drives);
199
200 if (fd < 0)
201 atf_tc_skip("failed to find suitable block device");
202
203 map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0);
204 ATF_REQUIRE_MSG(map != MAP_FAILED, "mmap: %s", strerror(errno));
205
206 (void)fprintf(stderr, "first byte %x\n", *map);
207 ATF_REQUIRE(close(fd) == 0);
208 (void)fprintf(stderr, "first byte %x\n", *map);
209
210 ATF_REQUIRE(munmap(map, 4096) == 0);
211}
212
213ATF_TC(mmap_err);
214ATF_TC_HEAD(mmap_err, tc)
215{
216 atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)");
217}
218
219ATF_TC_BODY(mmap_err, tc)
220{
221 size_t addr = SIZE_MAX;
222 void *map;
223
224 errno = 0;
225 map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0);
226
227 ATF_REQUIRE(map == MAP_FAILED);
228 ATF_REQUIRE(errno == EBADF);
229
230 errno = 0;
231 map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0);
232
233 ATF_REQUIRE(map == MAP_FAILED);
234 ATF_REQUIRE(errno == EINVAL);
235
236 errno = 0;
237 map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0);
238
239 ATF_REQUIRE(map == MAP_FAILED);
240 ATF_REQUIRE(errno == EINVAL);
241}
242
243ATF_TC_WITH_CLEANUP(mmap_loan);
244ATF_TC_HEAD(mmap_loan, tc)
245{
246 atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)");
247}
248
249ATF_TC_BODY(mmap_loan, tc)
250{
251 char buf[BUFSIZE];
252 char *vp, *vp2;
253 int fd;
254
255 fd = open(path, O_RDWR | O_CREAT, 0600);
256 ATF_REQUIRE(fd >= 0);
257
258 (void)memset(buf, 'x', sizeof(buf));
259 (void)write(fd, buf, sizeof(buf));
260
261 vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
262 MAP_FILE | MAP_PRIVATE, fd, 0);
263
264 ATF_REQUIRE(vp != MAP_FAILED);
265
266 vp2 = vp;
267
268 testloan(vp, vp2, 'A', 0);
269 testloan(vp, vp2, 'B', 1);
270
271 ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
272
273 vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
274 MAP_FILE | MAP_SHARED, fd, 0);
275
276 vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
277 MAP_FILE | MAP_SHARED, fd, 0);
278
279 ATF_REQUIRE(vp != MAP_FAILED);
280 ATF_REQUIRE(vp2 != MAP_FAILED);
281
282 testloan(vp, vp2, 'E', 1);
283
284 ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
285 ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0);
286}
287
288ATF_TC_CLEANUP(mmap_loan, tc)
289{
290 (void)unlink(path);
291}
292
293ATF_TC_WITH_CLEANUP(mmap_prot_1);
294ATF_TC_HEAD(mmap_prot_1, tc)
295{
296 atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1");
297}
298
299ATF_TC_BODY(mmap_prot_1, tc)
300{
301 void *map;
302 int fd;
303
304 /*
305 * Open a file write-only and try to
306 * map it read-only. This should fail.
307 */
308 fd = open(path, O_WRONLY | O_CREAT, 0700);
309
310 if (fd < 0)
311 return;
312
313 ATF_REQUIRE(write(fd, "XXX", 3) == 3);
314
315 map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
316 map_check(map, 1);
317
318 map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
319 map_check(map, 0);
320
321 ATF_REQUIRE(close(fd) == 0);
322}
323
324ATF_TC_CLEANUP(mmap_prot_1, tc)
325{
326 (void)unlink(path);
327}
328
329ATF_TC(mmap_prot_2);
330ATF_TC_HEAD(mmap_prot_2, tc)
331{
332 atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2");
333}
334
335ATF_TC_BODY(mmap_prot_2, tc)
336{
337 char buf[2];
338 void *map;
339 pid_t pid;
340 int sta;
341
342 /*
343 * Make a PROT_NONE mapping and try to access it.
344 * If we catch a SIGSEGV, all works as expected.
345 */
346 map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
347 ATF_REQUIRE(map != MAP_FAILED);
348
349 pid = fork();
350 ATF_REQUIRE(pid >= 0);
351
352 if (pid == 0) {
353 ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
354 ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
355 }
356
357 (void)wait(&sta);
358
359 ATF_REQUIRE(WIFEXITED(sta) != 0);
360 ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
361 ATF_REQUIRE(munmap(map, page) == 0);
362}
363
364ATF_TC_WITH_CLEANUP(mmap_prot_3);
365ATF_TC_HEAD(mmap_prot_3, tc)
366{
367 atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3");
368}
369
370ATF_TC_BODY(mmap_prot_3, tc)
371{
372 char buf[2];
373 int fd, sta;
374 void *map;
375 pid_t pid;
376
377 /*
378 * Open a file, change the permissions
379 * to read-only, and try to map it as
380 * PROT_NONE. This should succeed, but
381 * the access should generate SIGSEGV.
382 */
383 fd = open(path, O_RDWR | O_CREAT, 0700);
384
385 if (fd < 0)
386 return;
387
388 ATF_REQUIRE(write(fd, "XXX", 3) == 3);
389 ATF_REQUIRE(close(fd) == 0);
390 ATF_REQUIRE(chmod(path, 0444) == 0);
391
392 fd = open(path, O_RDONLY);
393 ATF_REQUIRE(fd != -1);
394
395 map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0);
396 ATF_REQUIRE(map != MAP_FAILED);
397
398 pid = fork();
399
400 ATF_REQUIRE(pid >= 0);
401
402 if (pid == 0) {
403 ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
404 ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
405 }
406
407 (void)wait(&sta);
408
409 ATF_REQUIRE(WIFEXITED(sta) != 0);
410 ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
411 ATF_REQUIRE(munmap(map, 3) == 0);
412}
413
414ATF_TC_CLEANUP(mmap_prot_3, tc)
415{
416 (void)unlink(path);
417}
418
419ATF_TC_WITH_CLEANUP(mmap_truncate);
420ATF_TC_HEAD(mmap_truncate, tc)
421{
422 atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)");
423}
424
425ATF_TC_BODY(mmap_truncate, tc)
426{
427 char *map;
428 long i;
429 int fd;
430
431 fd = open(path, O_RDWR | O_CREAT, 0700);
432
433 if (fd < 0)
434 return;
435
436 /*
437 * See that ftruncate(2) works
438 * while the file is mapped.
439 */
440 ATF_REQUIRE(ftruncate(fd, page) == 0);
441
442 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE,
443 fd, 0);
444 ATF_REQUIRE(map != MAP_FAILED);
445
446 for (i = 0; i < page; i++)
447 map[i] = 'x';
448
449 ATF_REQUIRE(ftruncate(fd, 0) == 0);
450 ATF_REQUIRE(ftruncate(fd, page / 8) == 0);
451 ATF_REQUIRE(ftruncate(fd, page / 4) == 0);
452 ATF_REQUIRE(ftruncate(fd, page / 2) == 0);
453 ATF_REQUIRE(ftruncate(fd, page / 12) == 0);
454 ATF_REQUIRE(ftruncate(fd, page / 64) == 0);
455
456 (void)munmap(map, page);
457 ATF_REQUIRE(close(fd) == 0);
458}
459
460ATF_TC_CLEANUP(mmap_truncate, tc)
461{
462 (void)unlink(path);
463}
464
465ATF_TC_WITH_CLEANUP(mmap_truncate_signal);
466ATF_TC_HEAD(mmap_truncate_signal, tc)
467{
468 atf_tc_set_md_var(tc, "descr",
469 "Test mmap(2) ftruncate(2) causing signal");
470}
471
472ATF_TC_BODY(mmap_truncate_signal, tc)
473{
474 char *map;
475 long i;
476 int fd, sta;
477 pid_t pid;
478
479 fd = open(path, O_RDWR | O_CREAT, 0700);
480
481 if (fd < 0)
482 return;
483
484 ATF_REQUIRE(write(fd, "foo\n", 5) == 5);
485
486 map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
487 ATF_REQUIRE(map != MAP_FAILED);
488
489 sta = 0;
490 for (i = 0; i < 5; i++)
491 sta += map[i];
492 ATF_REQUIRE(sta == 334);
493
494 ATF_REQUIRE(ftruncate(fd, 0) == 0);
495 pid = fork();
496 ATF_REQUIRE(pid >= 0);
497
498 if (pid == 0) {
499 ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR);
500 ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
501 sta = 0;
502 for (i = 0; i < page; i++)
503 sta += map[i];
504 /* child never will get this far, but the compiler will
505 not know, so better use the values calculated to
506 prevent the access to be optimized out */
507 ATF_REQUIRE(i == 0);
508 ATF_REQUIRE(sta == 0);
509 (void)munmap(map, page);
510 (void)close(fd);
511 return;
512 }
513
514 (void)wait(&sta);
515
516 ATF_REQUIRE(WIFEXITED(sta) != 0);
517 if (WEXITSTATUS(sta) == SIGSEGV)
518 atf_tc_fail("child process got SIGSEGV instead of SIGBUS");
519 ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS);
520 ATF_REQUIRE(munmap(map, page) == 0);
521 ATF_REQUIRE(close(fd) == 0);
522}
523
524ATF_TC_CLEANUP(mmap_truncate_signal, tc)
525{
526 (void)unlink(path);
527}
528
529ATF_TC(mmap_va0);
530ATF_TC_HEAD(mmap_va0, tc)
531{
532 atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable");
533}
534
535ATF_TC_BODY(mmap_va0, tc)
536{
537 int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE;
538 size_t len = sizeof(int);
539 void *map;
540 int val;
541
542 /*
543 * Make an anonymous fixed mapping at zero address. If the address
544 * is restricted as noted in security(7), the syscall should fail.
545 */
546 if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0)
547 atf_tc_fail("failed to read vm.user_va0_disable");
548
549 map = mmap(NULL, page, PROT_EXEC, flags, -1, 0);
550 map_check(map, val);
551
552 map = mmap(NULL, page, PROT_READ, flags, -1, 0);
553 map_check(map, val);
554
555 map = mmap(NULL, page, PROT_WRITE, flags, -1, 0);
556 map_check(map, val);
557
558 map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0);
559 map_check(map, val);
560
561 map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0);
562 map_check(map, val);
563}
564
565ATF_TP_ADD_TCS(tp)
566{
567 page = sysconf(_SC_PAGESIZE);
568 ATF_REQUIRE(page >= 0);
569
570 ATF_TP_ADD_TC(tp, mmap_block);
571 ATF_TP_ADD_TC(tp, mmap_err);
572 ATF_TP_ADD_TC(tp, mmap_loan);
573 ATF_TP_ADD_TC(tp, mmap_prot_1);
574 ATF_TP_ADD_TC(tp, mmap_prot_2);
575 ATF_TP_ADD_TC(tp, mmap_prot_3);
576 ATF_TP_ADD_TC(tp, mmap_truncate);
577 ATF_TP_ADD_TC(tp, mmap_truncate_signal);
578 /*
579 * Adjusted for OpenBSD, not available
580 * ATF_TP_ADD_TC(tp, mmap_va0);
581 */
582
583 return atf_no_error();
584}