1272343Sngie/* $NetBSD: t_mmap.c,v 1.7 2012/06/14 17:47:58 bouyer Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * This code is derived from software contributed to The NetBSD Foundation
8272343Sngie * by Jukka Ruohonen.
9272343Sngie *
10272343Sngie * Redistribution and use in source and binary forms, with or without
11272343Sngie * modification, are permitted provided that the following conditions
12272343Sngie * are met:
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in the
17272343Sngie *    documentation and/or other materials provided with the distribution.
18272343Sngie *
19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29272343Sngie * POSSIBILITY OF SUCH DAMAGE.
30272343Sngie */
31272343Sngie
32272343Sngie/*-
33272343Sngie * Copyright (c)2004 YAMAMOTO Takashi,
34272343Sngie * All rights reserved.
35272343Sngie *
36272343Sngie * Redistribution and use in source and binary forms, with or without
37272343Sngie * modification, are permitted provided that the following conditions
38272343Sngie * are met:
39272343Sngie * 1. Redistributions of source code must retain the above copyright
40272343Sngie *    notice, this list of conditions and the following disclaimer.
41272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
42272343Sngie *    notice, this list of conditions and the following disclaimer in the
43272343Sngie *    documentation and/or other materials provided with the distribution.
44272343Sngie *
45272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48272343Sngie * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55272343Sngie * SUCH DAMAGE.
56272343Sngie */
57272343Sngie#include <sys/cdefs.h>
58272343Sngie__RCSID("$NetBSD: t_mmap.c,v 1.7 2012/06/14 17:47:58 bouyer Exp $");
59272343Sngie
60272343Sngie#include <sys/param.h>
61272343Sngie#include <sys/mman.h>
62272343Sngie#include <sys/socket.h>
63272343Sngie#include <sys/sysctl.h>
64272343Sngie#include <sys/wait.h>
65272343Sngie
66272343Sngie#include <atf-c.h>
67272343Sngie#include <errno.h>
68272343Sngie#include <fcntl.h>
69272343Sngie#include <signal.h>
70272343Sngie#include <stdio.h>
71272343Sngie#include <stdlib.h>
72272343Sngie#include <string.h>
73272343Sngie#include <unistd.h>
74272343Sngie#include <paths.h>
75273525Sngie#ifdef __NetBSD__
76272343Sngie#include <machine/disklabel.h>
77273525Sngie#endif
78272343Sngie
79273525Sngie#ifdef __FreeBSD__
80273525Sngie#include <sys/disklabel.h>
81273525Sngie#include <sys/stat.h>
82273525Sngie#include <stdint.h>
83273525Sngie#endif
84273525Sngie
85272343Sngiestatic long	page = 0;
86272343Sngiestatic char	path[] = "mmap";
87272343Sngiestatic void	map_check(void *, int);
88272343Sngiestatic void	map_sighandler(int);
89272343Sngiestatic void	testloan(void *, void *, char, int);
90272343Sngie
91272343Sngie#define	BUFSIZE	(32 * 1024)	/* enough size to trigger sosend_loan */
92272343Sngie
93272343Sngiestatic void
94272343Sngiemap_check(void *map, int flag)
95272343Sngie{
96272343Sngie
97272343Sngie	if (flag != 0) {
98272343Sngie		ATF_REQUIRE(map == MAP_FAILED);
99272343Sngie		return;
100272343Sngie	}
101272343Sngie
102272343Sngie	ATF_REQUIRE(map != MAP_FAILED);
103272343Sngie	ATF_REQUIRE(munmap(map, page) == 0);
104272343Sngie}
105272343Sngie
106272343Sngievoid
107272343Sngietestloan(void *vp, void *vp2, char pat, int docheck)
108272343Sngie{
109272343Sngie	char buf[BUFSIZE];
110272343Sngie	char backup[BUFSIZE];
111272343Sngie	ssize_t nwritten;
112272343Sngie	ssize_t nread;
113272343Sngie	int fds[2];
114272343Sngie	int val;
115272343Sngie
116272343Sngie	val = BUFSIZE;
117272343Sngie
118272343Sngie	if (docheck != 0)
119272343Sngie		(void)memcpy(backup, vp, BUFSIZE);
120272343Sngie
121272343Sngie	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0)
122272343Sngie		atf_tc_fail("socketpair() failed");
123272343Sngie
124272343Sngie	val = BUFSIZE;
125272343Sngie
126272343Sngie	if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
127272343Sngie		atf_tc_fail("setsockopt() failed, SO_RCVBUF");
128272343Sngie
129272343Sngie	val = BUFSIZE;
130272343Sngie
131272343Sngie	if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
132272343Sngie		atf_tc_fail("setsockopt() failed, SO_SNDBUF");
133272343Sngie
134272343Sngie	if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0)
135272343Sngie		atf_tc_fail("fcntl() failed");
136272343Sngie
137272343Sngie	nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page);
138272343Sngie
139272343Sngie	if (nwritten == -1)
140272343Sngie		atf_tc_fail("write() failed");
141272343Sngie
142272343Sngie	/* Break loan. */
143272343Sngie	(void)memset(vp2, pat, BUFSIZE);
144272343Sngie
145272343Sngie	nread = read(fds[1], buf + page, BUFSIZE - page);
146272343Sngie
147272343Sngie	if (nread == -1)
148272343Sngie		atf_tc_fail("read() failed");
149272343Sngie
150272343Sngie	if (nread != nwritten)
151272343Sngie		atf_tc_fail("too short read");
152272343Sngie
153272343Sngie	if (docheck != 0 && memcmp(backup, buf + page, nread) != 0)
154272343Sngie		atf_tc_fail("data mismatch");
155272343Sngie
156272343Sngie	ATF_REQUIRE(close(fds[0]) == 0);
157272343Sngie	ATF_REQUIRE(close(fds[1]) == 0);
158272343Sngie}
159272343Sngie
160272343Sngiestatic void
161272343Sngiemap_sighandler(int signo)
162272343Sngie{
163272343Sngie	_exit(signo);
164272343Sngie}
165272343Sngie
166273525Sngie#ifdef __NetBSD__
167272343SngieATF_TC(mmap_block);
168272343SngieATF_TC_HEAD(mmap_block, tc)
169272343Sngie{
170272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device");
171272343Sngie	atf_tc_set_md_var(tc, "require.user", "root");
172272343Sngie}
173272343Sngie
174272343SngieATF_TC_BODY(mmap_block, tc)
175272343Sngie{
176272343Sngie	static const int mib[] = { CTL_HW, HW_DISKNAMES };
177272343Sngie	static const unsigned int miblen = __arraycount(mib);
178272343Sngie	char *map, *dk, *drives, dev[PATH_MAX];
179272343Sngie	size_t len;
180272343Sngie	int fd = -1;
181272343Sngie
182272343Sngie	atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)");
183272343Sngie
184272343Sngie	ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0);
185272343Sngie	drives = malloc(len);
186272343Sngie	ATF_REQUIRE(drives != NULL);
187272343Sngie	ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0);
188272343Sngie	for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) {
189272343Sngie		sprintf(dev, _PATH_DEV "%s%c", dk, 'a'+RAW_PART);
190272343Sngie		fprintf(stderr, "trying: %s\n", dev);
191272343Sngie
192272343Sngie		if ((fd = open(dev, O_RDONLY)) >= 0) {
193272343Sngie			(void)fprintf(stderr, "using %s\n", dev);
194272343Sngie			break;
195272343Sngie		}
196272343Sngie	}
197272343Sngie	free(drives);
198272343Sngie
199272343Sngie	if (fd < 0)
200272343Sngie		atf_tc_skip("failed to find suitable block device");
201272343Sngie
202272343Sngie	map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0);
203272343Sngie	ATF_REQUIRE(map != MAP_FAILED);
204272343Sngie
205272343Sngie	(void)fprintf(stderr, "first byte %x\n", *map);
206272343Sngie	ATF_REQUIRE(close(fd) == 0);
207272343Sngie	(void)fprintf(stderr, "first byte %x\n", *map);
208272343Sngie
209272343Sngie	ATF_REQUIRE(munmap(map, 4096) == 0);
210272343Sngie}
211273525Sngie#endif
212272343Sngie
213272343SngieATF_TC(mmap_err);
214272343SngieATF_TC_HEAD(mmap_err, tc)
215272343Sngie{
216272343Sngie	atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)");
217272343Sngie}
218272343Sngie
219272343SngieATF_TC_BODY(mmap_err, tc)
220272343Sngie{
221272343Sngie	size_t addr = SIZE_MAX;
222272343Sngie	void *map;
223272343Sngie
224272343Sngie	errno = 0;
225272343Sngie	map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0);
226272343Sngie
227272343Sngie	ATF_REQUIRE(map == MAP_FAILED);
228272343Sngie	ATF_REQUIRE(errno == EBADF);
229272343Sngie
230272343Sngie	errno = 0;
231272343Sngie	map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0);
232272343Sngie
233272343Sngie	ATF_REQUIRE(map == MAP_FAILED);
234272343Sngie	ATF_REQUIRE(errno == EINVAL);
235272343Sngie
236272343Sngie	errno = 0;
237272343Sngie	map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0);
238272343Sngie
239272343Sngie	ATF_REQUIRE(map == MAP_FAILED);
240272343Sngie	ATF_REQUIRE(errno == EINVAL);
241272343Sngie}
242272343Sngie
243272343SngieATF_TC_WITH_CLEANUP(mmap_loan);
244272343SngieATF_TC_HEAD(mmap_loan, tc)
245272343Sngie{
246272343Sngie	atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)");
247272343Sngie}
248272343Sngie
249272343SngieATF_TC_BODY(mmap_loan, tc)
250272343Sngie{
251272343Sngie	char buf[BUFSIZE];
252272343Sngie	char *vp, *vp2;
253272343Sngie	int fd;
254272343Sngie
255272343Sngie	fd = open(path, O_RDWR | O_CREAT, 0600);
256272343Sngie	ATF_REQUIRE(fd >= 0);
257272343Sngie
258272343Sngie	(void)memset(buf, 'x', sizeof(buf));
259272343Sngie	(void)write(fd, buf, sizeof(buf));
260272343Sngie
261272343Sngie	vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
262272343Sngie	    MAP_FILE | MAP_PRIVATE, fd, 0);
263272343Sngie
264272343Sngie	ATF_REQUIRE(vp != MAP_FAILED);
265272343Sngie
266272343Sngie	vp2 = vp;
267272343Sngie
268272343Sngie	testloan(vp, vp2, 'A', 0);
269272343Sngie	testloan(vp, vp2, 'B', 1);
270272343Sngie
271272343Sngie	ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
272272343Sngie
273272343Sngie	vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
274272343Sngie	    MAP_FILE | MAP_SHARED, fd, 0);
275272343Sngie
276272343Sngie	vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
277272343Sngie	    MAP_FILE | MAP_SHARED, fd, 0);
278272343Sngie
279272343Sngie	ATF_REQUIRE(vp != MAP_FAILED);
280272343Sngie	ATF_REQUIRE(vp2 != MAP_FAILED);
281272343Sngie
282272343Sngie	testloan(vp, vp2, 'E', 1);
283272343Sngie
284272343Sngie	ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
285272343Sngie	ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0);
286272343Sngie}
287272343Sngie
288272343SngieATF_TC_CLEANUP(mmap_loan, tc)
289272343Sngie{
290272343Sngie	(void)unlink(path);
291272343Sngie}
292272343Sngie
293272343SngieATF_TC_WITH_CLEANUP(mmap_prot_1);
294272343SngieATF_TC_HEAD(mmap_prot_1, tc)
295272343Sngie{
296272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1");
297272343Sngie}
298272343Sngie
299272343SngieATF_TC_BODY(mmap_prot_1, tc)
300272343Sngie{
301272343Sngie	void *map;
302272343Sngie	int fd;
303272343Sngie
304272343Sngie	/*
305272343Sngie	 * Open a file write-only and try to
306272343Sngie	 * map it read-only. This should fail.
307272343Sngie	 */
308272343Sngie	fd = open(path, O_WRONLY | O_CREAT, 0700);
309272343Sngie
310272343Sngie	if (fd < 0)
311272343Sngie		return;
312272343Sngie
313272343Sngie	ATF_REQUIRE(write(fd, "XXX", 3) == 3);
314272343Sngie
315272343Sngie	map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
316272343Sngie	map_check(map, 1);
317272343Sngie
318272343Sngie	map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
319272343Sngie	map_check(map, 0);
320272343Sngie
321272343Sngie	ATF_REQUIRE(close(fd) == 0);
322272343Sngie}
323272343Sngie
324272343SngieATF_TC_CLEANUP(mmap_prot_1, tc)
325272343Sngie{
326272343Sngie	(void)unlink(path);
327272343Sngie}
328272343Sngie
329272343SngieATF_TC(mmap_prot_2);
330272343SngieATF_TC_HEAD(mmap_prot_2, tc)
331272343Sngie{
332272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2");
333272343Sngie}
334272343Sngie
335272343SngieATF_TC_BODY(mmap_prot_2, tc)
336272343Sngie{
337272343Sngie	char buf[2];
338272343Sngie	void *map;
339272343Sngie	pid_t pid;
340272343Sngie	int sta;
341272343Sngie
342272343Sngie	/*
343272343Sngie	 * Make a PROT_NONE mapping and try to access it.
344272343Sngie	 * If we catch a SIGSEGV, all works as expected.
345272343Sngie	 */
346272343Sngie	map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
347272343Sngie	ATF_REQUIRE(map != MAP_FAILED);
348272343Sngie
349272343Sngie	pid = fork();
350272343Sngie	ATF_REQUIRE(pid >= 0);
351272343Sngie
352272343Sngie	if (pid == 0) {
353272343Sngie		ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
354272343Sngie		ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
355272343Sngie	}
356272343Sngie
357272343Sngie	(void)wait(&sta);
358272343Sngie
359272343Sngie	ATF_REQUIRE(WIFEXITED(sta) != 0);
360272343Sngie	ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
361272343Sngie	ATF_REQUIRE(munmap(map, page) == 0);
362272343Sngie}
363272343Sngie
364272343SngieATF_TC_WITH_CLEANUP(mmap_prot_3);
365272343SngieATF_TC_HEAD(mmap_prot_3, tc)
366272343Sngie{
367272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3");
368272343Sngie}
369272343Sngie
370272343SngieATF_TC_BODY(mmap_prot_3, tc)
371272343Sngie{
372272343Sngie	char buf[2];
373272343Sngie	int fd, sta;
374272343Sngie	void *map;
375272343Sngie	pid_t pid;
376272343Sngie
377272343Sngie	/*
378272343Sngie	 * Open a file, change the permissions
379272343Sngie	 * to read-only, and try to map it as
380272343Sngie	 * PROT_NONE. This should succeed, but
381272343Sngie	 * the access should generate SIGSEGV.
382272343Sngie	 */
383272343Sngie	fd = open(path, O_RDWR | O_CREAT, 0700);
384272343Sngie
385272343Sngie	if (fd < 0)
386272343Sngie		return;
387272343Sngie
388272343Sngie	ATF_REQUIRE(write(fd, "XXX", 3) == 3);
389272343Sngie	ATF_REQUIRE(close(fd) == 0);
390272343Sngie	ATF_REQUIRE(chmod(path, 0444) == 0);
391272343Sngie
392272343Sngie	fd = open(path, O_RDONLY);
393272343Sngie	ATF_REQUIRE(fd != -1);
394272343Sngie
395272343Sngie	map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0);
396272343Sngie	ATF_REQUIRE(map != MAP_FAILED);
397272343Sngie
398272343Sngie	pid = fork();
399272343Sngie
400272343Sngie	ATF_REQUIRE(pid >= 0);
401272343Sngie
402272343Sngie	if (pid == 0) {
403272343Sngie		ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
404272343Sngie		ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
405272343Sngie	}
406272343Sngie
407272343Sngie	(void)wait(&sta);
408272343Sngie
409272343Sngie	ATF_REQUIRE(WIFEXITED(sta) != 0);
410272343Sngie	ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
411272343Sngie	ATF_REQUIRE(munmap(map, 3) == 0);
412272343Sngie}
413272343Sngie
414272343SngieATF_TC_CLEANUP(mmap_prot_3, tc)
415272343Sngie{
416272343Sngie	(void)unlink(path);
417272343Sngie}
418272343Sngie
419272343SngieATF_TC_WITH_CLEANUP(mmap_truncate);
420272343SngieATF_TC_HEAD(mmap_truncate, tc)
421272343Sngie{
422272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)");
423272343Sngie}
424272343Sngie
425272343SngieATF_TC_BODY(mmap_truncate, tc)
426272343Sngie{
427272343Sngie	char *map;
428272343Sngie	long i;
429272343Sngie	int fd;
430272343Sngie
431272343Sngie	fd = open(path, O_RDWR | O_CREAT, 0700);
432272343Sngie
433272343Sngie	if (fd < 0)
434272343Sngie		return;
435272343Sngie
436272343Sngie	/*
437272343Sngie	 * See that ftruncate(2) works
438272343Sngie	 * while the file is mapped.
439272343Sngie	 */
440272343Sngie	ATF_REQUIRE(ftruncate(fd, page) == 0);
441272343Sngie
442272343Sngie	map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE,
443272343Sngie	     fd, 0);
444272343Sngie	ATF_REQUIRE(map != MAP_FAILED);
445272343Sngie
446272343Sngie	for (i = 0; i < page; i++)
447272343Sngie		map[i] = 'x';
448272343Sngie
449272343Sngie	ATF_REQUIRE(ftruncate(fd, 0) == 0);
450272343Sngie	ATF_REQUIRE(ftruncate(fd, page / 8) == 0);
451272343Sngie	ATF_REQUIRE(ftruncate(fd, page / 4) == 0);
452272343Sngie	ATF_REQUIRE(ftruncate(fd, page / 2) == 0);
453272343Sngie	ATF_REQUIRE(ftruncate(fd, page / 12) == 0);
454272343Sngie	ATF_REQUIRE(ftruncate(fd, page / 64) == 0);
455272343Sngie
456272343Sngie	ATF_REQUIRE(close(fd) == 0);
457272343Sngie}
458272343Sngie
459272343SngieATF_TC_CLEANUP(mmap_truncate, tc)
460272343Sngie{
461272343Sngie	(void)unlink(path);
462272343Sngie}
463272343Sngie
464272343SngieATF_TC(mmap_va0);
465272343SngieATF_TC_HEAD(mmap_va0, tc)
466272343Sngie{
467272343Sngie	atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable");
468272343Sngie}
469272343Sngie
470272343SngieATF_TC_BODY(mmap_va0, tc)
471272343Sngie{
472272343Sngie	int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE;
473272343Sngie	size_t len = sizeof(int);
474272343Sngie	void *map;
475272343Sngie	int val;
476272343Sngie
477272343Sngie	/*
478272343Sngie	 * Make an anonymous fixed mapping at zero address. If the address
479272343Sngie	 * is restricted as noted in security(7), the syscall should fail.
480272343Sngie	 */
481273525Sngie#ifdef __FreeBSD__
482273525Sngie	if (sysctlbyname("security.bsd.map_at_zero", &val, &len, NULL, 0) != 0)
483273525Sngie		atf_tc_fail("failed to read security.bsd.map_at_zero");
484273525Sngie	val = !val; /* 1 == enable  map at zero */
485273525Sngie#endif
486273525Sngie#ifdef __NetBSD__
487272343Sngie	if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0)
488272343Sngie		atf_tc_fail("failed to read vm.user_va0_disable");
489273525Sngie#endif
490272343Sngie
491272343Sngie	map = mmap(NULL, page, PROT_EXEC, flags, -1, 0);
492272343Sngie	map_check(map, val);
493272343Sngie
494272343Sngie	map = mmap(NULL, page, PROT_READ, flags, -1, 0);
495272343Sngie	map_check(map, val);
496272343Sngie
497272343Sngie	map = mmap(NULL, page, PROT_WRITE, flags, -1, 0);
498272343Sngie	map_check(map, val);
499272343Sngie
500272343Sngie	map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0);
501272343Sngie	map_check(map, val);
502272343Sngie
503272343Sngie	map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0);
504272343Sngie	map_check(map, val);
505272343Sngie}
506272343Sngie
507272343SngieATF_TP_ADD_TCS(tp)
508272343Sngie{
509272343Sngie	page = sysconf(_SC_PAGESIZE);
510272343Sngie	ATF_REQUIRE(page >= 0);
511272343Sngie
512273525Sngie#ifdef __NetBSD__
513272343Sngie	ATF_TP_ADD_TC(tp, mmap_block);
514273525Sngie#endif
515272343Sngie	ATF_TP_ADD_TC(tp, mmap_err);
516272343Sngie	ATF_TP_ADD_TC(tp, mmap_loan);
517272343Sngie	ATF_TP_ADD_TC(tp, mmap_prot_1);
518272343Sngie	ATF_TP_ADD_TC(tp, mmap_prot_2);
519272343Sngie	ATF_TP_ADD_TC(tp, mmap_prot_3);
520272343Sngie	ATF_TP_ADD_TC(tp, mmap_truncate);
521272343Sngie	ATF_TP_ADD_TC(tp, mmap_va0);
522272343Sngie
523272343Sngie	return atf_no_error();
524272343Sngie}
525