xref: /freebsd/tests/sys/vm/mmap_test.c (revision 410757a4f4e8d84e0bf2387d0a323d660580ecf5)
142484f6fSEnji Cooper /*-
242484f6fSEnji Cooper  * Copyright (c) 2009	Simon L. Nielsen <simon@FreeBSD.org>,
342484f6fSEnji Cooper  * 			Bjoern A. Zeeb <bz@FreeBSD.org>
442484f6fSEnji Cooper  *
542484f6fSEnji Cooper  * Redistribution and use in source and binary forms, with or without
642484f6fSEnji Cooper  * modification, are permitted provided that the following conditions
742484f6fSEnji Cooper  * are met:
842484f6fSEnji Cooper  * 1. Redistributions of source code must retain the above copyright
942484f6fSEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1042484f6fSEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1142484f6fSEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1242484f6fSEnji Cooper  *    documentation and/or other materials provided with the distribution.
1342484f6fSEnji Cooper  *
1442484f6fSEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1542484f6fSEnji Cooper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1642484f6fSEnji Cooper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1742484f6fSEnji Cooper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1842484f6fSEnji Cooper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1942484f6fSEnji Cooper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2042484f6fSEnji Cooper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2142484f6fSEnji Cooper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2242484f6fSEnji Cooper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2342484f6fSEnji Cooper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2442484f6fSEnji Cooper  * SUCH DAMAGE.
2542484f6fSEnji Cooper  *
2642484f6fSEnji Cooper  * $FreeBSD$
2742484f6fSEnji Cooper  */
2842484f6fSEnji Cooper 
2942484f6fSEnji Cooper #include <sys/param.h>
3042484f6fSEnji Cooper #include <sys/mman.h>
3142484f6fSEnji Cooper #include <sys/sysctl.h>
3242484f6fSEnji Cooper 
3395eee0d4SJohn Baldwin #include <atf-c.h>
3442484f6fSEnji Cooper #include <errno.h>
357f43ee0fSJohn Baldwin #include <fcntl.h>
367f43ee0fSJohn Baldwin #include <stdarg.h>
377f43ee0fSJohn Baldwin #include <stdio.h>
387f43ee0fSJohn Baldwin #include <stdlib.h>
3942484f6fSEnji Cooper 
4042484f6fSEnji Cooper static const struct {
4142484f6fSEnji Cooper 	void	*addr;
4242484f6fSEnji Cooper 	int	ok[2];	/* Depending on security.bsd.map_at_zero {0, !=0}. */
4395eee0d4SJohn Baldwin } map_at_zero_tests[] = {
4442484f6fSEnji Cooper 	{ (void *)0,			{ 0, 1 } }, /* Test sysctl. */
4542484f6fSEnji Cooper 	{ (void *)1,			{ 0, 0 } },
4642484f6fSEnji Cooper 	{ (void *)(PAGE_SIZE - 1),	{ 0, 0 } },
4742484f6fSEnji Cooper 	{ (void *)PAGE_SIZE,		{ 1, 1 } },
4842484f6fSEnji Cooper 	{ (void *)-1,			{ 0, 0 } },
4942484f6fSEnji Cooper 	{ (void *)(-PAGE_SIZE),		{ 0, 0 } },
5042484f6fSEnji Cooper 	{ (void *)(-1 - PAGE_SIZE),	{ 0, 0 } },
5142484f6fSEnji Cooper 	{ (void *)(-1 - PAGE_SIZE - 1),	{ 0, 0 } },
5242484f6fSEnji Cooper 	{ (void *)(0x1000 * PAGE_SIZE),	{ 1, 1 } },
5342484f6fSEnji Cooper };
5442484f6fSEnji Cooper 
5542484f6fSEnji Cooper #define	MAP_AT_ZERO	"security.bsd.map_at_zero"
5642484f6fSEnji Cooper 
5795eee0d4SJohn Baldwin ATF_TC_WITHOUT_HEAD(mmap__map_at_zero);
5895eee0d4SJohn Baldwin ATF_TC_BODY(mmap__map_at_zero, tc)
5942484f6fSEnji Cooper {
6042484f6fSEnji Cooper 	void *p;
6142484f6fSEnji Cooper 	size_t len;
6295eee0d4SJohn Baldwin 	unsigned int i;
6395eee0d4SJohn Baldwin 	int map_at_zero;
6442484f6fSEnji Cooper 
6542484f6fSEnji Cooper 	len = sizeof(map_at_zero);
6695eee0d4SJohn Baldwin 	if (sysctlbyname(MAP_AT_ZERO, &map_at_zero, &len, NULL, 0) == -1) {
6795eee0d4SJohn Baldwin 		atf_tc_skip("sysctl for %s failed: %s\n", MAP_AT_ZERO,
6842484f6fSEnji Cooper 		    strerror(errno));
6995eee0d4SJohn Baldwin 		return;
7042484f6fSEnji Cooper 	}
7142484f6fSEnji Cooper 
7242484f6fSEnji Cooper 	/* Normalize to 0 or 1 for array access. */
7342484f6fSEnji Cooper 	map_at_zero = !!map_at_zero;
7442484f6fSEnji Cooper 
7595eee0d4SJohn Baldwin 	for (i = 0; i < nitems(map_at_zero_tests); i++) {
7695eee0d4SJohn Baldwin 		p = mmap((void *)map_at_zero_tests[i].addr, PAGE_SIZE,
7742484f6fSEnji Cooper 		    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_FIXED,
7842484f6fSEnji Cooper 		    -1, 0);
7942484f6fSEnji Cooper 		if (p == MAP_FAILED) {
8095eee0d4SJohn Baldwin 			ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 0,
8195eee0d4SJohn Baldwin 			    "mmap(%p, ...) failed", map_at_zero_tests[i].addr);
8242484f6fSEnji Cooper 		} else {
8395eee0d4SJohn Baldwin 			ATF_CHECK_MSG(map_at_zero_tests[i].ok[map_at_zero] == 1,
8495eee0d4SJohn Baldwin 			    "mmap(%p, ...) succeeded: p=%p\n",
8595eee0d4SJohn Baldwin 			    map_at_zero_tests[i].addr, p);
8695eee0d4SJohn Baldwin 		}
8742484f6fSEnji Cooper 	}
8842484f6fSEnji Cooper }
8942484f6fSEnji Cooper 
907f43ee0fSJohn Baldwin static void
917f43ee0fSJohn Baldwin checked_mmap(int prot, int flags, int fd, int error, const char *msg)
927f43ee0fSJohn Baldwin {
937f43ee0fSJohn Baldwin 	void *p;
94*410757a4SEnji Cooper 	int pagesize;
957f43ee0fSJohn Baldwin 
96*410757a4SEnji Cooper 	ATF_REQUIRE((pagesize = getpagesize()) > 0);
97*410757a4SEnji Cooper 	p = mmap(NULL, pagesize, prot, flags, fd, 0);
987f43ee0fSJohn Baldwin 	if (p == MAP_FAILED) {
997f43ee0fSJohn Baldwin 		if (error == 0)
1007f43ee0fSJohn Baldwin 			ATF_CHECK_MSG(0, "%s failed with errno %d", msg,
1017f43ee0fSJohn Baldwin 			    errno);
1027f43ee0fSJohn Baldwin 		else
1037f43ee0fSJohn Baldwin 			ATF_CHECK_EQ_MSG(error, errno,
1047f43ee0fSJohn Baldwin 			    "%s failed with wrong errno %d (expected %d)", msg,
1057f43ee0fSJohn Baldwin 			    errno, error);
1067f43ee0fSJohn Baldwin 	} else {
1077f43ee0fSJohn Baldwin 		ATF_CHECK_MSG(error == 0, "%s succeeded", msg);
108*410757a4SEnji Cooper 		munmap(p, pagesize);
1097f43ee0fSJohn Baldwin 	}
1107f43ee0fSJohn Baldwin }
1117f43ee0fSJohn Baldwin 
1127f43ee0fSJohn Baldwin ATF_TC_WITHOUT_HEAD(mmap__bad_arguments);
1137f43ee0fSJohn Baldwin ATF_TC_BODY(mmap__bad_arguments, tc)
1147f43ee0fSJohn Baldwin {
115*410757a4SEnji Cooper 	int devstatfd, pagesize, shmfd, zerofd;
1167f43ee0fSJohn Baldwin 
117*410757a4SEnji Cooper 	ATF_REQUIRE((pagesize = getpagesize()) > 0);
1189695459dSJohn Baldwin 	ATF_REQUIRE((devstatfd = open("/dev/devstat", O_RDONLY)) >= 0);
1199695459dSJohn Baldwin 	ATF_REQUIRE((shmfd = shm_open(SHM_ANON, O_RDWR, 0644)) >= 0);
120*410757a4SEnji Cooper 	ATF_REQUIRE(ftruncate(shmfd, pagesize) == 0);
1219695459dSJohn Baldwin 	ATF_REQUIRE((zerofd = open("/dev/zero", O_RDONLY)) >= 0);
1227f43ee0fSJohn Baldwin 
1237f43ee0fSJohn Baldwin 	/* These should work. */
1247f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON, -1, 0,
1257f43ee0fSJohn Baldwin 	    "simple MAP_ANON");
1269695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0,
1277f43ee0fSJohn Baldwin 	    "simple shm fd shared");
1289695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, shmfd, 0,
1297f43ee0fSJohn Baldwin 	    "simple shm fd private");
1309695459dSJohn Baldwin 	checked_mmap(PROT_READ, MAP_SHARED, zerofd, 0,
1319695459dSJohn Baldwin 	    "simple /dev/zero shared");
1329695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE, zerofd, 0,
1339695459dSJohn Baldwin 	    "simple /dev/zero private");
1349695459dSJohn Baldwin 	checked_mmap(PROT_READ, MAP_SHARED, devstatfd, 0,
1359695459dSJohn Baldwin 	    "simple /dev/devstat shared");
1367f43ee0fSJohn Baldwin 
1377f43ee0fSJohn Baldwin 	/* Extra PROT flags. */
1387f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE | 0x100000, MAP_ANON, -1, EINVAL,
1397f43ee0fSJohn Baldwin 	    "MAP_ANON with extra PROT flags");
1409695459dSJohn Baldwin 	checked_mmap(0xffff, MAP_SHARED, shmfd, EINVAL,
1417f43ee0fSJohn Baldwin 	    "shm fd with garbage PROT");
1427f43ee0fSJohn Baldwin 
1437f43ee0fSJohn Baldwin 	/* Undefined flag. */
1447f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_RESERVED0080, -1,
1457f43ee0fSJohn Baldwin 	    EINVAL, "Undefined flag");
1467f43ee0fSJohn Baldwin 
1477f43ee0fSJohn Baldwin 	/* Both MAP_SHARED and MAP_PRIVATE */
1487f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE |
1497f43ee0fSJohn Baldwin 	    MAP_SHARED, -1, EINVAL, "MAP_ANON with both SHARED and PRIVATE");
1509695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_SHARED, shmfd,
1517f43ee0fSJohn Baldwin 	    EINVAL, "shm fd with both SHARED and PRIVATE");
1527f43ee0fSJohn Baldwin 
1537f43ee0fSJohn Baldwin 	/* At least one of MAP_SHARED or MAP_PRIVATE without ANON */
1549695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, 0, shmfd, EINVAL,
1557f43ee0fSJohn Baldwin 	    "shm fd without sharing flag");
1567f43ee0fSJohn Baldwin 
1577f43ee0fSJohn Baldwin 	/* MAP_ANON with either sharing flag (impacts fork). */
1587f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0,
1597f43ee0fSJohn Baldwin 	    "shared MAP_ANON");
1607f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0,
1617f43ee0fSJohn Baldwin 	    "private MAP_ANON");
1627f43ee0fSJohn Baldwin 
1637f43ee0fSJohn Baldwin 	/* MAP_ANON should require an fd of -1. */
1647f43ee0fSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, EINVAL,
1657f43ee0fSJohn Baldwin 	    "MAP_ANON with fd != -1");
1669695459dSJohn Baldwin 
1679695459dSJohn Baldwin 	/* Writable MAP_SHARED should fail on read-only descriptors. */
1689695459dSJohn Baldwin 	checked_mmap(PROT_READ | PROT_WRITE, MAP_SHARED, zerofd, EACCES,
1699695459dSJohn Baldwin 	    "MAP_SHARED of read-only /dev/zero");
1709695459dSJohn Baldwin 
1719695459dSJohn Baldwin 	/*
1729695459dSJohn Baldwin 	 * Character devices other than /dev/zero do not support private
1739695459dSJohn Baldwin 	 * mappings.
1749695459dSJohn Baldwin 	 */
1759695459dSJohn Baldwin 	checked_mmap(PROT_READ, MAP_PRIVATE, devstatfd, EINVAL,
1769695459dSJohn Baldwin 	    "MAP_PRIVATE of /dev/devstat");
177*410757a4SEnji Cooper 
178*410757a4SEnji Cooper 	close(devstatfd);
179*410757a4SEnji Cooper 	close(shmfd);
180*410757a4SEnji Cooper 	close(zerofd);
1819695459dSJohn Baldwin }
1829695459dSJohn Baldwin 
1839695459dSJohn Baldwin ATF_TC_WITHOUT_HEAD(mmap__dev_zero_private);
1849695459dSJohn Baldwin ATF_TC_BODY(mmap__dev_zero_private, tc)
1859695459dSJohn Baldwin {
1869695459dSJohn Baldwin 	char *p1, *p2, *p3;
1879695459dSJohn Baldwin 	size_t i;
188*410757a4SEnji Cooper 	int fd, pagesize;
1899695459dSJohn Baldwin 
190*410757a4SEnji Cooper 	ATF_REQUIRE((pagesize = getpagesize()) > 0);
1919695459dSJohn Baldwin 	ATF_REQUIRE((fd = open("/dev/zero", O_RDONLY)) >= 0);
1929695459dSJohn Baldwin 
193*410757a4SEnji Cooper 	p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1949695459dSJohn Baldwin 	ATF_REQUIRE(p1 != MAP_FAILED);
1959695459dSJohn Baldwin 
196*410757a4SEnji Cooper 	p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1979695459dSJohn Baldwin 	ATF_REQUIRE(p2 != MAP_FAILED);
1989695459dSJohn Baldwin 
199*410757a4SEnji Cooper 	for (i = 0; i < pagesize; i++)
2009695459dSJohn Baldwin 		ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%zu] is %x", i, p1[i]);
2019695459dSJohn Baldwin 
202*410757a4SEnji Cooper 	ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0);
2039695459dSJohn Baldwin 
2049695459dSJohn Baldwin 	p1[0] = 1;
2059695459dSJohn Baldwin 
2069695459dSJohn Baldwin 	ATF_REQUIRE(p2[0] == 0);
2079695459dSJohn Baldwin 
2089695459dSJohn Baldwin 	p2[0] = 2;
2099695459dSJohn Baldwin 
2109695459dSJohn Baldwin 	ATF_REQUIRE(p1[0] == 1);
2119695459dSJohn Baldwin 
212*410757a4SEnji Cooper 	p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
2139695459dSJohn Baldwin 	ATF_REQUIRE(p3 != MAP_FAILED);
2149695459dSJohn Baldwin 
2159695459dSJohn Baldwin 	ATF_REQUIRE(p3[0] == 0);
216*410757a4SEnji Cooper 
217*410757a4SEnji Cooper 	munmap(p1, pagesize);
218*410757a4SEnji Cooper 	munmap(p2, pagesize);
219*410757a4SEnji Cooper 	munmap(p3, pagesize);
220*410757a4SEnji Cooper 	close(fd);
2219695459dSJohn Baldwin }
2229695459dSJohn Baldwin 
2239695459dSJohn Baldwin ATF_TC_WITHOUT_HEAD(mmap__dev_zero_shared);
2249695459dSJohn Baldwin ATF_TC_BODY(mmap__dev_zero_shared, tc)
2259695459dSJohn Baldwin {
2269695459dSJohn Baldwin 	char *p1, *p2, *p3;
2279695459dSJohn Baldwin 	size_t i;
228*410757a4SEnji Cooper 	int fd, pagesize;
2299695459dSJohn Baldwin 
230*410757a4SEnji Cooper 	ATF_REQUIRE((pagesize = getpagesize()) > 0);
2319695459dSJohn Baldwin 	ATF_REQUIRE((fd = open("/dev/zero", O_RDWR)) >= 0);
2329695459dSJohn Baldwin 
233*410757a4SEnji Cooper 	p1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2349695459dSJohn Baldwin 	ATF_REQUIRE(p1 != MAP_FAILED);
2359695459dSJohn Baldwin 
236*410757a4SEnji Cooper 	p2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2379695459dSJohn Baldwin 	ATF_REQUIRE(p2 != MAP_FAILED);
2389695459dSJohn Baldwin 
239*410757a4SEnji Cooper 	for (i = 0; i < pagesize; i++)
2409695459dSJohn Baldwin 		ATF_REQUIRE_EQ_MSG(0, p1[i], "byte at p1[%zu] is %x", i, p1[i]);
2419695459dSJohn Baldwin 
242*410757a4SEnji Cooper 	ATF_REQUIRE(memcmp(p1, p2, pagesize) == 0);
2439695459dSJohn Baldwin 
2449695459dSJohn Baldwin 	p1[0] = 1;
2459695459dSJohn Baldwin 
2469695459dSJohn Baldwin 	ATF_REQUIRE(p2[0] == 0);
2479695459dSJohn Baldwin 
2489695459dSJohn Baldwin 	p2[0] = 2;
2499695459dSJohn Baldwin 
2509695459dSJohn Baldwin 	ATF_REQUIRE(p1[0] == 1);
2519695459dSJohn Baldwin 
252*410757a4SEnji Cooper 	p3 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
2539695459dSJohn Baldwin 	    0);
2549695459dSJohn Baldwin 	ATF_REQUIRE(p3 != MAP_FAILED);
2559695459dSJohn Baldwin 
2569695459dSJohn Baldwin 	ATF_REQUIRE(p3[0] == 0);
257*410757a4SEnji Cooper 
258*410757a4SEnji Cooper 	munmap(p1, pagesize);
259*410757a4SEnji Cooper 	munmap(p2, pagesize);
260*410757a4SEnji Cooper 	munmap(p3, pagesize);
261*410757a4SEnji Cooper 	close(fd);
2627f43ee0fSJohn Baldwin }
2637f43ee0fSJohn Baldwin 
26495eee0d4SJohn Baldwin ATF_TP_ADD_TCS(tp)
26595eee0d4SJohn Baldwin {
26695eee0d4SJohn Baldwin 
26795eee0d4SJohn Baldwin 	ATF_TP_ADD_TC(tp, mmap__map_at_zero);
2687f43ee0fSJohn Baldwin 	ATF_TP_ADD_TC(tp, mmap__bad_arguments);
2699695459dSJohn Baldwin 	ATF_TP_ADD_TC(tp, mmap__dev_zero_private);
2709695459dSJohn Baldwin 	ATF_TP_ADD_TC(tp, mmap__dev_zero_shared);
27195eee0d4SJohn Baldwin 
27295eee0d4SJohn Baldwin 	return (atf_no_error());
27342484f6fSEnji Cooper }
274