xref: /freebsd/contrib/netbsd-tests/lib/libc/sys/t_mmap.c (revision 640235e2c2ba32947f7c59d168437ffa1280f1e6)
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