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