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