1 /* $NetBSD: t_mmap.c,v 1.9 2015/02/28 13:57:08 martin Exp $ */
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c)2004 YAMAMOTO Takashi,
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 #include <sys/cdefs.h>
58 __RCSID("$NetBSD: t_mmap.c,v 1.9 2015/02/28 13:57:08 martin Exp $");
60 #include <sys/param.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
75 #include <machine/disklabel.h>
78 static char path
[] = "mmap";
79 static void map_check(void *, int);
80 static void map_sighandler(int);
81 static void testloan(void *, void *, char, int);
83 #define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */
86 map_check(void *map
, int flag
)
90 ATF_REQUIRE(map
== MAP_FAILED
);
94 ATF_REQUIRE(map
!= MAP_FAILED
);
95 ATF_REQUIRE(munmap(map
, page
) == 0);
99 testloan(void *vp
, void *vp2
, char pat
, int docheck
)
102 char backup
[BUFSIZE
];
111 (void)memcpy(backup
, vp
, BUFSIZE
);
113 if (socketpair(AF_LOCAL
, SOCK_STREAM
, PF_UNSPEC
, fds
) != 0)
114 atf_tc_fail("socketpair() failed");
118 if (setsockopt(fds
[1], SOL_SOCKET
, SO_RCVBUF
, &val
, sizeof(val
)) != 0)
119 atf_tc_fail("setsockopt() failed, SO_RCVBUF");
123 if (setsockopt(fds
[0], SOL_SOCKET
, SO_SNDBUF
, &val
, sizeof(val
)) != 0)
124 atf_tc_fail("setsockopt() failed, SO_SNDBUF");
126 if (fcntl(fds
[0], F_SETFL
, O_NONBLOCK
) != 0)
127 atf_tc_fail("fcntl() failed");
129 nwritten
= write(fds
[0], (char *)vp
+ page
, BUFSIZE
- page
);
132 atf_tc_fail("write() failed");
135 (void)memset(vp2
, pat
, BUFSIZE
);
137 nread
= read(fds
[1], buf
+ page
, BUFSIZE
- page
);
140 atf_tc_fail("read() failed");
142 if (nread
!= nwritten
)
143 atf_tc_fail("too short read");
145 if (docheck
!= 0 && memcmp(backup
, buf
+ page
, nread
) != 0)
146 atf_tc_fail("data mismatch");
148 ATF_REQUIRE(close(fds
[0]) == 0);
149 ATF_REQUIRE(close(fds
[1]) == 0);
153 map_sighandler(int signo
)
159 ATF_TC_HEAD(mmap_block
, tc
)
161 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) with a block device");
162 atf_tc_set_md_var(tc
, "require.user", "root");
165 ATF_TC_BODY(mmap_block
, tc
)
167 static const int mib
[] = { CTL_HW
, HW_DISKNAMES
};
168 static const unsigned int miblen
= __arraycount(mib
);
169 char *map
, *dk
, *drives
, dev
[PATH_MAX
];
173 atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)");
175 ATF_REQUIRE(sysctl(mib
, miblen
, NULL
, &len
, NULL
, 0) == 0);
176 drives
= malloc(len
);
177 ATF_REQUIRE(drives
!= NULL
);
178 ATF_REQUIRE(sysctl(mib
, miblen
, drives
, &len
, NULL
, 0) == 0);
179 for (dk
= strtok(drives
, " "); dk
!= NULL
; dk
= strtok(NULL
, " ")) {
180 sprintf(dev
, _PATH_DEV
"%s%c", dk
, 'a'+RAW_PART
);
181 fprintf(stderr
, "trying: %s\n", dev
);
183 if ((fd
= open(dev
, O_RDONLY
)) >= 0) {
184 (void)fprintf(stderr
, "using %s\n", dev
);
191 atf_tc_skip("failed to find suitable block device");
193 map
= mmap(NULL
, 4096, PROT_READ
, MAP_FILE
, fd
, 0);
194 ATF_REQUIRE(map
!= MAP_FAILED
);
196 (void)fprintf(stderr
, "first byte %x\n", *map
);
197 ATF_REQUIRE(close(fd
) == 0);
198 (void)fprintf(stderr
, "first byte %x\n", *map
);
200 ATF_REQUIRE(munmap(map
, 4096) == 0);
204 ATF_TC_HEAD(mmap_err
, tc
)
206 atf_tc_set_md_var(tc
, "descr", "Test error conditions of mmap(2)");
209 ATF_TC_BODY(mmap_err
, tc
)
211 size_t addr
= SIZE_MAX
;
215 map
= mmap(NULL
, 3, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, -1, 0);
217 ATF_REQUIRE(map
== MAP_FAILED
);
218 ATF_REQUIRE(errno
== EBADF
);
221 map
= mmap(&addr
, page
, PROT_READ
, MAP_FIXED
|MAP_PRIVATE
, -1, 0);
223 ATF_REQUIRE(map
== MAP_FAILED
);
224 ATF_REQUIRE(errno
== EINVAL
);
227 map
= mmap(NULL
, page
, PROT_READ
, MAP_ANON
|MAP_PRIVATE
, INT_MAX
, 0);
229 ATF_REQUIRE(map
== MAP_FAILED
);
230 ATF_REQUIRE(errno
== EINVAL
);
233 ATF_TC_WITH_CLEANUP(mmap_loan
);
234 ATF_TC_HEAD(mmap_loan
, tc
)
236 atf_tc_set_md_var(tc
, "descr", "Test uvm page loanout with mmap(2)");
239 ATF_TC_BODY(mmap_loan
, tc
)
245 fd
= open(path
, O_RDWR
| O_CREAT
, 0600);
246 ATF_REQUIRE(fd
>= 0);
248 (void)memset(buf
, 'x', sizeof(buf
));
249 (void)write(fd
, buf
, sizeof(buf
));
251 vp
= mmap(NULL
, BUFSIZE
, PROT_READ
| PROT_WRITE
,
252 MAP_FILE
| MAP_PRIVATE
, fd
, 0);
254 ATF_REQUIRE(vp
!= MAP_FAILED
);
258 testloan(vp
, vp2
, 'A', 0);
259 testloan(vp
, vp2
, 'B', 1);
261 ATF_REQUIRE(munmap(vp
, BUFSIZE
) == 0);
263 vp
= mmap(NULL
, BUFSIZE
, PROT_READ
| PROT_WRITE
,
264 MAP_FILE
| MAP_SHARED
, fd
, 0);
266 vp2
= mmap(NULL
, BUFSIZE
, PROT_READ
| PROT_WRITE
,
267 MAP_FILE
| MAP_SHARED
, fd
, 0);
269 ATF_REQUIRE(vp
!= MAP_FAILED
);
270 ATF_REQUIRE(vp2
!= MAP_FAILED
);
272 testloan(vp
, vp2
, 'E', 1);
274 ATF_REQUIRE(munmap(vp
, BUFSIZE
) == 0);
275 ATF_REQUIRE(munmap(vp2
, BUFSIZE
) == 0);
278 ATF_TC_CLEANUP(mmap_loan
, tc
)
283 ATF_TC_WITH_CLEANUP(mmap_prot_1
);
284 ATF_TC_HEAD(mmap_prot_1
, tc
)
286 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) protections, #1");
289 ATF_TC_BODY(mmap_prot_1
, tc
)
295 * Open a file write-only and try to
296 * map it read-only. This should fail.
298 fd
= open(path
, O_WRONLY
| O_CREAT
, 0700);
303 ATF_REQUIRE(write(fd
, "XXX", 3) == 3);
305 map
= mmap(NULL
, 3, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
308 map
= mmap(NULL
, 3, PROT_WRITE
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
311 ATF_REQUIRE(close(fd
) == 0);
314 ATF_TC_CLEANUP(mmap_prot_1
, tc
)
320 ATF_TC_HEAD(mmap_prot_2
, tc
)
322 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) protections, #2");
325 ATF_TC_BODY(mmap_prot_2
, tc
)
333 * Make a PROT_NONE mapping and try to access it.
334 * If we catch a SIGSEGV, all works as expected.
336 map
= mmap(NULL
, page
, PROT_NONE
, MAP_ANON
|MAP_PRIVATE
, -1, 0);
337 ATF_REQUIRE(map
!= MAP_FAILED
);
340 ATF_REQUIRE(pid
>= 0);
343 ATF_REQUIRE(signal(SIGSEGV
, map_sighandler
) != SIG_ERR
);
344 ATF_REQUIRE(strlcpy(buf
, map
, sizeof(buf
)) != 0);
349 ATF_REQUIRE(WIFEXITED(sta
) != 0);
350 ATF_REQUIRE(WEXITSTATUS(sta
) == SIGSEGV
);
351 ATF_REQUIRE(munmap(map
, page
) == 0);
354 ATF_TC_WITH_CLEANUP(mmap_prot_3
);
355 ATF_TC_HEAD(mmap_prot_3
, tc
)
357 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) protections, #3");
360 ATF_TC_BODY(mmap_prot_3
, tc
)
368 * Open a file, change the permissions
369 * to read-only, and try to map it as
370 * PROT_NONE. This should succeed, but
371 * the access should generate SIGSEGV.
373 fd
= open(path
, O_RDWR
| O_CREAT
, 0700);
378 ATF_REQUIRE(write(fd
, "XXX", 3) == 3);
379 ATF_REQUIRE(close(fd
) == 0);
380 ATF_REQUIRE(chmod(path
, 0444) == 0);
382 fd
= open(path
, O_RDONLY
);
383 ATF_REQUIRE(fd
!= -1);
385 map
= mmap(NULL
, 3, PROT_NONE
, MAP_FILE
| MAP_SHARED
, fd
, 0);
386 ATF_REQUIRE(map
!= MAP_FAILED
);
390 ATF_REQUIRE(pid
>= 0);
393 ATF_REQUIRE(signal(SIGSEGV
, map_sighandler
) != SIG_ERR
);
394 ATF_REQUIRE(strlcpy(buf
, map
, sizeof(buf
)) != 0);
399 ATF_REQUIRE(WIFEXITED(sta
) != 0);
400 ATF_REQUIRE(WEXITSTATUS(sta
) == SIGSEGV
);
401 ATF_REQUIRE(munmap(map
, 3) == 0);
404 ATF_TC_CLEANUP(mmap_prot_3
, tc
)
409 ATF_TC_WITH_CLEANUP(mmap_truncate
);
410 ATF_TC_HEAD(mmap_truncate
, tc
)
412 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) and ftruncate(2)");
415 ATF_TC_BODY(mmap_truncate
, tc
)
421 fd
= open(path
, O_RDWR
| O_CREAT
, 0700);
427 * See that ftruncate(2) works
428 * while the file is mapped.
430 ATF_REQUIRE(ftruncate(fd
, page
) == 0);
432 map
= mmap(NULL
, page
, PROT_READ
| PROT_WRITE
, MAP_FILE
|MAP_PRIVATE
,
434 ATF_REQUIRE(map
!= MAP_FAILED
);
436 for (i
= 0; i
< page
; i
++)
439 ATF_REQUIRE(ftruncate(fd
, 0) == 0);
440 ATF_REQUIRE(ftruncate(fd
, page
/ 8) == 0);
441 ATF_REQUIRE(ftruncate(fd
, page
/ 4) == 0);
442 ATF_REQUIRE(ftruncate(fd
, page
/ 2) == 0);
443 ATF_REQUIRE(ftruncate(fd
, page
/ 12) == 0);
444 ATF_REQUIRE(ftruncate(fd
, page
/ 64) == 0);
446 ATF_REQUIRE(close(fd
) == 0);
449 ATF_TC_CLEANUP(mmap_truncate
, tc
)
454 ATF_TC_WITH_CLEANUP(mmap_truncate_signal
);
455 ATF_TC_HEAD(mmap_truncate_signal
, tc
)
457 atf_tc_set_md_var(tc
, "descr",
458 "Test mmap(2) ftruncate(2) causing signal");
461 ATF_TC_BODY(mmap_truncate_signal
, tc
)
468 fd
= open(path
, O_RDWR
| O_CREAT
, 0700);
473 ATF_REQUIRE(write(fd
, "foo\n", 5) == 5);
475 map
= mmap(NULL
, page
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
476 ATF_REQUIRE(map
!= MAP_FAILED
);
479 for (i
= 0; i
< 5; i
++)
481 ATF_REQUIRE(sta
== 334);
483 ATF_REQUIRE(ftruncate(fd
, 0) == 0);
485 ATF_REQUIRE(pid
>= 0);
488 ATF_REQUIRE(signal(SIGBUS
, map_sighandler
) != SIG_ERR
);
489 ATF_REQUIRE(signal(SIGSEGV
, map_sighandler
) != SIG_ERR
);
491 for (i
= 0; i
< page
; i
++)
493 /* child never will get this far, but the compiler will
494 not know, so better use the values calculated to
495 prevent the access to be optimized out */
497 ATF_REQUIRE(sta
== 0);
503 ATF_REQUIRE(WIFEXITED(sta
) != 0);
504 if (WEXITSTATUS(sta
) == SIGSEGV
)
505 atf_tc_fail("child process got SIGSEGV instead of SIGBUS");
506 ATF_REQUIRE(WEXITSTATUS(sta
) == SIGBUS
);
507 ATF_REQUIRE(munmap(map
, page
) == 0);
508 ATF_REQUIRE(close(fd
) == 0);
511 ATF_TC_CLEANUP(mmap_truncate_signal
, tc
)
517 ATF_TC_HEAD(mmap_va0
, tc
)
519 atf_tc_set_md_var(tc
, "descr", "Test mmap(2) and vm.user_va0_disable");
522 ATF_TC_BODY(mmap_va0
, tc
)
524 int flags
= MAP_ANON
| MAP_FIXED
| MAP_PRIVATE
;
525 size_t len
= sizeof(int);
530 * Make an anonymous fixed mapping at zero address. If the address
531 * is restricted as noted in security(7), the syscall should fail.
533 if (sysctlbyname("vm.user_va0_disable", &val
, &len
, NULL
, 0) != 0)
534 atf_tc_fail("failed to read vm.user_va0_disable");
536 map
= mmap(NULL
, page
, PROT_EXEC
, flags
, -1, 0);
539 map
= mmap(NULL
, page
, PROT_READ
, flags
, -1, 0);
542 map
= mmap(NULL
, page
, PROT_WRITE
, flags
, -1, 0);
545 map
= mmap(NULL
, page
, PROT_READ
|PROT_WRITE
, flags
, -1, 0);
548 map
= mmap(NULL
, page
, PROT_EXEC
|PROT_READ
|PROT_WRITE
, flags
, -1, 0);
554 page
= sysconf(_SC_PAGESIZE
);
555 ATF_REQUIRE(page
>= 0);
557 ATF_TP_ADD_TC(tp
, mmap_block
);
558 ATF_TP_ADD_TC(tp
, mmap_err
);
559 ATF_TP_ADD_TC(tp
, mmap_loan
);
560 ATF_TP_ADD_TC(tp
, mmap_prot_1
);
561 ATF_TP_ADD_TC(tp
, mmap_prot_2
);
562 ATF_TP_ADD_TC(tp
, mmap_prot_3
);
563 ATF_TP_ADD_TC(tp
, mmap_truncate
);
564 ATF_TP_ADD_TC(tp
, mmap_truncate_signal
);
565 ATF_TP_ADD_TC(tp
, mmap_va0
);
567 return atf_no_error();