13b0a9131SEnji Cooper /* $NetBSD: t_mmap.c,v 1.12 2017/01/16 16:31:05 christos Exp $ */
257718be8SEnji Cooper
357718be8SEnji Cooper /*-
457718be8SEnji Cooper * Copyright (c) 2011 The NetBSD Foundation, Inc.
557718be8SEnji Cooper * All rights reserved.
657718be8SEnji Cooper *
757718be8SEnji Cooper * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper * by Jukka Ruohonen.
957718be8SEnji Cooper *
1057718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
1157718be8SEnji Cooper * modification, are permitted provided that the following conditions
1257718be8SEnji Cooper * are met:
1357718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
1457718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
1557718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
1657718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
1757718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
1857718be8SEnji Cooper *
1957718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2057718be8SEnji Cooper * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2157718be8SEnji Cooper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2257718be8SEnji Cooper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2357718be8SEnji Cooper * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2457718be8SEnji Cooper * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2557718be8SEnji Cooper * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2657718be8SEnji Cooper * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2757718be8SEnji Cooper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2857718be8SEnji Cooper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2957718be8SEnji Cooper * POSSIBILITY OF SUCH DAMAGE.
3057718be8SEnji Cooper */
3157718be8SEnji Cooper
3257718be8SEnji Cooper /*-
3357718be8SEnji Cooper * Copyright (c)2004 YAMAMOTO Takashi,
3457718be8SEnji Cooper * All rights reserved.
3557718be8SEnji Cooper *
3657718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
3757718be8SEnji Cooper * modification, are permitted provided that the following conditions
3857718be8SEnji Cooper * are met:
3957718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
4057718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
4157718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
4257718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
4357718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
4457718be8SEnji Cooper *
4557718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4657718be8SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4757718be8SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4857718be8SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4957718be8SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5057718be8SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5157718be8SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5257718be8SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5357718be8SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5457718be8SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5557718be8SEnji Cooper * SUCH DAMAGE.
5657718be8SEnji Cooper */
5757718be8SEnji Cooper #include <sys/cdefs.h>
583b0a9131SEnji Cooper __RCSID("$NetBSD: t_mmap.c,v 1.12 2017/01/16 16:31:05 christos Exp $");
5957718be8SEnji Cooper
6057718be8SEnji Cooper #include <sys/param.h>
613b0a9131SEnji Cooper #include <sys/disklabel.h>
6257718be8SEnji Cooper #include <sys/mman.h>
63ddba0402SEnji Cooper #include <sys/stat.h>
6457718be8SEnji Cooper #include <sys/socket.h>
6557718be8SEnji Cooper #include <sys/sysctl.h>
6657718be8SEnji Cooper #include <sys/wait.h>
6757718be8SEnji Cooper
6857718be8SEnji Cooper #include <atf-c.h>
6957718be8SEnji Cooper #include <errno.h>
7057718be8SEnji Cooper #include <fcntl.h>
7157718be8SEnji Cooper #include <signal.h>
7257718be8SEnji Cooper #include <stdio.h>
7357718be8SEnji Cooper #include <stdlib.h>
7457718be8SEnji Cooper #include <string.h>
7557718be8SEnji Cooper #include <unistd.h>
7657718be8SEnji Cooper #include <paths.h>
773b0a9131SEnji Cooper #ifdef __FreeBSD__
7841acfd75SEnji Cooper #include <stdint.h>
7941acfd75SEnji Cooper #endif
8057718be8SEnji Cooper
8157718be8SEnji Cooper static long page = 0;
8257718be8SEnji Cooper static char path[] = "mmap";
8357718be8SEnji Cooper static void map_check(void *, int);
8457718be8SEnji Cooper static void map_sighandler(int);
8557718be8SEnji Cooper static void testloan(void *, void *, char, int);
8657718be8SEnji Cooper
8757718be8SEnji Cooper #define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */
8857718be8SEnji Cooper
8957718be8SEnji Cooper static void
map_check(void * map,int flag)9057718be8SEnji Cooper map_check(void *map, int flag)
9157718be8SEnji Cooper {
9257718be8SEnji Cooper
9357718be8SEnji Cooper if (flag != 0) {
9457718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED);
9557718be8SEnji Cooper return;
9657718be8SEnji Cooper }
9757718be8SEnji Cooper
9857718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
9957718be8SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0);
10057718be8SEnji Cooper }
10157718be8SEnji Cooper
10257718be8SEnji Cooper void
testloan(void * vp,void * vp2,char pat,int docheck)10357718be8SEnji Cooper testloan(void *vp, void *vp2, char pat, int docheck)
10457718be8SEnji Cooper {
10557718be8SEnji Cooper char buf[BUFSIZE];
10657718be8SEnji Cooper char backup[BUFSIZE];
10757718be8SEnji Cooper ssize_t nwritten;
10857718be8SEnji Cooper ssize_t nread;
10957718be8SEnji Cooper int fds[2];
11057718be8SEnji Cooper int val;
11157718be8SEnji Cooper
11257718be8SEnji Cooper val = BUFSIZE;
11357718be8SEnji Cooper
11457718be8SEnji Cooper if (docheck != 0)
11557718be8SEnji Cooper (void)memcpy(backup, vp, BUFSIZE);
11657718be8SEnji Cooper
11757718be8SEnji Cooper if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0)
11857718be8SEnji Cooper atf_tc_fail("socketpair() failed");
11957718be8SEnji Cooper
12057718be8SEnji Cooper val = BUFSIZE;
12157718be8SEnji Cooper
12257718be8SEnji Cooper if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
12357718be8SEnji Cooper atf_tc_fail("setsockopt() failed, SO_RCVBUF");
12457718be8SEnji Cooper
12557718be8SEnji Cooper val = BUFSIZE;
12657718be8SEnji Cooper
12757718be8SEnji Cooper if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
12857718be8SEnji Cooper atf_tc_fail("setsockopt() failed, SO_SNDBUF");
12957718be8SEnji Cooper
13057718be8SEnji Cooper if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0)
13157718be8SEnji Cooper atf_tc_fail("fcntl() failed");
13257718be8SEnji Cooper
13357718be8SEnji Cooper nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page);
13457718be8SEnji Cooper
13557718be8SEnji Cooper if (nwritten == -1)
13657718be8SEnji Cooper atf_tc_fail("write() failed");
13757718be8SEnji Cooper
13857718be8SEnji Cooper /* Break loan. */
13957718be8SEnji Cooper (void)memset(vp2, pat, BUFSIZE);
14057718be8SEnji Cooper
14157718be8SEnji Cooper nread = read(fds[1], buf + page, BUFSIZE - page);
14257718be8SEnji Cooper
14357718be8SEnji Cooper if (nread == -1)
14457718be8SEnji Cooper atf_tc_fail("read() failed");
14557718be8SEnji Cooper
14657718be8SEnji Cooper if (nread != nwritten)
14757718be8SEnji Cooper atf_tc_fail("too short read");
14857718be8SEnji Cooper
14957718be8SEnji Cooper if (docheck != 0 && memcmp(backup, buf + page, nread) != 0)
15057718be8SEnji Cooper atf_tc_fail("data mismatch");
15157718be8SEnji Cooper
15257718be8SEnji Cooper ATF_REQUIRE(close(fds[0]) == 0);
15357718be8SEnji Cooper ATF_REQUIRE(close(fds[1]) == 0);
15457718be8SEnji Cooper }
15557718be8SEnji Cooper
15657718be8SEnji Cooper static void
map_sighandler(int signo)15757718be8SEnji Cooper map_sighandler(int signo)
15857718be8SEnji Cooper {
15957718be8SEnji Cooper _exit(signo);
16057718be8SEnji Cooper }
16157718be8SEnji Cooper
16241acfd75SEnji Cooper #ifdef __NetBSD__
16357718be8SEnji Cooper ATF_TC(mmap_block);
ATF_TC_HEAD(mmap_block,tc)16457718be8SEnji Cooper ATF_TC_HEAD(mmap_block, tc)
16557718be8SEnji Cooper {
16657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device");
16757718be8SEnji Cooper atf_tc_set_md_var(tc, "require.user", "root");
16857718be8SEnji Cooper }
16957718be8SEnji Cooper
ATF_TC_BODY(mmap_block,tc)17057718be8SEnji Cooper ATF_TC_BODY(mmap_block, tc)
17157718be8SEnji Cooper {
17257718be8SEnji Cooper static const int mib[] = { CTL_HW, HW_DISKNAMES };
17357718be8SEnji Cooper static const unsigned int miblen = __arraycount(mib);
17457718be8SEnji Cooper char *map, *dk, *drives, dev[PATH_MAX];
17557718be8SEnji Cooper size_t len;
17657718be8SEnji Cooper int fd = -1;
17757718be8SEnji Cooper
17857718be8SEnji Cooper atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)");
17957718be8SEnji Cooper
18057718be8SEnji Cooper ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0);
18157718be8SEnji Cooper drives = malloc(len);
18257718be8SEnji Cooper ATF_REQUIRE(drives != NULL);
18357718be8SEnji Cooper ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0);
18457718be8SEnji Cooper for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) {
18557718be8SEnji Cooper sprintf(dev, _PATH_DEV "%s%c", dk, 'a'+RAW_PART);
18657718be8SEnji Cooper fprintf(stderr, "trying: %s\n", dev);
18757718be8SEnji Cooper
18857718be8SEnji Cooper if ((fd = open(dev, O_RDONLY)) >= 0) {
18957718be8SEnji Cooper (void)fprintf(stderr, "using %s\n", dev);
19057718be8SEnji Cooper break;
19157718be8SEnji Cooper }
19257718be8SEnji Cooper }
19357718be8SEnji Cooper free(drives);
19457718be8SEnji Cooper
19557718be8SEnji Cooper if (fd < 0)
19657718be8SEnji Cooper atf_tc_skip("failed to find suitable block device");
19757718be8SEnji Cooper
19857718be8SEnji Cooper map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0);
19957718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
20057718be8SEnji Cooper
20157718be8SEnji Cooper (void)fprintf(stderr, "first byte %x\n", *map);
20257718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0);
20357718be8SEnji Cooper (void)fprintf(stderr, "first byte %x\n", *map);
20457718be8SEnji Cooper
20557718be8SEnji Cooper ATF_REQUIRE(munmap(map, 4096) == 0);
20657718be8SEnji Cooper }
20741acfd75SEnji Cooper #endif
20857718be8SEnji Cooper
20957718be8SEnji Cooper ATF_TC(mmap_err);
ATF_TC_HEAD(mmap_err,tc)21057718be8SEnji Cooper ATF_TC_HEAD(mmap_err, tc)
21157718be8SEnji Cooper {
21257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)");
21357718be8SEnji Cooper }
21457718be8SEnji Cooper
ATF_TC_BODY(mmap_err,tc)21557718be8SEnji Cooper ATF_TC_BODY(mmap_err, tc)
21657718be8SEnji Cooper {
21757718be8SEnji Cooper size_t addr = SIZE_MAX;
21857718be8SEnji Cooper void *map;
21957718be8SEnji Cooper
22057718be8SEnji Cooper errno = 0;
22157718be8SEnji Cooper map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0);
22257718be8SEnji Cooper
22357718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED);
22457718be8SEnji Cooper ATF_REQUIRE(errno == EBADF);
22557718be8SEnji Cooper
22657718be8SEnji Cooper errno = 0;
22757718be8SEnji Cooper map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0);
22857718be8SEnji Cooper
22957718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED);
23057718be8SEnji Cooper ATF_REQUIRE(errno == EINVAL);
23157718be8SEnji Cooper
23257718be8SEnji Cooper errno = 0;
23357718be8SEnji Cooper map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0);
23457718be8SEnji Cooper
23557718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED);
23657718be8SEnji Cooper ATF_REQUIRE(errno == EINVAL);
23757718be8SEnji Cooper }
23857718be8SEnji Cooper
23957718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_loan);
ATF_TC_HEAD(mmap_loan,tc)24057718be8SEnji Cooper ATF_TC_HEAD(mmap_loan, tc)
24157718be8SEnji Cooper {
24257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)");
24357718be8SEnji Cooper }
24457718be8SEnji Cooper
ATF_TC_BODY(mmap_loan,tc)24557718be8SEnji Cooper ATF_TC_BODY(mmap_loan, tc)
24657718be8SEnji Cooper {
24757718be8SEnji Cooper char buf[BUFSIZE];
24857718be8SEnji Cooper char *vp, *vp2;
24957718be8SEnji Cooper int fd;
25057718be8SEnji Cooper
25157718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0600);
25257718be8SEnji Cooper ATF_REQUIRE(fd >= 0);
25357718be8SEnji Cooper
25457718be8SEnji Cooper (void)memset(buf, 'x', sizeof(buf));
25557718be8SEnji Cooper (void)write(fd, buf, sizeof(buf));
25657718be8SEnji Cooper
25757718be8SEnji Cooper vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
25857718be8SEnji Cooper MAP_FILE | MAP_PRIVATE, fd, 0);
25957718be8SEnji Cooper
26057718be8SEnji Cooper ATF_REQUIRE(vp != MAP_FAILED);
26157718be8SEnji Cooper
26257718be8SEnji Cooper vp2 = vp;
26357718be8SEnji Cooper
26457718be8SEnji Cooper testloan(vp, vp2, 'A', 0);
26557718be8SEnji Cooper testloan(vp, vp2, 'B', 1);
26657718be8SEnji Cooper
26757718be8SEnji Cooper ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
26857718be8SEnji Cooper
26957718be8SEnji Cooper vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
27057718be8SEnji Cooper MAP_FILE | MAP_SHARED, fd, 0);
27157718be8SEnji Cooper
27257718be8SEnji Cooper vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
27357718be8SEnji Cooper MAP_FILE | MAP_SHARED, fd, 0);
27457718be8SEnji Cooper
27557718be8SEnji Cooper ATF_REQUIRE(vp != MAP_FAILED);
27657718be8SEnji Cooper ATF_REQUIRE(vp2 != MAP_FAILED);
27757718be8SEnji Cooper
27857718be8SEnji Cooper testloan(vp, vp2, 'E', 1);
27957718be8SEnji Cooper
28057718be8SEnji Cooper ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
28157718be8SEnji Cooper ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0);
28257718be8SEnji Cooper }
28357718be8SEnji Cooper
ATF_TC_CLEANUP(mmap_loan,tc)28457718be8SEnji Cooper ATF_TC_CLEANUP(mmap_loan, tc)
28557718be8SEnji Cooper {
28657718be8SEnji Cooper (void)unlink(path);
28757718be8SEnji Cooper }
28857718be8SEnji Cooper
28957718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_prot_1);
ATF_TC_HEAD(mmap_prot_1,tc)29057718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_1, tc)
29157718be8SEnji Cooper {
29257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1");
29357718be8SEnji Cooper }
29457718be8SEnji Cooper
ATF_TC_BODY(mmap_prot_1,tc)29557718be8SEnji Cooper ATF_TC_BODY(mmap_prot_1, tc)
29657718be8SEnji Cooper {
29757718be8SEnji Cooper void *map;
29857718be8SEnji Cooper int fd;
29957718be8SEnji Cooper
30057718be8SEnji Cooper /*
30157718be8SEnji Cooper * Open a file write-only and try to
30257718be8SEnji Cooper * map it read-only. This should fail.
30357718be8SEnji Cooper */
30457718be8SEnji Cooper fd = open(path, O_WRONLY | O_CREAT, 0700);
30557718be8SEnji Cooper
30657718be8SEnji Cooper if (fd < 0)
30757718be8SEnji Cooper return;
30857718be8SEnji Cooper
30957718be8SEnji Cooper ATF_REQUIRE(write(fd, "XXX", 3) == 3);
31057718be8SEnji Cooper
31157718be8SEnji Cooper map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
31257718be8SEnji Cooper map_check(map, 1);
31357718be8SEnji Cooper
31457718be8SEnji Cooper map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
31557718be8SEnji Cooper map_check(map, 0);
31657718be8SEnji Cooper
31757718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0);
31857718be8SEnji Cooper }
31957718be8SEnji Cooper
ATF_TC_CLEANUP(mmap_prot_1,tc)32057718be8SEnji Cooper ATF_TC_CLEANUP(mmap_prot_1, tc)
32157718be8SEnji Cooper {
32257718be8SEnji Cooper (void)unlink(path);
32357718be8SEnji Cooper }
32457718be8SEnji Cooper
32557718be8SEnji Cooper ATF_TC(mmap_prot_2);
ATF_TC_HEAD(mmap_prot_2,tc)32657718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_2, tc)
32757718be8SEnji Cooper {
32857718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2");
32957718be8SEnji Cooper }
33057718be8SEnji Cooper
ATF_TC_BODY(mmap_prot_2,tc)33157718be8SEnji Cooper ATF_TC_BODY(mmap_prot_2, tc)
33257718be8SEnji Cooper {
33357718be8SEnji Cooper char buf[2];
33457718be8SEnji Cooper void *map;
33557718be8SEnji Cooper pid_t pid;
33657718be8SEnji Cooper int sta;
33757718be8SEnji Cooper
33857718be8SEnji Cooper /*
33957718be8SEnji Cooper * Make a PROT_NONE mapping and try to access it.
34057718be8SEnji Cooper * If we catch a SIGSEGV, all works as expected.
34157718be8SEnji Cooper */
34257718be8SEnji Cooper map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
34357718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
34457718be8SEnji Cooper
34557718be8SEnji Cooper pid = fork();
34657718be8SEnji Cooper ATF_REQUIRE(pid >= 0);
34757718be8SEnji Cooper
34857718be8SEnji Cooper if (pid == 0) {
34957718be8SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
35057718be8SEnji Cooper ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
35157718be8SEnji Cooper }
35257718be8SEnji Cooper
35357718be8SEnji Cooper (void)wait(&sta);
35457718be8SEnji Cooper
35557718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0);
35657718be8SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
35757718be8SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0);
35857718be8SEnji Cooper }
35957718be8SEnji Cooper
36057718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_prot_3);
ATF_TC_HEAD(mmap_prot_3,tc)36157718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_3, tc)
36257718be8SEnji Cooper {
36357718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3");
36457718be8SEnji Cooper }
36557718be8SEnji Cooper
ATF_TC_BODY(mmap_prot_3,tc)36657718be8SEnji Cooper ATF_TC_BODY(mmap_prot_3, tc)
36757718be8SEnji Cooper {
36857718be8SEnji Cooper char buf[2];
36957718be8SEnji Cooper int fd, sta;
37057718be8SEnji Cooper void *map;
37157718be8SEnji Cooper pid_t pid;
37257718be8SEnji Cooper
37357718be8SEnji Cooper /*
37457718be8SEnji Cooper * Open a file, change the permissions
37557718be8SEnji Cooper * to read-only, and try to map it as
37657718be8SEnji Cooper * PROT_NONE. This should succeed, but
37757718be8SEnji Cooper * the access should generate SIGSEGV.
37857718be8SEnji Cooper */
37957718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700);
380*e2a4e9c6SEnji Cooper
38157718be8SEnji Cooper if (fd < 0)
38257f5b7d8SEnji Cooper #ifdef __FreeBSD__
38357f5b7d8SEnji Cooper atf_tc_skip("opening %s failed; skipping testcase: %s",
38457f5b7d8SEnji Cooper path, strerror(errno));
38557f5b7d8SEnji Cooper #else
38657718be8SEnji Cooper return;
38757f5b7d8SEnji Cooper #endif
38857718be8SEnji Cooper
38957718be8SEnji Cooper ATF_REQUIRE(write(fd, "XXX", 3) == 3);
39057718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0);
39157718be8SEnji Cooper ATF_REQUIRE(chmod(path, 0444) == 0);
39257718be8SEnji Cooper
39357718be8SEnji Cooper fd = open(path, O_RDONLY);
39457718be8SEnji Cooper ATF_REQUIRE(fd != -1);
39557718be8SEnji Cooper
39657718be8SEnji Cooper map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0);
39757718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
39857718be8SEnji Cooper
39957718be8SEnji Cooper pid = fork();
40057718be8SEnji Cooper
40157718be8SEnji Cooper ATF_REQUIRE(pid >= 0);
40257718be8SEnji Cooper
40357718be8SEnji Cooper if (pid == 0) {
40457718be8SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
40557718be8SEnji Cooper ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
40657718be8SEnji Cooper }
40757718be8SEnji Cooper
40857718be8SEnji Cooper (void)wait(&sta);
40957718be8SEnji Cooper
41057718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0);
41157718be8SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
41257718be8SEnji Cooper ATF_REQUIRE(munmap(map, 3) == 0);
41357f5b7d8SEnji Cooper #ifdef __FreeBSD__
41457f5b7d8SEnji Cooper (void)close(fd);
41557f5b7d8SEnji Cooper #endif
41657718be8SEnji Cooper }
41757718be8SEnji Cooper
ATF_TC_CLEANUP(mmap_prot_3,tc)41857718be8SEnji Cooper ATF_TC_CLEANUP(mmap_prot_3, tc)
41957718be8SEnji Cooper {
42057718be8SEnji Cooper (void)unlink(path);
42157718be8SEnji Cooper }
42257718be8SEnji Cooper
42357718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_truncate);
ATF_TC_HEAD(mmap_truncate,tc)42457718be8SEnji Cooper ATF_TC_HEAD(mmap_truncate, tc)
42557718be8SEnji Cooper {
42657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)");
42757718be8SEnji Cooper }
42857718be8SEnji Cooper
ATF_TC_BODY(mmap_truncate,tc)42957718be8SEnji Cooper ATF_TC_BODY(mmap_truncate, tc)
43057718be8SEnji Cooper {
43157718be8SEnji Cooper char *map;
43257718be8SEnji Cooper long i;
43357718be8SEnji Cooper int fd;
43457718be8SEnji Cooper
43557718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700);
43657718be8SEnji Cooper
43757718be8SEnji Cooper if (fd < 0)
43857718be8SEnji Cooper return;
43957718be8SEnji Cooper
44057718be8SEnji Cooper /*
44157718be8SEnji Cooper * See that ftruncate(2) works
44257718be8SEnji Cooper * while the file is mapped.
44357718be8SEnji Cooper */
44457718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page) == 0);
44557718be8SEnji Cooper
44657718be8SEnji Cooper map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE,
44757718be8SEnji Cooper fd, 0);
44857718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
44957718be8SEnji Cooper
45057718be8SEnji Cooper for (i = 0; i < page; i++)
45157718be8SEnji Cooper map[i] = 'x';
45257718be8SEnji Cooper
45357718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, 0) == 0);
45457718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 8) == 0);
45557718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 4) == 0);
45657718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 2) == 0);
45757718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 12) == 0);
45857718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 64) == 0);
45957718be8SEnji Cooper
46057f5b7d8SEnji Cooper (void)munmap(map, page);
46157718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0);
46257718be8SEnji Cooper }
46357718be8SEnji Cooper
ATF_TC_CLEANUP(mmap_truncate,tc)46457718be8SEnji Cooper ATF_TC_CLEANUP(mmap_truncate, tc)
46557718be8SEnji Cooper {
46657718be8SEnji Cooper (void)unlink(path);
46757718be8SEnji Cooper }
46857718be8SEnji Cooper
469640235e2SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_truncate_signal);
ATF_TC_HEAD(mmap_truncate_signal,tc)470640235e2SEnji Cooper ATF_TC_HEAD(mmap_truncate_signal, tc)
471640235e2SEnji Cooper {
472640235e2SEnji Cooper atf_tc_set_md_var(tc, "descr",
473640235e2SEnji Cooper "Test mmap(2) ftruncate(2) causing signal");
474640235e2SEnji Cooper }
475640235e2SEnji Cooper
ATF_TC_BODY(mmap_truncate_signal,tc)476640235e2SEnji Cooper ATF_TC_BODY(mmap_truncate_signal, tc)
477640235e2SEnji Cooper {
478640235e2SEnji Cooper char *map;
479640235e2SEnji Cooper long i;
480640235e2SEnji Cooper int fd, sta;
481640235e2SEnji Cooper pid_t pid;
482640235e2SEnji Cooper
483640235e2SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700);
484640235e2SEnji Cooper
485640235e2SEnji Cooper if (fd < 0)
486640235e2SEnji Cooper return;
487640235e2SEnji Cooper
488640235e2SEnji Cooper ATF_REQUIRE(write(fd, "foo\n", 5) == 5);
489640235e2SEnji Cooper
490640235e2SEnji Cooper map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
491640235e2SEnji Cooper ATF_REQUIRE(map != MAP_FAILED);
492640235e2SEnji Cooper
493640235e2SEnji Cooper sta = 0;
494640235e2SEnji Cooper for (i = 0; i < 5; i++)
495640235e2SEnji Cooper sta += map[i];
496640235e2SEnji Cooper ATF_REQUIRE(sta == 334);
497640235e2SEnji Cooper
498640235e2SEnji Cooper ATF_REQUIRE(ftruncate(fd, 0) == 0);
499640235e2SEnji Cooper pid = fork();
500640235e2SEnji Cooper ATF_REQUIRE(pid >= 0);
501640235e2SEnji Cooper
502640235e2SEnji Cooper if (pid == 0) {
503640235e2SEnji Cooper ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR);
504640235e2SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
505640235e2SEnji Cooper sta = 0;
506640235e2SEnji Cooper for (i = 0; i < page; i++)
507640235e2SEnji Cooper sta += map[i];
508640235e2SEnji Cooper /* child never will get this far, but the compiler will
509640235e2SEnji Cooper not know, so better use the values calculated to
510640235e2SEnji Cooper prevent the access to be optimized out */
511640235e2SEnji Cooper ATF_REQUIRE(i == 0);
512640235e2SEnji Cooper ATF_REQUIRE(sta == 0);
51357f5b7d8SEnji Cooper (void)munmap(map, page);
51457f5b7d8SEnji Cooper (void)close(fd);
515640235e2SEnji Cooper return;
516640235e2SEnji Cooper }
517640235e2SEnji Cooper
518640235e2SEnji Cooper (void)wait(&sta);
519640235e2SEnji Cooper
520640235e2SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0);
521640235e2SEnji Cooper if (WEXITSTATUS(sta) == SIGSEGV)
522640235e2SEnji Cooper atf_tc_fail("child process got SIGSEGV instead of SIGBUS");
523640235e2SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS);
524640235e2SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0);
525640235e2SEnji Cooper ATF_REQUIRE(close(fd) == 0);
526640235e2SEnji Cooper }
527640235e2SEnji Cooper
ATF_TC_CLEANUP(mmap_truncate_signal,tc)528640235e2SEnji Cooper ATF_TC_CLEANUP(mmap_truncate_signal, tc)
529640235e2SEnji Cooper {
530640235e2SEnji Cooper (void)unlink(path);
531640235e2SEnji Cooper }
532640235e2SEnji Cooper
53357718be8SEnji Cooper ATF_TC(mmap_va0);
ATF_TC_HEAD(mmap_va0,tc)53457718be8SEnji Cooper ATF_TC_HEAD(mmap_va0, tc)
53557718be8SEnji Cooper {
53657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable");
53757718be8SEnji Cooper }
53857718be8SEnji Cooper
ATF_TC_BODY(mmap_va0,tc)53957718be8SEnji Cooper ATF_TC_BODY(mmap_va0, tc)
54057718be8SEnji Cooper {
54157718be8SEnji Cooper int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE;
54257718be8SEnji Cooper size_t len = sizeof(int);
54357718be8SEnji Cooper void *map;
54457718be8SEnji Cooper int val;
54557718be8SEnji Cooper
54657718be8SEnji Cooper /*
54757718be8SEnji Cooper * Make an anonymous fixed mapping at zero address. If the address
54857718be8SEnji Cooper * is restricted as noted in security(7), the syscall should fail.
54957718be8SEnji Cooper */
55041acfd75SEnji Cooper #ifdef __FreeBSD__
55141acfd75SEnji Cooper if (sysctlbyname("security.bsd.map_at_zero", &val, &len, NULL, 0) != 0)
55241acfd75SEnji Cooper atf_tc_fail("failed to read security.bsd.map_at_zero");
55341acfd75SEnji Cooper val = !val; /* 1 == enable map at zero */
55441acfd75SEnji Cooper #endif
55541acfd75SEnji Cooper #ifdef __NetBSD__
55657718be8SEnji Cooper if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0)
55757718be8SEnji Cooper atf_tc_fail("failed to read vm.user_va0_disable");
55841acfd75SEnji Cooper #endif
55957718be8SEnji Cooper
56057718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC, flags, -1, 0);
56157718be8SEnji Cooper map_check(map, val);
56257718be8SEnji Cooper
56357718be8SEnji Cooper map = mmap(NULL, page, PROT_READ, flags, -1, 0);
56457718be8SEnji Cooper map_check(map, val);
56557718be8SEnji Cooper
56657718be8SEnji Cooper map = mmap(NULL, page, PROT_WRITE, flags, -1, 0);
56757718be8SEnji Cooper map_check(map, val);
56857718be8SEnji Cooper
56957718be8SEnji Cooper map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0);
57057718be8SEnji Cooper map_check(map, val);
57157718be8SEnji Cooper
57257718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0);
57357718be8SEnji Cooper map_check(map, val);
57457718be8SEnji Cooper }
57557718be8SEnji Cooper
ATF_TP_ADD_TCS(tp)57657718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
57757718be8SEnji Cooper {
57857718be8SEnji Cooper page = sysconf(_SC_PAGESIZE);
57957718be8SEnji Cooper ATF_REQUIRE(page >= 0);
58057718be8SEnji Cooper
58141acfd75SEnji Cooper #ifdef __NetBSD__
58257718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_block);
58341acfd75SEnji Cooper #endif
58457718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_err);
58557718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_loan);
58657718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_1);
58757718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_2);
58857718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_3);
58957718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate);
590640235e2SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate_signal);
59157718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_va0);
59257718be8SEnji Cooper
59357718be8SEnji Cooper return atf_no_error();
59457718be8SEnji Cooper }
595