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 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 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 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); 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 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); 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 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); 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 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 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); 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 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 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); 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 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); 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 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 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); 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 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 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); 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 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 48374f4c1cfSEnji Cooper #ifdef __FreeBSD__ 48474f4c1cfSEnji Cooper atf_tc_expect_fail("testcase fails with SIGSEGV on FreeBSD; bug # 211924"); 48574f4c1cfSEnji Cooper #endif 48674f4c1cfSEnji Cooper 487640235e2SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700); 488640235e2SEnji Cooper 489640235e2SEnji Cooper if (fd < 0) 490640235e2SEnji Cooper return; 491640235e2SEnji Cooper 492640235e2SEnji Cooper ATF_REQUIRE(write(fd, "foo\n", 5) == 5); 493640235e2SEnji Cooper 494640235e2SEnji Cooper map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 495640235e2SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 496640235e2SEnji Cooper 497640235e2SEnji Cooper sta = 0; 498640235e2SEnji Cooper for (i = 0; i < 5; i++) 499640235e2SEnji Cooper sta += map[i]; 500640235e2SEnji Cooper ATF_REQUIRE(sta == 334); 501640235e2SEnji Cooper 502640235e2SEnji Cooper ATF_REQUIRE(ftruncate(fd, 0) == 0); 503640235e2SEnji Cooper pid = fork(); 504640235e2SEnji Cooper ATF_REQUIRE(pid >= 0); 505640235e2SEnji Cooper 506640235e2SEnji Cooper if (pid == 0) { 507640235e2SEnji Cooper ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR); 508640235e2SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 509640235e2SEnji Cooper sta = 0; 510640235e2SEnji Cooper for (i = 0; i < page; i++) 511640235e2SEnji Cooper sta += map[i]; 512640235e2SEnji Cooper /* child never will get this far, but the compiler will 513640235e2SEnji Cooper not know, so better use the values calculated to 514640235e2SEnji Cooper prevent the access to be optimized out */ 515640235e2SEnji Cooper ATF_REQUIRE(i == 0); 516640235e2SEnji Cooper ATF_REQUIRE(sta == 0); 51757f5b7d8SEnji Cooper (void)munmap(map, page); 51857f5b7d8SEnji Cooper (void)close(fd); 519640235e2SEnji Cooper return; 520640235e2SEnji Cooper } 521640235e2SEnji Cooper 522640235e2SEnji Cooper (void)wait(&sta); 523640235e2SEnji Cooper 524640235e2SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0); 525640235e2SEnji Cooper if (WEXITSTATUS(sta) == SIGSEGV) 526640235e2SEnji Cooper atf_tc_fail("child process got SIGSEGV instead of SIGBUS"); 527640235e2SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS); 528640235e2SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0); 529640235e2SEnji Cooper ATF_REQUIRE(close(fd) == 0); 530640235e2SEnji Cooper } 531640235e2SEnji Cooper 532640235e2SEnji Cooper ATF_TC_CLEANUP(mmap_truncate_signal, tc) 533640235e2SEnji Cooper { 534640235e2SEnji Cooper (void)unlink(path); 535640235e2SEnji Cooper } 536640235e2SEnji Cooper 53757718be8SEnji Cooper ATF_TC(mmap_va0); 53857718be8SEnji Cooper ATF_TC_HEAD(mmap_va0, tc) 53957718be8SEnji Cooper { 54057718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable"); 54157718be8SEnji Cooper } 54257718be8SEnji Cooper 54357718be8SEnji Cooper ATF_TC_BODY(mmap_va0, tc) 54457718be8SEnji Cooper { 54557718be8SEnji Cooper int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE; 54657718be8SEnji Cooper size_t len = sizeof(int); 54757718be8SEnji Cooper void *map; 54857718be8SEnji Cooper int val; 54957718be8SEnji Cooper 55057718be8SEnji Cooper /* 55157718be8SEnji Cooper * Make an anonymous fixed mapping at zero address. If the address 55257718be8SEnji Cooper * is restricted as noted in security(7), the syscall should fail. 55357718be8SEnji Cooper */ 55441acfd75SEnji Cooper #ifdef __FreeBSD__ 55541acfd75SEnji Cooper if (sysctlbyname("security.bsd.map_at_zero", &val, &len, NULL, 0) != 0) 55641acfd75SEnji Cooper atf_tc_fail("failed to read security.bsd.map_at_zero"); 55741acfd75SEnji Cooper val = !val; /* 1 == enable map at zero */ 55841acfd75SEnji Cooper #endif 55941acfd75SEnji Cooper #ifdef __NetBSD__ 56057718be8SEnji Cooper if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0) 56157718be8SEnji Cooper atf_tc_fail("failed to read vm.user_va0_disable"); 56241acfd75SEnji Cooper #endif 56357718be8SEnji Cooper 56457718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC, flags, -1, 0); 56557718be8SEnji Cooper map_check(map, val); 56657718be8SEnji Cooper 56757718be8SEnji Cooper map = mmap(NULL, page, PROT_READ, flags, -1, 0); 56857718be8SEnji Cooper map_check(map, val); 56957718be8SEnji Cooper 57057718be8SEnji Cooper map = mmap(NULL, page, PROT_WRITE, flags, -1, 0); 57157718be8SEnji Cooper map_check(map, val); 57257718be8SEnji Cooper 57357718be8SEnji Cooper map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0); 57457718be8SEnji Cooper map_check(map, val); 57557718be8SEnji Cooper 57657718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0); 57757718be8SEnji Cooper map_check(map, val); 57857718be8SEnji Cooper } 57957718be8SEnji Cooper 58057718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 58157718be8SEnji Cooper { 58257718be8SEnji Cooper page = sysconf(_SC_PAGESIZE); 58357718be8SEnji Cooper ATF_REQUIRE(page >= 0); 58457718be8SEnji Cooper 58541acfd75SEnji Cooper #ifdef __NetBSD__ 58657718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_block); 58741acfd75SEnji Cooper #endif 58857718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_err); 58957718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_loan); 59057718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_1); 59157718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_2); 59257718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_3); 59357718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate); 594640235e2SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate_signal); 59557718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_va0); 59657718be8SEnji Cooper 59757718be8SEnji Cooper return atf_no_error(); 59857718be8SEnji Cooper } 599