Home | History | Annotate | Line # | Download | only in sys
t_mmap.c revision 1.17
      1  1.17      gson /* $NetBSD: t_mmap.c,v 1.17 2022/04/06 10:02:55 gson 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.17      gson __RCSID("$NetBSD: t_mmap.c,v 1.17 2022/04/06 10:02:55 gson 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.17      gson #include <pthread.h>
     78   1.1    jruoho 
     79   1.1    jruoho static long	page = 0;
     80   1.1    jruoho static char	path[] = "mmap";
     81   1.1    jruoho static void	map_check(void *, int);
     82   1.1    jruoho static void	map_sighandler(int);
     83   1.2    jruoho static void	testloan(void *, void *, char, int);
     84   1.2    jruoho 
     85   1.2    jruoho #define	BUFSIZE	(32 * 1024)	/* enough size to trigger sosend_loan */
     86   1.1    jruoho 
     87   1.1    jruoho static void
     88   1.1    jruoho map_check(void *map, int flag)
     89   1.1    jruoho {
     90   1.1    jruoho 
     91   1.1    jruoho 	if (flag != 0) {
     92   1.1    jruoho 		ATF_REQUIRE(map == MAP_FAILED);
     93   1.1    jruoho 		return;
     94   1.1    jruoho 	}
     95   1.1    jruoho 
     96   1.1    jruoho 	ATF_REQUIRE(map != MAP_FAILED);
     97   1.1    jruoho 	ATF_REQUIRE(munmap(map, page) == 0);
     98   1.1    jruoho }
     99   1.1    jruoho 
    100   1.2    jruoho void
    101   1.2    jruoho testloan(void *vp, void *vp2, char pat, int docheck)
    102   1.2    jruoho {
    103   1.2    jruoho 	char buf[BUFSIZE];
    104   1.2    jruoho 	char backup[BUFSIZE];
    105   1.2    jruoho 	ssize_t nwritten;
    106   1.2    jruoho 	ssize_t nread;
    107   1.2    jruoho 	int fds[2];
    108   1.2    jruoho 	int val;
    109   1.2    jruoho 
    110   1.2    jruoho 	val = BUFSIZE;
    111   1.2    jruoho 
    112   1.2    jruoho 	if (docheck != 0)
    113   1.2    jruoho 		(void)memcpy(backup, vp, BUFSIZE);
    114   1.2    jruoho 
    115   1.2    jruoho 	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0)
    116   1.2    jruoho 		atf_tc_fail("socketpair() failed");
    117   1.2    jruoho 
    118   1.2    jruoho 	val = BUFSIZE;
    119   1.2    jruoho 
    120   1.2    jruoho 	if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
    121   1.2    jruoho 		atf_tc_fail("setsockopt() failed, SO_RCVBUF");
    122   1.2    jruoho 
    123   1.2    jruoho 	val = BUFSIZE;
    124   1.2    jruoho 
    125   1.2    jruoho 	if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
    126   1.2    jruoho 		atf_tc_fail("setsockopt() failed, SO_SNDBUF");
    127   1.2    jruoho 
    128   1.2    jruoho 	if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0)
    129   1.2    jruoho 		atf_tc_fail("fcntl() failed");
    130   1.2    jruoho 
    131   1.2    jruoho 	nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page);
    132   1.2    jruoho 
    133   1.2    jruoho 	if (nwritten == -1)
    134   1.2    jruoho 		atf_tc_fail("write() failed");
    135   1.2    jruoho 
    136   1.2    jruoho 	/* Break loan. */
    137   1.2    jruoho 	(void)memset(vp2, pat, BUFSIZE);
    138   1.2    jruoho 
    139   1.2    jruoho 	nread = read(fds[1], buf + page, BUFSIZE - page);
    140   1.2    jruoho 
    141   1.2    jruoho 	if (nread == -1)
    142   1.2    jruoho 		atf_tc_fail("read() failed");
    143   1.2    jruoho 
    144   1.2    jruoho 	if (nread != nwritten)
    145   1.2    jruoho 		atf_tc_fail("too short read");
    146   1.2    jruoho 
    147   1.2    jruoho 	if (docheck != 0 && memcmp(backup, buf + page, nread) != 0)
    148   1.2    jruoho 		atf_tc_fail("data mismatch");
    149   1.2    jruoho 
    150   1.2    jruoho 	ATF_REQUIRE(close(fds[0]) == 0);
    151   1.2    jruoho 	ATF_REQUIRE(close(fds[1]) == 0);
    152   1.2    jruoho }
    153   1.2    jruoho 
    154   1.1    jruoho static void
    155   1.1    jruoho map_sighandler(int signo)
    156   1.1    jruoho {
    157   1.1    jruoho 	_exit(signo);
    158   1.1    jruoho }
    159   1.1    jruoho 
    160   1.3    jruoho ATF_TC(mmap_block);
    161   1.3    jruoho ATF_TC_HEAD(mmap_block, tc)
    162   1.3    jruoho {
    163   1.3    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device");
    164   1.5    martin 	atf_tc_set_md_var(tc, "require.user", "root");
    165   1.3    jruoho }
    166   1.3    jruoho 
    167   1.3    jruoho ATF_TC_BODY(mmap_block, tc)
    168   1.3    jruoho {
    169   1.5    martin 	static const int mib[] = { CTL_HW, HW_DISKNAMES };
    170   1.5    martin 	static const unsigned int miblen = __arraycount(mib);
    171   1.5    martin 	char *map, *dk, *drives, dev[PATH_MAX];
    172   1.5    martin 	size_t len;
    173   1.5    martin 	int fd = -1;
    174   1.3    jruoho 
    175  1.14    jruoho 	atf_tc_skip("The test case causes a panic " \
    176  1.14    jruoho 	    "(PR kern/38889, PR kern/46592)");
    177   1.3    jruoho 
    178   1.5    martin 	ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0);
    179   1.5    martin 	drives = malloc(len);
    180   1.5    martin 	ATF_REQUIRE(drives != NULL);
    181   1.5    martin 	ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0);
    182   1.5    martin 	for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) {
    183  1.13  christos 		if (strncmp(dk, "dk", 2) == 0)
    184  1.13  christos 			snprintf(dev, sizeof(dev), _PATH_DEV "%s", dk);
    185  1.13  christos 		else
    186  1.13  christos 			snprintf(dev, sizeof(dev), _PATH_DEV "%s%c", dk,
    187  1.13  christos 			    'a' + RAW_PART);
    188   1.5    martin 		fprintf(stderr, "trying: %s\n", dev);
    189   1.3    jruoho 
    190   1.5    martin 		if ((fd = open(dev, O_RDONLY)) >= 0) {
    191   1.5    martin 			(void)fprintf(stderr, "using %s\n", dev);
    192   1.3    jruoho 			break;
    193  1.13  christos 		} else
    194  1.13  christos 			(void)fprintf(stderr, "%s: %s\n", dev, strerror(errno));
    195   1.3    jruoho 	}
    196   1.5    martin 	free(drives);
    197   1.3    jruoho 
    198   1.5    martin 	if (fd < 0)
    199   1.4    jruoho 		atf_tc_skip("failed to find suitable block device");
    200   1.3    jruoho 
    201   1.3    jruoho 	map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0);
    202  1.13  christos 	ATF_REQUIRE_MSG(map != MAP_FAILED, "mmap: %s", strerror(errno));
    203   1.3    jruoho 
    204   1.3    jruoho 	(void)fprintf(stderr, "first byte %x\n", *map);
    205   1.3    jruoho 	ATF_REQUIRE(close(fd) == 0);
    206   1.3    jruoho 	(void)fprintf(stderr, "first byte %x\n", *map);
    207   1.3    jruoho 
    208   1.3    jruoho 	ATF_REQUIRE(munmap(map, 4096) == 0);
    209   1.3    jruoho }
    210   1.3    jruoho 
    211   1.1    jruoho ATF_TC(mmap_err);
    212   1.1    jruoho ATF_TC_HEAD(mmap_err, tc)
    213   1.1    jruoho {
    214   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)");
    215   1.1    jruoho }
    216   1.1    jruoho 
    217   1.1    jruoho ATF_TC_BODY(mmap_err, tc)
    218   1.1    jruoho {
    219  1.16      gson 	void *addr = (void *)-1;
    220   1.1    jruoho 	void *map;
    221   1.1    jruoho 
    222   1.1    jruoho 	errno = 0;
    223   1.1    jruoho 	map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0);
    224   1.1    jruoho 
    225   1.1    jruoho 	ATF_REQUIRE(map == MAP_FAILED);
    226   1.1    jruoho 	ATF_REQUIRE(errno == EBADF);
    227   1.1    jruoho 
    228   1.1    jruoho 	errno = 0;
    229  1.16      gson 	map = mmap(addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0);
    230   1.1    jruoho 
    231   1.1    jruoho 	ATF_REQUIRE(map == MAP_FAILED);
    232  1.15      gson 	ATF_REQUIRE_MSG(errno == EINVAL, "errno %d != EINVAL", errno);
    233   1.1    jruoho 
    234   1.1    jruoho 	errno = 0;
    235   1.1    jruoho 	map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0);
    236   1.1    jruoho 
    237   1.1    jruoho 	ATF_REQUIRE(map == MAP_FAILED);
    238   1.1    jruoho 	ATF_REQUIRE(errno == EINVAL);
    239   1.1    jruoho }
    240   1.1    jruoho 
    241   1.2    jruoho ATF_TC_WITH_CLEANUP(mmap_loan);
    242   1.2    jruoho ATF_TC_HEAD(mmap_loan, tc)
    243   1.2    jruoho {
    244   1.2    jruoho 	atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)");
    245   1.2    jruoho }
    246   1.2    jruoho 
    247   1.2    jruoho ATF_TC_BODY(mmap_loan, tc)
    248   1.2    jruoho {
    249   1.2    jruoho 	char buf[BUFSIZE];
    250   1.2    jruoho 	char *vp, *vp2;
    251   1.2    jruoho 	int fd;
    252   1.2    jruoho 
    253   1.2    jruoho 	fd = open(path, O_RDWR | O_CREAT, 0600);
    254   1.2    jruoho 	ATF_REQUIRE(fd >= 0);
    255   1.2    jruoho 
    256   1.2    jruoho 	(void)memset(buf, 'x', sizeof(buf));
    257   1.2    jruoho 	(void)write(fd, buf, sizeof(buf));
    258   1.2    jruoho 
    259   1.2    jruoho 	vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
    260   1.2    jruoho 	    MAP_FILE | MAP_PRIVATE, fd, 0);
    261   1.2    jruoho 
    262   1.2    jruoho 	ATF_REQUIRE(vp != MAP_FAILED);
    263   1.2    jruoho 
    264   1.2    jruoho 	vp2 = vp;
    265   1.2    jruoho 
    266   1.2    jruoho 	testloan(vp, vp2, 'A', 0);
    267   1.2    jruoho 	testloan(vp, vp2, 'B', 1);
    268   1.2    jruoho 
    269   1.2    jruoho 	ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
    270   1.2    jruoho 
    271   1.2    jruoho 	vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
    272   1.2    jruoho 	    MAP_FILE | MAP_SHARED, fd, 0);
    273   1.2    jruoho 
    274   1.2    jruoho 	vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
    275   1.2    jruoho 	    MAP_FILE | MAP_SHARED, fd, 0);
    276   1.2    jruoho 
    277   1.2    jruoho 	ATF_REQUIRE(vp != MAP_FAILED);
    278   1.2    jruoho 	ATF_REQUIRE(vp2 != MAP_FAILED);
    279   1.2    jruoho 
    280   1.2    jruoho 	testloan(vp, vp2, 'E', 1);
    281   1.2    jruoho 
    282   1.2    jruoho 	ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
    283   1.2    jruoho 	ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0);
    284   1.2    jruoho }
    285   1.2    jruoho 
    286   1.2    jruoho ATF_TC_CLEANUP(mmap_loan, tc)
    287   1.2    jruoho {
    288   1.2    jruoho 	(void)unlink(path);
    289   1.2    jruoho }
    290   1.2    jruoho 
    291   1.1    jruoho ATF_TC_WITH_CLEANUP(mmap_prot_1);
    292   1.1    jruoho ATF_TC_HEAD(mmap_prot_1, tc)
    293   1.1    jruoho {
    294   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1");
    295   1.1    jruoho }
    296   1.1    jruoho 
    297   1.1    jruoho ATF_TC_BODY(mmap_prot_1, tc)
    298   1.1    jruoho {
    299   1.1    jruoho 	void *map;
    300   1.1    jruoho 	int fd;
    301   1.1    jruoho 
    302   1.1    jruoho 	/*
    303   1.1    jruoho 	 * Open a file write-only and try to
    304   1.1    jruoho 	 * map it read-only. This should fail.
    305   1.1    jruoho 	 */
    306   1.1    jruoho 	fd = open(path, O_WRONLY | O_CREAT, 0700);
    307   1.1    jruoho 
    308   1.1    jruoho 	if (fd < 0)
    309   1.1    jruoho 		return;
    310   1.1    jruoho 
    311   1.1    jruoho 	ATF_REQUIRE(write(fd, "XXX", 3) == 3);
    312   1.1    jruoho 
    313   1.1    jruoho 	map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
    314   1.1    jruoho 	map_check(map, 1);
    315   1.1    jruoho 
    316   1.1    jruoho 	map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
    317   1.1    jruoho 	map_check(map, 0);
    318   1.1    jruoho 
    319   1.1    jruoho 	ATF_REQUIRE(close(fd) == 0);
    320   1.1    jruoho }
    321   1.1    jruoho 
    322   1.1    jruoho ATF_TC_CLEANUP(mmap_prot_1, tc)
    323   1.1    jruoho {
    324   1.1    jruoho 	(void)unlink(path);
    325   1.1    jruoho }
    326   1.1    jruoho 
    327   1.1    jruoho ATF_TC(mmap_prot_2);
    328   1.1    jruoho ATF_TC_HEAD(mmap_prot_2, tc)
    329   1.1    jruoho {
    330   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2");
    331   1.1    jruoho }
    332   1.1    jruoho 
    333   1.1    jruoho ATF_TC_BODY(mmap_prot_2, tc)
    334   1.1    jruoho {
    335   1.1    jruoho 	char buf[2];
    336   1.1    jruoho 	void *map;
    337   1.1    jruoho 	pid_t pid;
    338   1.1    jruoho 	int sta;
    339   1.1    jruoho 
    340   1.1    jruoho 	/*
    341   1.1    jruoho 	 * Make a PROT_NONE mapping and try to access it.
    342   1.1    jruoho 	 * If we catch a SIGSEGV, all works as expected.
    343   1.1    jruoho 	 */
    344   1.1    jruoho 	map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
    345   1.1    jruoho 	ATF_REQUIRE(map != MAP_FAILED);
    346   1.1    jruoho 
    347   1.1    jruoho 	pid = fork();
    348   1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    349   1.1    jruoho 
    350   1.1    jruoho 	if (pid == 0) {
    351   1.1    jruoho 		ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
    352   1.1    jruoho 		ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
    353   1.1    jruoho 	}
    354   1.1    jruoho 
    355   1.1    jruoho 	(void)wait(&sta);
    356   1.1    jruoho 
    357   1.1    jruoho 	ATF_REQUIRE(WIFEXITED(sta) != 0);
    358   1.1    jruoho 	ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
    359   1.1    jruoho 	ATF_REQUIRE(munmap(map, page) == 0);
    360   1.1    jruoho }
    361   1.1    jruoho 
    362   1.1    jruoho ATF_TC_WITH_CLEANUP(mmap_prot_3);
    363   1.1    jruoho ATF_TC_HEAD(mmap_prot_3, tc)
    364   1.1    jruoho {
    365   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3");
    366   1.1    jruoho }
    367   1.1    jruoho 
    368   1.1    jruoho ATF_TC_BODY(mmap_prot_3, tc)
    369   1.1    jruoho {
    370   1.1    jruoho 	char buf[2];
    371   1.1    jruoho 	int fd, sta;
    372   1.1    jruoho 	void *map;
    373   1.1    jruoho 	pid_t pid;
    374   1.1    jruoho 
    375   1.1    jruoho 	/*
    376   1.1    jruoho 	 * Open a file, change the permissions
    377   1.1    jruoho 	 * to read-only, and try to map it as
    378   1.1    jruoho 	 * PROT_NONE. This should succeed, but
    379   1.1    jruoho 	 * the access should generate SIGSEGV.
    380   1.1    jruoho 	 */
    381   1.1    jruoho 	fd = open(path, O_RDWR | O_CREAT, 0700);
    382   1.1    jruoho 
    383   1.1    jruoho 	if (fd < 0)
    384   1.1    jruoho 		return;
    385   1.1    jruoho 
    386   1.1    jruoho 	ATF_REQUIRE(write(fd, "XXX", 3) == 3);
    387   1.1    jruoho 	ATF_REQUIRE(close(fd) == 0);
    388   1.1    jruoho 	ATF_REQUIRE(chmod(path, 0444) == 0);
    389   1.1    jruoho 
    390   1.1    jruoho 	fd = open(path, O_RDONLY);
    391   1.1    jruoho 	ATF_REQUIRE(fd != -1);
    392   1.1    jruoho 
    393   1.1    jruoho 	map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0);
    394   1.1    jruoho 	ATF_REQUIRE(map != MAP_FAILED);
    395   1.1    jruoho 
    396   1.1    jruoho 	pid = fork();
    397   1.1    jruoho 
    398   1.1    jruoho 	ATF_REQUIRE(pid >= 0);
    399   1.1    jruoho 
    400   1.1    jruoho 	if (pid == 0) {
    401   1.1    jruoho 		ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
    402   1.1    jruoho 		ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
    403   1.1    jruoho 	}
    404   1.1    jruoho 
    405   1.1    jruoho 	(void)wait(&sta);
    406   1.1    jruoho 
    407   1.1    jruoho 	ATF_REQUIRE(WIFEXITED(sta) != 0);
    408   1.1    jruoho 	ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
    409   1.1    jruoho 	ATF_REQUIRE(munmap(map, 3) == 0);
    410   1.1    jruoho }
    411   1.1    jruoho 
    412   1.1    jruoho ATF_TC_CLEANUP(mmap_prot_3, tc)
    413   1.1    jruoho {
    414   1.1    jruoho 	(void)unlink(path);
    415   1.1    jruoho }
    416   1.1    jruoho 
    417  1.17      gson ATF_TC(mmap_reprotect_race);
    418  1.17      gson 
    419  1.17      gson ATF_TC_HEAD(mmap_reprotect_race, tc)
    420  1.17      gson {
    421  1.17      gson 	atf_tc_set_md_var(tc, "descr", "Test for the race condition of PR 52239");
    422  1.17      gson }
    423  1.17      gson 
    424  1.17      gson const int mmap_reprotect_race_npages = 13;
    425  1.17      gson const int mmap_reprotect_iterations = 1000000;
    426  1.17      gson 
    427  1.17      gson static void *
    428  1.17      gson mmap_reprotect_race_thread(void *arg)
    429  1.17      gson {
    430  1.17      gson 	int i, r;
    431  1.17      gson 	void *p;
    432  1.17      gson 
    433  1.17      gson 	for (i = 0; i < mmap_reprotect_iterations; i++) {
    434  1.17      gson 		/* Get some unrelated memory */
    435  1.17      gson 		p = mmap(0, mmap_reprotect_race_npages * page,
    436  1.17      gson 			 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    437  1.17      gson 		ATF_REQUIRE(p);
    438  1.17      gson 		r = munmap(p, mmap_reprotect_race_npages * page);
    439  1.17      gson 		ATF_REQUIRE(r == 0);
    440  1.17      gson 	}
    441  1.17      gson 	return 0;
    442  1.17      gson }
    443  1.17      gson 
    444  1.17      gson ATF_TC_BODY(mmap_reprotect_race, tc)
    445  1.17      gson {
    446  1.17      gson 	pthread_t thread;
    447  1.17      gson 	void *p, *q;
    448  1.17      gson 	int i, r;
    449  1.17      gson 
    450  1.17      gson 	r = pthread_create(&thread, 0, mmap_reprotect_race_thread, 0);
    451  1.17      gson 	ATF_REQUIRE(r == 0);
    452  1.17      gson 
    453  1.17      gson 	for (i = 0; i < mmap_reprotect_iterations; i++) {
    454  1.17      gson 		/* Get a placeholder region */
    455  1.17      gson 		p = mmap(0, mmap_reprotect_race_npages * page,
    456  1.17      gson 			 PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
    457  1.17      gson 		if (p == MAP_FAILED)
    458  1.17      gson 			atf_tc_fail("mmap: %s", strerror(errno));
    459  1.17      gson 
    460  1.17      gson 		/* Upgrade placeholder to read/write access */
    461  1.17      gson 		q = mmap(p, mmap_reprotect_race_npages * page,
    462  1.17      gson 			 PROT_READ|PROT_WRITE,
    463  1.17      gson 			 MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
    464  1.17      gson 		if (q == MAP_FAILED)
    465  1.17      gson 			atf_tc_fail("update mmap: %s", strerror(errno));
    466  1.17      gson 		ATF_REQUIRE(q == p);
    467  1.17      gson 
    468  1.17      gson 		/* Free it */
    469  1.17      gson 		r = munmap(q, mmap_reprotect_race_npages * page);
    470  1.17      gson 		if (r != 0)
    471  1.17      gson 			atf_tc_fail("munmap: %s", strerror(errno));
    472  1.17      gson 	}
    473  1.17      gson 	pthread_join(thread, NULL);
    474  1.17      gson }
    475  1.17      gson 
    476   1.1    jruoho ATF_TC_WITH_CLEANUP(mmap_truncate);
    477   1.1    jruoho ATF_TC_HEAD(mmap_truncate, tc)
    478   1.1    jruoho {
    479   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)");
    480   1.1    jruoho }
    481   1.1    jruoho 
    482   1.1    jruoho ATF_TC_BODY(mmap_truncate, tc)
    483   1.1    jruoho {
    484   1.1    jruoho 	char *map;
    485   1.1    jruoho 	long i;
    486   1.1    jruoho 	int fd;
    487   1.1    jruoho 
    488   1.1    jruoho 	fd = open(path, O_RDWR | O_CREAT, 0700);
    489   1.1    jruoho 
    490   1.1    jruoho 	if (fd < 0)
    491   1.1    jruoho 		return;
    492   1.1    jruoho 
    493   1.1    jruoho 	/*
    494   1.1    jruoho 	 * See that ftruncate(2) works
    495   1.1    jruoho 	 * while the file is mapped.
    496   1.1    jruoho 	 */
    497   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page) == 0);
    498   1.1    jruoho 
    499   1.1    jruoho 	map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE,
    500   1.1    jruoho 	     fd, 0);
    501   1.1    jruoho 	ATF_REQUIRE(map != MAP_FAILED);
    502   1.1    jruoho 
    503   1.1    jruoho 	for (i = 0; i < page; i++)
    504   1.1    jruoho 		map[i] = 'x';
    505   1.1    jruoho 
    506   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, 0) == 0);
    507   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page / 8) == 0);
    508   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page / 4) == 0);
    509   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page / 2) == 0);
    510   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page / 12) == 0);
    511   1.1    jruoho 	ATF_REQUIRE(ftruncate(fd, page / 64) == 0);
    512   1.1    jruoho 
    513  1.11  christos 	(void)munmap(map, page);
    514   1.1    jruoho 	ATF_REQUIRE(close(fd) == 0);
    515   1.1    jruoho }
    516   1.1    jruoho 
    517   1.1    jruoho ATF_TC_CLEANUP(mmap_truncate, tc)
    518   1.1    jruoho {
    519   1.1    jruoho 	(void)unlink(path);
    520   1.1    jruoho }
    521   1.1    jruoho 
    522   1.8  christos ATF_TC_WITH_CLEANUP(mmap_truncate_signal);
    523   1.8  christos ATF_TC_HEAD(mmap_truncate_signal, tc)
    524   1.8  christos {
    525   1.8  christos 	atf_tc_set_md_var(tc, "descr",
    526   1.8  christos 	    "Test mmap(2) ftruncate(2) causing signal");
    527   1.8  christos }
    528   1.8  christos 
    529   1.8  christos ATF_TC_BODY(mmap_truncate_signal, tc)
    530   1.8  christos {
    531   1.8  christos 	char *map;
    532   1.8  christos 	long i;
    533   1.8  christos 	int fd, sta;
    534   1.8  christos 	pid_t pid;
    535   1.8  christos 
    536   1.8  christos 	fd = open(path, O_RDWR | O_CREAT, 0700);
    537   1.8  christos 
    538   1.8  christos 	if (fd < 0)
    539   1.8  christos 		return;
    540   1.8  christos 
    541   1.8  christos 	ATF_REQUIRE(write(fd, "foo\n", 5) == 5);
    542   1.8  christos 
    543   1.8  christos 	map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
    544   1.8  christos 	ATF_REQUIRE(map != MAP_FAILED);
    545   1.8  christos 
    546   1.8  christos 	sta = 0;
    547   1.8  christos 	for (i = 0; i < 5; i++)
    548   1.8  christos 		sta += map[i];
    549   1.8  christos 	ATF_REQUIRE(sta == 334);
    550   1.8  christos 
    551   1.8  christos 	ATF_REQUIRE(ftruncate(fd, 0) == 0);
    552   1.8  christos 	pid = fork();
    553   1.8  christos 	ATF_REQUIRE(pid >= 0);
    554   1.8  christos 
    555   1.8  christos 	if (pid == 0) {
    556   1.8  christos 		ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR);
    557   1.9    martin 		ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
    558   1.8  christos 		sta = 0;
    559   1.8  christos 		for (i = 0; i < page; i++)
    560   1.8  christos 			sta += map[i];
    561   1.9    martin 		/* child never will get this far, but the compiler will
    562   1.9    martin 		   not know, so better use the values calculated to
    563   1.9    martin 		   prevent the access to be optimized out */
    564   1.8  christos 		ATF_REQUIRE(i == 0);
    565   1.9    martin 		ATF_REQUIRE(sta == 0);
    566  1.11  christos 		(void)munmap(map, page);
    567  1.11  christos 		(void)close(fd);
    568   1.9    martin 		return;
    569   1.8  christos 	}
    570   1.8  christos 
    571   1.8  christos 	(void)wait(&sta);
    572   1.8  christos 
    573   1.8  christos 	ATF_REQUIRE(WIFEXITED(sta) != 0);
    574   1.9    martin 	if (WEXITSTATUS(sta) == SIGSEGV)
    575   1.9    martin 		atf_tc_fail("child process got SIGSEGV instead of SIGBUS");
    576   1.8  christos 	ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS);
    577   1.8  christos 	ATF_REQUIRE(munmap(map, page) == 0);
    578   1.8  christos 	ATF_REQUIRE(close(fd) == 0);
    579   1.8  christos }
    580   1.8  christos 
    581   1.8  christos ATF_TC_CLEANUP(mmap_truncate_signal, tc)
    582   1.8  christos {
    583   1.8  christos 	(void)unlink(path);
    584   1.8  christos }
    585   1.8  christos 
    586   1.1    jruoho ATF_TC(mmap_va0);
    587   1.1    jruoho ATF_TC_HEAD(mmap_va0, tc)
    588   1.1    jruoho {
    589   1.1    jruoho 	atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable");
    590   1.1    jruoho }
    591   1.1    jruoho 
    592   1.1    jruoho ATF_TC_BODY(mmap_va0, tc)
    593   1.1    jruoho {
    594   1.1    jruoho 	int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE;
    595   1.1    jruoho 	size_t len = sizeof(int);
    596   1.1    jruoho 	void *map;
    597   1.1    jruoho 	int val;
    598   1.1    jruoho 
    599   1.1    jruoho 	/*
    600   1.1    jruoho 	 * Make an anonymous fixed mapping at zero address. If the address
    601   1.1    jruoho 	 * is restricted as noted in security(7), the syscall should fail.
    602   1.1    jruoho 	 */
    603   1.1    jruoho 	if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0)
    604   1.1    jruoho 		atf_tc_fail("failed to read vm.user_va0_disable");
    605   1.1    jruoho 
    606   1.1    jruoho 	map = mmap(NULL, page, PROT_EXEC, flags, -1, 0);
    607   1.1    jruoho 	map_check(map, val);
    608   1.1    jruoho 
    609   1.1    jruoho 	map = mmap(NULL, page, PROT_READ, flags, -1, 0);
    610   1.1    jruoho 	map_check(map, val);
    611   1.1    jruoho 
    612   1.1    jruoho 	map = mmap(NULL, page, PROT_WRITE, flags, -1, 0);
    613   1.1    jruoho 	map_check(map, val);
    614   1.1    jruoho 
    615   1.1    jruoho 	map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0);
    616   1.1    jruoho 	map_check(map, val);
    617   1.1    jruoho 
    618   1.1    jruoho 	map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0);
    619   1.1    jruoho 	map_check(map, val);
    620   1.1    jruoho }
    621   1.1    jruoho 
    622   1.1    jruoho ATF_TP_ADD_TCS(tp)
    623   1.1    jruoho {
    624   1.1    jruoho 	page = sysconf(_SC_PAGESIZE);
    625   1.1    jruoho 	ATF_REQUIRE(page >= 0);
    626   1.1    jruoho 
    627   1.3    jruoho 	ATF_TP_ADD_TC(tp, mmap_block);
    628   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_err);
    629   1.2    jruoho 	ATF_TP_ADD_TC(tp, mmap_loan);
    630   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_prot_1);
    631   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_prot_2);
    632   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_prot_3);
    633  1.17      gson 	ATF_TP_ADD_TC(tp, mmap_reprotect_race);
    634   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_truncate);
    635   1.8  christos 	ATF_TP_ADD_TC(tp, mmap_truncate_signal);
    636   1.1    jruoho 	ATF_TP_ADD_TC(tp, mmap_va0);
    637   1.1    jruoho 
    638   1.1    jruoho 	return atf_no_error();
    639   1.1    jruoho }
    640