1*640235e2SEnji Cooper /* $NetBSD: t_mmap.c,v 1.9 2015/02/28 13:57:08 martin 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> 58*640235e2SEnji Cooper __RCSID("$NetBSD: t_mmap.c,v 1.9 2015/02/28 13:57:08 martin Exp $"); 5957718be8SEnji Cooper 6057718be8SEnji Cooper #include <sys/param.h> 6157718be8SEnji Cooper #include <sys/mman.h> 6257718be8SEnji Cooper #include <sys/socket.h> 6357718be8SEnji Cooper #include <sys/sysctl.h> 6457718be8SEnji Cooper #include <sys/wait.h> 6557718be8SEnji Cooper 6657718be8SEnji Cooper #include <atf-c.h> 6757718be8SEnji Cooper #include <errno.h> 6857718be8SEnji Cooper #include <fcntl.h> 6957718be8SEnji Cooper #include <signal.h> 7057718be8SEnji Cooper #include <stdio.h> 7157718be8SEnji Cooper #include <stdlib.h> 7257718be8SEnji Cooper #include <string.h> 7357718be8SEnji Cooper #include <unistd.h> 7457718be8SEnji Cooper #include <paths.h> 7541acfd75SEnji Cooper #ifdef __NetBSD__ 7657718be8SEnji Cooper #include <machine/disklabel.h> 7741acfd75SEnji Cooper #endif 7841acfd75SEnji Cooper 7941acfd75SEnji Cooper #ifdef __FreeBSD__ 8041acfd75SEnji Cooper #include <sys/disklabel.h> 8141acfd75SEnji Cooper #include <sys/stat.h> 8241acfd75SEnji Cooper #include <stdint.h> 8341acfd75SEnji Cooper #endif 8457718be8SEnji Cooper 8557718be8SEnji Cooper static long page = 0; 8657718be8SEnji Cooper static char path[] = "mmap"; 8757718be8SEnji Cooper static void map_check(void *, int); 8857718be8SEnji Cooper static void map_sighandler(int); 8957718be8SEnji Cooper static void testloan(void *, void *, char, int); 9057718be8SEnji Cooper 9157718be8SEnji Cooper #define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */ 9257718be8SEnji Cooper 9357718be8SEnji Cooper static void 9457718be8SEnji Cooper map_check(void *map, int flag) 9557718be8SEnji Cooper { 9657718be8SEnji Cooper 9757718be8SEnji Cooper if (flag != 0) { 9857718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED); 9957718be8SEnji Cooper return; 10057718be8SEnji Cooper } 10157718be8SEnji Cooper 10257718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 10357718be8SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0); 10457718be8SEnji Cooper } 10557718be8SEnji Cooper 10657718be8SEnji Cooper void 10757718be8SEnji Cooper testloan(void *vp, void *vp2, char pat, int docheck) 10857718be8SEnji Cooper { 10957718be8SEnji Cooper char buf[BUFSIZE]; 11057718be8SEnji Cooper char backup[BUFSIZE]; 11157718be8SEnji Cooper ssize_t nwritten; 11257718be8SEnji Cooper ssize_t nread; 11357718be8SEnji Cooper int fds[2]; 11457718be8SEnji Cooper int val; 11557718be8SEnji Cooper 11657718be8SEnji Cooper val = BUFSIZE; 11757718be8SEnji Cooper 11857718be8SEnji Cooper if (docheck != 0) 11957718be8SEnji Cooper (void)memcpy(backup, vp, BUFSIZE); 12057718be8SEnji Cooper 12157718be8SEnji Cooper if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0) 12257718be8SEnji Cooper atf_tc_fail("socketpair() failed"); 12357718be8SEnji Cooper 12457718be8SEnji Cooper val = BUFSIZE; 12557718be8SEnji Cooper 12657718be8SEnji Cooper if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0) 12757718be8SEnji Cooper atf_tc_fail("setsockopt() failed, SO_RCVBUF"); 12857718be8SEnji Cooper 12957718be8SEnji Cooper val = BUFSIZE; 13057718be8SEnji Cooper 13157718be8SEnji Cooper if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0) 13257718be8SEnji Cooper atf_tc_fail("setsockopt() failed, SO_SNDBUF"); 13357718be8SEnji Cooper 13457718be8SEnji Cooper if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0) 13557718be8SEnji Cooper atf_tc_fail("fcntl() failed"); 13657718be8SEnji Cooper 13757718be8SEnji Cooper nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page); 13857718be8SEnji Cooper 13957718be8SEnji Cooper if (nwritten == -1) 14057718be8SEnji Cooper atf_tc_fail("write() failed"); 14157718be8SEnji Cooper 14257718be8SEnji Cooper /* Break loan. */ 14357718be8SEnji Cooper (void)memset(vp2, pat, BUFSIZE); 14457718be8SEnji Cooper 14557718be8SEnji Cooper nread = read(fds[1], buf + page, BUFSIZE - page); 14657718be8SEnji Cooper 14757718be8SEnji Cooper if (nread == -1) 14857718be8SEnji Cooper atf_tc_fail("read() failed"); 14957718be8SEnji Cooper 15057718be8SEnji Cooper if (nread != nwritten) 15157718be8SEnji Cooper atf_tc_fail("too short read"); 15257718be8SEnji Cooper 15357718be8SEnji Cooper if (docheck != 0 && memcmp(backup, buf + page, nread) != 0) 15457718be8SEnji Cooper atf_tc_fail("data mismatch"); 15557718be8SEnji Cooper 15657718be8SEnji Cooper ATF_REQUIRE(close(fds[0]) == 0); 15757718be8SEnji Cooper ATF_REQUIRE(close(fds[1]) == 0); 15857718be8SEnji Cooper } 15957718be8SEnji Cooper 16057718be8SEnji Cooper static void 16157718be8SEnji Cooper map_sighandler(int signo) 16257718be8SEnji Cooper { 16357718be8SEnji Cooper _exit(signo); 16457718be8SEnji Cooper } 16557718be8SEnji Cooper 16641acfd75SEnji Cooper #ifdef __NetBSD__ 16757718be8SEnji Cooper ATF_TC(mmap_block); 16857718be8SEnji Cooper ATF_TC_HEAD(mmap_block, tc) 16957718be8SEnji Cooper { 17057718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device"); 17157718be8SEnji Cooper atf_tc_set_md_var(tc, "require.user", "root"); 17257718be8SEnji Cooper } 17357718be8SEnji Cooper 17457718be8SEnji Cooper ATF_TC_BODY(mmap_block, tc) 17557718be8SEnji Cooper { 17657718be8SEnji Cooper static const int mib[] = { CTL_HW, HW_DISKNAMES }; 17757718be8SEnji Cooper static const unsigned int miblen = __arraycount(mib); 17857718be8SEnji Cooper char *map, *dk, *drives, dev[PATH_MAX]; 17957718be8SEnji Cooper size_t len; 18057718be8SEnji Cooper int fd = -1; 18157718be8SEnji Cooper 18257718be8SEnji Cooper atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)"); 18357718be8SEnji Cooper 18457718be8SEnji Cooper ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0); 18557718be8SEnji Cooper drives = malloc(len); 18657718be8SEnji Cooper ATF_REQUIRE(drives != NULL); 18757718be8SEnji Cooper ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0); 18857718be8SEnji Cooper for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) { 18957718be8SEnji Cooper sprintf(dev, _PATH_DEV "%s%c", dk, 'a'+RAW_PART); 19057718be8SEnji Cooper fprintf(stderr, "trying: %s\n", dev); 19157718be8SEnji Cooper 19257718be8SEnji Cooper if ((fd = open(dev, O_RDONLY)) >= 0) { 19357718be8SEnji Cooper (void)fprintf(stderr, "using %s\n", dev); 19457718be8SEnji Cooper break; 19557718be8SEnji Cooper } 19657718be8SEnji Cooper } 19757718be8SEnji Cooper free(drives); 19857718be8SEnji Cooper 19957718be8SEnji Cooper if (fd < 0) 20057718be8SEnji Cooper atf_tc_skip("failed to find suitable block device"); 20157718be8SEnji Cooper 20257718be8SEnji Cooper map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0); 20357718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 20457718be8SEnji Cooper 20557718be8SEnji Cooper (void)fprintf(stderr, "first byte %x\n", *map); 20657718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0); 20757718be8SEnji Cooper (void)fprintf(stderr, "first byte %x\n", *map); 20857718be8SEnji Cooper 20957718be8SEnji Cooper ATF_REQUIRE(munmap(map, 4096) == 0); 21057718be8SEnji Cooper } 21141acfd75SEnji Cooper #endif 21257718be8SEnji Cooper 21357718be8SEnji Cooper ATF_TC(mmap_err); 21457718be8SEnji Cooper ATF_TC_HEAD(mmap_err, tc) 21557718be8SEnji Cooper { 21657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)"); 21757718be8SEnji Cooper } 21857718be8SEnji Cooper 21957718be8SEnji Cooper ATF_TC_BODY(mmap_err, tc) 22057718be8SEnji Cooper { 22157718be8SEnji Cooper size_t addr = SIZE_MAX; 22257718be8SEnji Cooper void *map; 22357718be8SEnji Cooper 22457718be8SEnji Cooper errno = 0; 22557718be8SEnji Cooper map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0); 22657718be8SEnji Cooper 22757718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED); 22857718be8SEnji Cooper ATF_REQUIRE(errno == EBADF); 22957718be8SEnji Cooper 23057718be8SEnji Cooper errno = 0; 23157718be8SEnji Cooper map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0); 23257718be8SEnji Cooper 23357718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED); 23457718be8SEnji Cooper ATF_REQUIRE(errno == EINVAL); 23557718be8SEnji Cooper 23657718be8SEnji Cooper errno = 0; 23757718be8SEnji Cooper map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0); 23857718be8SEnji Cooper 23957718be8SEnji Cooper ATF_REQUIRE(map == MAP_FAILED); 24057718be8SEnji Cooper ATF_REQUIRE(errno == EINVAL); 24157718be8SEnji Cooper } 24257718be8SEnji Cooper 24357718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_loan); 24457718be8SEnji Cooper ATF_TC_HEAD(mmap_loan, tc) 24557718be8SEnji Cooper { 24657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)"); 24757718be8SEnji Cooper } 24857718be8SEnji Cooper 24957718be8SEnji Cooper ATF_TC_BODY(mmap_loan, tc) 25057718be8SEnji Cooper { 25157718be8SEnji Cooper char buf[BUFSIZE]; 25257718be8SEnji Cooper char *vp, *vp2; 25357718be8SEnji Cooper int fd; 25457718be8SEnji Cooper 25557718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0600); 25657718be8SEnji Cooper ATF_REQUIRE(fd >= 0); 25757718be8SEnji Cooper 25857718be8SEnji Cooper (void)memset(buf, 'x', sizeof(buf)); 25957718be8SEnji Cooper (void)write(fd, buf, sizeof(buf)); 26057718be8SEnji Cooper 26157718be8SEnji Cooper vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 26257718be8SEnji Cooper MAP_FILE | MAP_PRIVATE, fd, 0); 26357718be8SEnji Cooper 26457718be8SEnji Cooper ATF_REQUIRE(vp != MAP_FAILED); 26557718be8SEnji Cooper 26657718be8SEnji Cooper vp2 = vp; 26757718be8SEnji Cooper 26857718be8SEnji Cooper testloan(vp, vp2, 'A', 0); 26957718be8SEnji Cooper testloan(vp, vp2, 'B', 1); 27057718be8SEnji Cooper 27157718be8SEnji Cooper ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); 27257718be8SEnji Cooper 27357718be8SEnji Cooper vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 27457718be8SEnji Cooper MAP_FILE | MAP_SHARED, fd, 0); 27557718be8SEnji Cooper 27657718be8SEnji Cooper vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 27757718be8SEnji Cooper MAP_FILE | MAP_SHARED, fd, 0); 27857718be8SEnji Cooper 27957718be8SEnji Cooper ATF_REQUIRE(vp != MAP_FAILED); 28057718be8SEnji Cooper ATF_REQUIRE(vp2 != MAP_FAILED); 28157718be8SEnji Cooper 28257718be8SEnji Cooper testloan(vp, vp2, 'E', 1); 28357718be8SEnji Cooper 28457718be8SEnji Cooper ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); 28557718be8SEnji Cooper ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0); 28657718be8SEnji Cooper } 28757718be8SEnji Cooper 28857718be8SEnji Cooper ATF_TC_CLEANUP(mmap_loan, tc) 28957718be8SEnji Cooper { 29057718be8SEnji Cooper (void)unlink(path); 29157718be8SEnji Cooper } 29257718be8SEnji Cooper 29357718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_prot_1); 29457718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_1, tc) 29557718be8SEnji Cooper { 29657718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1"); 29757718be8SEnji Cooper } 29857718be8SEnji Cooper 29957718be8SEnji Cooper ATF_TC_BODY(mmap_prot_1, tc) 30057718be8SEnji Cooper { 30157718be8SEnji Cooper void *map; 30257718be8SEnji Cooper int fd; 30357718be8SEnji Cooper 30457718be8SEnji Cooper /* 30557718be8SEnji Cooper * Open a file write-only and try to 30657718be8SEnji Cooper * map it read-only. This should fail. 30757718be8SEnji Cooper */ 30857718be8SEnji Cooper fd = open(path, O_WRONLY | O_CREAT, 0700); 30957718be8SEnji Cooper 31057718be8SEnji Cooper if (fd < 0) 31157718be8SEnji Cooper return; 31257718be8SEnji Cooper 31357718be8SEnji Cooper ATF_REQUIRE(write(fd, "XXX", 3) == 3); 31457718be8SEnji Cooper 31557718be8SEnji Cooper map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 31657718be8SEnji Cooper map_check(map, 1); 31757718be8SEnji Cooper 31857718be8SEnji Cooper map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0); 31957718be8SEnji Cooper map_check(map, 0); 32057718be8SEnji Cooper 32157718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0); 32257718be8SEnji Cooper } 32357718be8SEnji Cooper 32457718be8SEnji Cooper ATF_TC_CLEANUP(mmap_prot_1, tc) 32557718be8SEnji Cooper { 32657718be8SEnji Cooper (void)unlink(path); 32757718be8SEnji Cooper } 32857718be8SEnji Cooper 32957718be8SEnji Cooper ATF_TC(mmap_prot_2); 33057718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_2, tc) 33157718be8SEnji Cooper { 33257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2"); 33357718be8SEnji Cooper } 33457718be8SEnji Cooper 33557718be8SEnji Cooper ATF_TC_BODY(mmap_prot_2, tc) 33657718be8SEnji Cooper { 33757718be8SEnji Cooper char buf[2]; 33857718be8SEnji Cooper void *map; 33957718be8SEnji Cooper pid_t pid; 34057718be8SEnji Cooper int sta; 34157718be8SEnji Cooper 34257718be8SEnji Cooper /* 34357718be8SEnji Cooper * Make a PROT_NONE mapping and try to access it. 34457718be8SEnji Cooper * If we catch a SIGSEGV, all works as expected. 34557718be8SEnji Cooper */ 34657718be8SEnji Cooper map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); 34757718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 34857718be8SEnji Cooper 34957718be8SEnji Cooper pid = fork(); 35057718be8SEnji Cooper ATF_REQUIRE(pid >= 0); 35157718be8SEnji Cooper 35257718be8SEnji Cooper if (pid == 0) { 35357718be8SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 35457718be8SEnji Cooper ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); 35557718be8SEnji Cooper } 35657718be8SEnji Cooper 35757718be8SEnji Cooper (void)wait(&sta); 35857718be8SEnji Cooper 35957718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0); 36057718be8SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); 36157718be8SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0); 36257718be8SEnji Cooper } 36357718be8SEnji Cooper 36457718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_prot_3); 36557718be8SEnji Cooper ATF_TC_HEAD(mmap_prot_3, tc) 36657718be8SEnji Cooper { 36757718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3"); 36857718be8SEnji Cooper } 36957718be8SEnji Cooper 37057718be8SEnji Cooper ATF_TC_BODY(mmap_prot_3, tc) 37157718be8SEnji Cooper { 37257718be8SEnji Cooper char buf[2]; 37357718be8SEnji Cooper int fd, sta; 37457718be8SEnji Cooper void *map; 37557718be8SEnji Cooper pid_t pid; 37657718be8SEnji Cooper 37757718be8SEnji Cooper /* 37857718be8SEnji Cooper * Open a file, change the permissions 37957718be8SEnji Cooper * to read-only, and try to map it as 38057718be8SEnji Cooper * PROT_NONE. This should succeed, but 38157718be8SEnji Cooper * the access should generate SIGSEGV. 38257718be8SEnji Cooper */ 38357718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700); 38457718be8SEnji Cooper 38557718be8SEnji Cooper if (fd < 0) 38657718be8SEnji Cooper return; 38757718be8SEnji Cooper 38857718be8SEnji Cooper ATF_REQUIRE(write(fd, "XXX", 3) == 3); 38957718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0); 39057718be8SEnji Cooper ATF_REQUIRE(chmod(path, 0444) == 0); 39157718be8SEnji Cooper 39257718be8SEnji Cooper fd = open(path, O_RDONLY); 39357718be8SEnji Cooper ATF_REQUIRE(fd != -1); 39457718be8SEnji Cooper 39557718be8SEnji Cooper map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); 39657718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 39757718be8SEnji Cooper 39857718be8SEnji Cooper pid = fork(); 39957718be8SEnji Cooper 40057718be8SEnji Cooper ATF_REQUIRE(pid >= 0); 40157718be8SEnji Cooper 40257718be8SEnji Cooper if (pid == 0) { 40357718be8SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 40457718be8SEnji Cooper ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); 40557718be8SEnji Cooper } 40657718be8SEnji Cooper 40757718be8SEnji Cooper (void)wait(&sta); 40857718be8SEnji Cooper 40957718be8SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0); 41057718be8SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); 41157718be8SEnji Cooper ATF_REQUIRE(munmap(map, 3) == 0); 41257718be8SEnji Cooper } 41357718be8SEnji Cooper 41457718be8SEnji Cooper ATF_TC_CLEANUP(mmap_prot_3, tc) 41557718be8SEnji Cooper { 41657718be8SEnji Cooper (void)unlink(path); 41757718be8SEnji Cooper } 41857718be8SEnji Cooper 41957718be8SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_truncate); 42057718be8SEnji Cooper ATF_TC_HEAD(mmap_truncate, tc) 42157718be8SEnji Cooper { 42257718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)"); 42357718be8SEnji Cooper } 42457718be8SEnji Cooper 42557718be8SEnji Cooper ATF_TC_BODY(mmap_truncate, tc) 42657718be8SEnji Cooper { 42757718be8SEnji Cooper char *map; 42857718be8SEnji Cooper long i; 42957718be8SEnji Cooper int fd; 43057718be8SEnji Cooper 43157718be8SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700); 43257718be8SEnji Cooper 43357718be8SEnji Cooper if (fd < 0) 43457718be8SEnji Cooper return; 43557718be8SEnji Cooper 43657718be8SEnji Cooper /* 43757718be8SEnji Cooper * See that ftruncate(2) works 43857718be8SEnji Cooper * while the file is mapped. 43957718be8SEnji Cooper */ 44057718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page) == 0); 44157718be8SEnji Cooper 44257718be8SEnji Cooper map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 44357718be8SEnji Cooper fd, 0); 44457718be8SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 44557718be8SEnji Cooper 44657718be8SEnji Cooper for (i = 0; i < page; i++) 44757718be8SEnji Cooper map[i] = 'x'; 44857718be8SEnji Cooper 44957718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, 0) == 0); 45057718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 8) == 0); 45157718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 4) == 0); 45257718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 2) == 0); 45357718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 12) == 0); 45457718be8SEnji Cooper ATF_REQUIRE(ftruncate(fd, page / 64) == 0); 45557718be8SEnji Cooper 45657718be8SEnji Cooper ATF_REQUIRE(close(fd) == 0); 45757718be8SEnji Cooper } 45857718be8SEnji Cooper 45957718be8SEnji Cooper ATF_TC_CLEANUP(mmap_truncate, tc) 46057718be8SEnji Cooper { 46157718be8SEnji Cooper (void)unlink(path); 46257718be8SEnji Cooper } 46357718be8SEnji Cooper 464*640235e2SEnji Cooper ATF_TC_WITH_CLEANUP(mmap_truncate_signal); 465*640235e2SEnji Cooper ATF_TC_HEAD(mmap_truncate_signal, tc) 466*640235e2SEnji Cooper { 467*640235e2SEnji Cooper atf_tc_set_md_var(tc, "descr", 468*640235e2SEnji Cooper "Test mmap(2) ftruncate(2) causing signal"); 469*640235e2SEnji Cooper } 470*640235e2SEnji Cooper 471*640235e2SEnji Cooper ATF_TC_BODY(mmap_truncate_signal, tc) 472*640235e2SEnji Cooper { 473*640235e2SEnji Cooper char *map; 474*640235e2SEnji Cooper long i; 475*640235e2SEnji Cooper int fd, sta; 476*640235e2SEnji Cooper pid_t pid; 477*640235e2SEnji Cooper 478*640235e2SEnji Cooper fd = open(path, O_RDWR | O_CREAT, 0700); 479*640235e2SEnji Cooper 480*640235e2SEnji Cooper if (fd < 0) 481*640235e2SEnji Cooper return; 482*640235e2SEnji Cooper 483*640235e2SEnji Cooper ATF_REQUIRE(write(fd, "foo\n", 5) == 5); 484*640235e2SEnji Cooper 485*640235e2SEnji Cooper map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 486*640235e2SEnji Cooper ATF_REQUIRE(map != MAP_FAILED); 487*640235e2SEnji Cooper 488*640235e2SEnji Cooper sta = 0; 489*640235e2SEnji Cooper for (i = 0; i < 5; i++) 490*640235e2SEnji Cooper sta += map[i]; 491*640235e2SEnji Cooper ATF_REQUIRE(sta == 334); 492*640235e2SEnji Cooper 493*640235e2SEnji Cooper ATF_REQUIRE(ftruncate(fd, 0) == 0); 494*640235e2SEnji Cooper pid = fork(); 495*640235e2SEnji Cooper ATF_REQUIRE(pid >= 0); 496*640235e2SEnji Cooper 497*640235e2SEnji Cooper if (pid == 0) { 498*640235e2SEnji Cooper ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR); 499*640235e2SEnji Cooper ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 500*640235e2SEnji Cooper sta = 0; 501*640235e2SEnji Cooper for (i = 0; i < page; i++) 502*640235e2SEnji Cooper sta += map[i]; 503*640235e2SEnji Cooper /* child never will get this far, but the compiler will 504*640235e2SEnji Cooper not know, so better use the values calculated to 505*640235e2SEnji Cooper prevent the access to be optimized out */ 506*640235e2SEnji Cooper ATF_REQUIRE(i == 0); 507*640235e2SEnji Cooper ATF_REQUIRE(sta == 0); 508*640235e2SEnji Cooper return; 509*640235e2SEnji Cooper } 510*640235e2SEnji Cooper 511*640235e2SEnji Cooper (void)wait(&sta); 512*640235e2SEnji Cooper 513*640235e2SEnji Cooper ATF_REQUIRE(WIFEXITED(sta) != 0); 514*640235e2SEnji Cooper if (WEXITSTATUS(sta) == SIGSEGV) 515*640235e2SEnji Cooper atf_tc_fail("child process got SIGSEGV instead of SIGBUS"); 516*640235e2SEnji Cooper ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS); 517*640235e2SEnji Cooper ATF_REQUIRE(munmap(map, page) == 0); 518*640235e2SEnji Cooper ATF_REQUIRE(close(fd) == 0); 519*640235e2SEnji Cooper } 520*640235e2SEnji Cooper 521*640235e2SEnji Cooper ATF_TC_CLEANUP(mmap_truncate_signal, tc) 522*640235e2SEnji Cooper { 523*640235e2SEnji Cooper (void)unlink(path); 524*640235e2SEnji Cooper } 525*640235e2SEnji Cooper 52657718be8SEnji Cooper ATF_TC(mmap_va0); 52757718be8SEnji Cooper ATF_TC_HEAD(mmap_va0, tc) 52857718be8SEnji Cooper { 52957718be8SEnji Cooper atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable"); 53057718be8SEnji Cooper } 53157718be8SEnji Cooper 53257718be8SEnji Cooper ATF_TC_BODY(mmap_va0, tc) 53357718be8SEnji Cooper { 53457718be8SEnji Cooper int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE; 53557718be8SEnji Cooper size_t len = sizeof(int); 53657718be8SEnji Cooper void *map; 53757718be8SEnji Cooper int val; 53857718be8SEnji Cooper 53957718be8SEnji Cooper /* 54057718be8SEnji Cooper * Make an anonymous fixed mapping at zero address. If the address 54157718be8SEnji Cooper * is restricted as noted in security(7), the syscall should fail. 54257718be8SEnji Cooper */ 54341acfd75SEnji Cooper #ifdef __FreeBSD__ 54441acfd75SEnji Cooper if (sysctlbyname("security.bsd.map_at_zero", &val, &len, NULL, 0) != 0) 54541acfd75SEnji Cooper atf_tc_fail("failed to read security.bsd.map_at_zero"); 54641acfd75SEnji Cooper val = !val; /* 1 == enable map at zero */ 54741acfd75SEnji Cooper #endif 54841acfd75SEnji Cooper #ifdef __NetBSD__ 54957718be8SEnji Cooper if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0) 55057718be8SEnji Cooper atf_tc_fail("failed to read vm.user_va0_disable"); 55141acfd75SEnji Cooper #endif 55257718be8SEnji Cooper 55357718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC, flags, -1, 0); 55457718be8SEnji Cooper map_check(map, val); 55557718be8SEnji Cooper 55657718be8SEnji Cooper map = mmap(NULL, page, PROT_READ, flags, -1, 0); 55757718be8SEnji Cooper map_check(map, val); 55857718be8SEnji Cooper 55957718be8SEnji Cooper map = mmap(NULL, page, PROT_WRITE, flags, -1, 0); 56057718be8SEnji Cooper map_check(map, val); 56157718be8SEnji Cooper 56257718be8SEnji Cooper map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0); 56357718be8SEnji Cooper map_check(map, val); 56457718be8SEnji Cooper 56557718be8SEnji Cooper map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0); 56657718be8SEnji Cooper map_check(map, val); 56757718be8SEnji Cooper } 56857718be8SEnji Cooper 56957718be8SEnji Cooper ATF_TP_ADD_TCS(tp) 57057718be8SEnji Cooper { 57157718be8SEnji Cooper page = sysconf(_SC_PAGESIZE); 57257718be8SEnji Cooper ATF_REQUIRE(page >= 0); 57357718be8SEnji Cooper 57441acfd75SEnji Cooper #ifdef __NetBSD__ 57557718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_block); 57641acfd75SEnji Cooper #endif 57757718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_err); 57857718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_loan); 57957718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_1); 58057718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_2); 58157718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_prot_3); 58257718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate); 583*640235e2SEnji Cooper ATF_TP_ADD_TC(tp, mmap_truncate_signal); 58457718be8SEnji Cooper ATF_TP_ADD_TC(tp, mmap_va0); 58557718be8SEnji Cooper 58657718be8SEnji Cooper return atf_no_error(); 58757718be8SEnji Cooper } 588