t_mmap.c revision 1.14 1 1.14 jruoho /* $NetBSD: t_mmap.c,v 1.14 2020/06/26 07:50:11 jruoho Exp $ */
2 1.1 jruoho
3 1.1 jruoho /*-
4 1.1 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 1.1 jruoho * All rights reserved.
6 1.1 jruoho *
7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation
8 1.1 jruoho * by Jukka Ruohonen.
9 1.1 jruoho *
10 1.1 jruoho * Redistribution and use in source and binary forms, with or without
11 1.1 jruoho * modification, are permitted provided that the following conditions
12 1.1 jruoho * are met:
13 1.1 jruoho * 1. Redistributions of source code must retain the above copyright
14 1.1 jruoho * notice, this list of conditions and the following disclaimer.
15 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jruoho * notice, this list of conditions and the following disclaimer in the
17 1.1 jruoho * documentation and/or other materials provided with the distribution.
18 1.1 jruoho *
19 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE.
30 1.1 jruoho */
31 1.2 jruoho
32 1.2 jruoho /*-
33 1.2 jruoho * Copyright (c)2004 YAMAMOTO Takashi,
34 1.2 jruoho * All rights reserved.
35 1.2 jruoho *
36 1.2 jruoho * Redistribution and use in source and binary forms, with or without
37 1.2 jruoho * modification, are permitted provided that the following conditions
38 1.2 jruoho * are met:
39 1.2 jruoho * 1. Redistributions of source code must retain the above copyright
40 1.2 jruoho * notice, this list of conditions and the following disclaimer.
41 1.2 jruoho * 2. Redistributions in binary form must reproduce the above copyright
42 1.2 jruoho * notice, this list of conditions and the following disclaimer in the
43 1.2 jruoho * documentation and/or other materials provided with the distribution.
44 1.2 jruoho *
45 1.2 jruoho * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46 1.2 jruoho * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 1.2 jruoho * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 1.2 jruoho * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 1.2 jruoho * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 1.2 jruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 1.2 jruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 1.2 jruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 1.2 jruoho * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 1.2 jruoho * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 1.2 jruoho * SUCH DAMAGE.
56 1.2 jruoho */
57 1.1 jruoho #include <sys/cdefs.h>
58 1.14 jruoho __RCSID("$NetBSD: t_mmap.c,v 1.14 2020/06/26 07:50:11 jruoho Exp $");
59 1.1 jruoho
60 1.1 jruoho #include <sys/param.h>
61 1.12 christos #include <sys/disklabel.h>
62 1.1 jruoho #include <sys/mman.h>
63 1.10 christos #include <sys/stat.h>
64 1.2 jruoho #include <sys/socket.h>
65 1.1 jruoho #include <sys/sysctl.h>
66 1.1 jruoho #include <sys/wait.h>
67 1.1 jruoho
68 1.2 jruoho #include <atf-c.h>
69 1.1 jruoho #include <errno.h>
70 1.1 jruoho #include <fcntl.h>
71 1.1 jruoho #include <signal.h>
72 1.3 jruoho #include <stdio.h>
73 1.1 jruoho #include <stdlib.h>
74 1.1 jruoho #include <string.h>
75 1.1 jruoho #include <unistd.h>
76 1.5 martin #include <paths.h>
77 1.1 jruoho
78 1.1 jruoho static long page = 0;
79 1.1 jruoho static char path[] = "mmap";
80 1.1 jruoho static void map_check(void *, int);
81 1.1 jruoho static void map_sighandler(int);
82 1.2 jruoho static void testloan(void *, void *, char, int);
83 1.2 jruoho
84 1.2 jruoho #define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */
85 1.1 jruoho
86 1.1 jruoho static void
87 1.1 jruoho map_check(void *map, int flag)
88 1.1 jruoho {
89 1.1 jruoho
90 1.1 jruoho if (flag != 0) {
91 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED);
92 1.1 jruoho return;
93 1.1 jruoho }
94 1.1 jruoho
95 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED);
96 1.1 jruoho ATF_REQUIRE(munmap(map, page) == 0);
97 1.1 jruoho }
98 1.1 jruoho
99 1.2 jruoho void
100 1.2 jruoho testloan(void *vp, void *vp2, char pat, int docheck)
101 1.2 jruoho {
102 1.2 jruoho char buf[BUFSIZE];
103 1.2 jruoho char backup[BUFSIZE];
104 1.2 jruoho ssize_t nwritten;
105 1.2 jruoho ssize_t nread;
106 1.2 jruoho int fds[2];
107 1.2 jruoho int val;
108 1.2 jruoho
109 1.2 jruoho val = BUFSIZE;
110 1.2 jruoho
111 1.2 jruoho if (docheck != 0)
112 1.2 jruoho (void)memcpy(backup, vp, BUFSIZE);
113 1.2 jruoho
114 1.2 jruoho if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0)
115 1.2 jruoho atf_tc_fail("socketpair() failed");
116 1.2 jruoho
117 1.2 jruoho val = BUFSIZE;
118 1.2 jruoho
119 1.2 jruoho if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0)
120 1.2 jruoho atf_tc_fail("setsockopt() failed, SO_RCVBUF");
121 1.2 jruoho
122 1.2 jruoho val = BUFSIZE;
123 1.2 jruoho
124 1.2 jruoho if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0)
125 1.2 jruoho atf_tc_fail("setsockopt() failed, SO_SNDBUF");
126 1.2 jruoho
127 1.2 jruoho if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0)
128 1.2 jruoho atf_tc_fail("fcntl() failed");
129 1.2 jruoho
130 1.2 jruoho nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page);
131 1.2 jruoho
132 1.2 jruoho if (nwritten == -1)
133 1.2 jruoho atf_tc_fail("write() failed");
134 1.2 jruoho
135 1.2 jruoho /* Break loan. */
136 1.2 jruoho (void)memset(vp2, pat, BUFSIZE);
137 1.2 jruoho
138 1.2 jruoho nread = read(fds[1], buf + page, BUFSIZE - page);
139 1.2 jruoho
140 1.2 jruoho if (nread == -1)
141 1.2 jruoho atf_tc_fail("read() failed");
142 1.2 jruoho
143 1.2 jruoho if (nread != nwritten)
144 1.2 jruoho atf_tc_fail("too short read");
145 1.2 jruoho
146 1.2 jruoho if (docheck != 0 && memcmp(backup, buf + page, nread) != 0)
147 1.2 jruoho atf_tc_fail("data mismatch");
148 1.2 jruoho
149 1.2 jruoho ATF_REQUIRE(close(fds[0]) == 0);
150 1.2 jruoho ATF_REQUIRE(close(fds[1]) == 0);
151 1.2 jruoho }
152 1.2 jruoho
153 1.1 jruoho static void
154 1.1 jruoho map_sighandler(int signo)
155 1.1 jruoho {
156 1.1 jruoho _exit(signo);
157 1.1 jruoho }
158 1.1 jruoho
159 1.3 jruoho ATF_TC(mmap_block);
160 1.3 jruoho ATF_TC_HEAD(mmap_block, tc)
161 1.3 jruoho {
162 1.3 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device");
163 1.5 martin atf_tc_set_md_var(tc, "require.user", "root");
164 1.3 jruoho }
165 1.3 jruoho
166 1.3 jruoho ATF_TC_BODY(mmap_block, tc)
167 1.3 jruoho {
168 1.5 martin static const int mib[] = { CTL_HW, HW_DISKNAMES };
169 1.5 martin static const unsigned int miblen = __arraycount(mib);
170 1.5 martin char *map, *dk, *drives, dev[PATH_MAX];
171 1.5 martin size_t len;
172 1.5 martin int fd = -1;
173 1.3 jruoho
174 1.14 jruoho atf_tc_skip("The test case causes a panic " \
175 1.14 jruoho "(PR kern/38889, PR kern/46592)");
176 1.3 jruoho
177 1.5 martin ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0);
178 1.5 martin drives = malloc(len);
179 1.5 martin ATF_REQUIRE(drives != NULL);
180 1.5 martin ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0);
181 1.5 martin for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) {
182 1.13 christos if (strncmp(dk, "dk", 2) == 0)
183 1.13 christos snprintf(dev, sizeof(dev), _PATH_DEV "%s", dk);
184 1.13 christos else
185 1.13 christos snprintf(dev, sizeof(dev), _PATH_DEV "%s%c", dk,
186 1.13 christos 'a' + RAW_PART);
187 1.5 martin fprintf(stderr, "trying: %s\n", dev);
188 1.3 jruoho
189 1.5 martin if ((fd = open(dev, O_RDONLY)) >= 0) {
190 1.5 martin (void)fprintf(stderr, "using %s\n", dev);
191 1.3 jruoho break;
192 1.13 christos } else
193 1.13 christos (void)fprintf(stderr, "%s: %s\n", dev, strerror(errno));
194 1.3 jruoho }
195 1.5 martin free(drives);
196 1.3 jruoho
197 1.5 martin if (fd < 0)
198 1.4 jruoho atf_tc_skip("failed to find suitable block device");
199 1.3 jruoho
200 1.3 jruoho map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0);
201 1.13 christos ATF_REQUIRE_MSG(map != MAP_FAILED, "mmap: %s", strerror(errno));
202 1.3 jruoho
203 1.3 jruoho (void)fprintf(stderr, "first byte %x\n", *map);
204 1.3 jruoho ATF_REQUIRE(close(fd) == 0);
205 1.3 jruoho (void)fprintf(stderr, "first byte %x\n", *map);
206 1.3 jruoho
207 1.3 jruoho ATF_REQUIRE(munmap(map, 4096) == 0);
208 1.3 jruoho }
209 1.3 jruoho
210 1.1 jruoho ATF_TC(mmap_err);
211 1.1 jruoho ATF_TC_HEAD(mmap_err, tc)
212 1.1 jruoho {
213 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)");
214 1.1 jruoho }
215 1.1 jruoho
216 1.1 jruoho ATF_TC_BODY(mmap_err, tc)
217 1.1 jruoho {
218 1.1 jruoho size_t addr = SIZE_MAX;
219 1.1 jruoho void *map;
220 1.1 jruoho
221 1.1 jruoho errno = 0;
222 1.1 jruoho map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0);
223 1.1 jruoho
224 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED);
225 1.1 jruoho ATF_REQUIRE(errno == EBADF);
226 1.1 jruoho
227 1.1 jruoho errno = 0;
228 1.1 jruoho map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0);
229 1.1 jruoho
230 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED);
231 1.1 jruoho ATF_REQUIRE(errno == EINVAL);
232 1.1 jruoho
233 1.1 jruoho errno = 0;
234 1.1 jruoho map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0);
235 1.1 jruoho
236 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED);
237 1.1 jruoho ATF_REQUIRE(errno == EINVAL);
238 1.1 jruoho }
239 1.1 jruoho
240 1.2 jruoho ATF_TC_WITH_CLEANUP(mmap_loan);
241 1.2 jruoho ATF_TC_HEAD(mmap_loan, tc)
242 1.2 jruoho {
243 1.2 jruoho atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)");
244 1.2 jruoho }
245 1.2 jruoho
246 1.2 jruoho ATF_TC_BODY(mmap_loan, tc)
247 1.2 jruoho {
248 1.2 jruoho char buf[BUFSIZE];
249 1.2 jruoho char *vp, *vp2;
250 1.2 jruoho int fd;
251 1.2 jruoho
252 1.2 jruoho fd = open(path, O_RDWR | O_CREAT, 0600);
253 1.2 jruoho ATF_REQUIRE(fd >= 0);
254 1.2 jruoho
255 1.2 jruoho (void)memset(buf, 'x', sizeof(buf));
256 1.2 jruoho (void)write(fd, buf, sizeof(buf));
257 1.2 jruoho
258 1.2 jruoho vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
259 1.2 jruoho MAP_FILE | MAP_PRIVATE, fd, 0);
260 1.2 jruoho
261 1.2 jruoho ATF_REQUIRE(vp != MAP_FAILED);
262 1.2 jruoho
263 1.2 jruoho vp2 = vp;
264 1.2 jruoho
265 1.2 jruoho testloan(vp, vp2, 'A', 0);
266 1.2 jruoho testloan(vp, vp2, 'B', 1);
267 1.2 jruoho
268 1.2 jruoho ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
269 1.2 jruoho
270 1.2 jruoho vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
271 1.2 jruoho MAP_FILE | MAP_SHARED, fd, 0);
272 1.2 jruoho
273 1.2 jruoho vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE,
274 1.2 jruoho MAP_FILE | MAP_SHARED, fd, 0);
275 1.2 jruoho
276 1.2 jruoho ATF_REQUIRE(vp != MAP_FAILED);
277 1.2 jruoho ATF_REQUIRE(vp2 != MAP_FAILED);
278 1.2 jruoho
279 1.2 jruoho testloan(vp, vp2, 'E', 1);
280 1.2 jruoho
281 1.2 jruoho ATF_REQUIRE(munmap(vp, BUFSIZE) == 0);
282 1.2 jruoho ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0);
283 1.2 jruoho }
284 1.2 jruoho
285 1.2 jruoho ATF_TC_CLEANUP(mmap_loan, tc)
286 1.2 jruoho {
287 1.2 jruoho (void)unlink(path);
288 1.2 jruoho }
289 1.2 jruoho
290 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_prot_1);
291 1.1 jruoho ATF_TC_HEAD(mmap_prot_1, tc)
292 1.1 jruoho {
293 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1");
294 1.1 jruoho }
295 1.1 jruoho
296 1.1 jruoho ATF_TC_BODY(mmap_prot_1, tc)
297 1.1 jruoho {
298 1.1 jruoho void *map;
299 1.1 jruoho int fd;
300 1.1 jruoho
301 1.1 jruoho /*
302 1.1 jruoho * Open a file write-only and try to
303 1.1 jruoho * map it read-only. This should fail.
304 1.1 jruoho */
305 1.1 jruoho fd = open(path, O_WRONLY | O_CREAT, 0700);
306 1.1 jruoho
307 1.1 jruoho if (fd < 0)
308 1.1 jruoho return;
309 1.1 jruoho
310 1.1 jruoho ATF_REQUIRE(write(fd, "XXX", 3) == 3);
311 1.1 jruoho
312 1.1 jruoho map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
313 1.1 jruoho map_check(map, 1);
314 1.1 jruoho
315 1.1 jruoho map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
316 1.1 jruoho map_check(map, 0);
317 1.1 jruoho
318 1.1 jruoho ATF_REQUIRE(close(fd) == 0);
319 1.1 jruoho }
320 1.1 jruoho
321 1.1 jruoho ATF_TC_CLEANUP(mmap_prot_1, tc)
322 1.1 jruoho {
323 1.1 jruoho (void)unlink(path);
324 1.1 jruoho }
325 1.1 jruoho
326 1.1 jruoho ATF_TC(mmap_prot_2);
327 1.1 jruoho ATF_TC_HEAD(mmap_prot_2, tc)
328 1.1 jruoho {
329 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2");
330 1.1 jruoho }
331 1.1 jruoho
332 1.1 jruoho ATF_TC_BODY(mmap_prot_2, tc)
333 1.1 jruoho {
334 1.1 jruoho char buf[2];
335 1.1 jruoho void *map;
336 1.1 jruoho pid_t pid;
337 1.1 jruoho int sta;
338 1.1 jruoho
339 1.1 jruoho /*
340 1.1 jruoho * Make a PROT_NONE mapping and try to access it.
341 1.1 jruoho * If we catch a SIGSEGV, all works as expected.
342 1.1 jruoho */
343 1.1 jruoho map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
344 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED);
345 1.1 jruoho
346 1.1 jruoho pid = fork();
347 1.1 jruoho ATF_REQUIRE(pid >= 0);
348 1.1 jruoho
349 1.1 jruoho if (pid == 0) {
350 1.1 jruoho ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
351 1.1 jruoho ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
352 1.1 jruoho }
353 1.1 jruoho
354 1.1 jruoho (void)wait(&sta);
355 1.1 jruoho
356 1.1 jruoho ATF_REQUIRE(WIFEXITED(sta) != 0);
357 1.1 jruoho ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
358 1.1 jruoho ATF_REQUIRE(munmap(map, page) == 0);
359 1.1 jruoho }
360 1.1 jruoho
361 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_prot_3);
362 1.1 jruoho ATF_TC_HEAD(mmap_prot_3, tc)
363 1.1 jruoho {
364 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3");
365 1.1 jruoho }
366 1.1 jruoho
367 1.1 jruoho ATF_TC_BODY(mmap_prot_3, tc)
368 1.1 jruoho {
369 1.1 jruoho char buf[2];
370 1.1 jruoho int fd, sta;
371 1.1 jruoho void *map;
372 1.1 jruoho pid_t pid;
373 1.1 jruoho
374 1.1 jruoho /*
375 1.1 jruoho * Open a file, change the permissions
376 1.1 jruoho * to read-only, and try to map it as
377 1.1 jruoho * PROT_NONE. This should succeed, but
378 1.1 jruoho * the access should generate SIGSEGV.
379 1.1 jruoho */
380 1.1 jruoho fd = open(path, O_RDWR | O_CREAT, 0700);
381 1.1 jruoho
382 1.1 jruoho if (fd < 0)
383 1.1 jruoho return;
384 1.1 jruoho
385 1.1 jruoho ATF_REQUIRE(write(fd, "XXX", 3) == 3);
386 1.1 jruoho ATF_REQUIRE(close(fd) == 0);
387 1.1 jruoho ATF_REQUIRE(chmod(path, 0444) == 0);
388 1.1 jruoho
389 1.1 jruoho fd = open(path, O_RDONLY);
390 1.1 jruoho ATF_REQUIRE(fd != -1);
391 1.1 jruoho
392 1.1 jruoho map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0);
393 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED);
394 1.1 jruoho
395 1.1 jruoho pid = fork();
396 1.1 jruoho
397 1.1 jruoho ATF_REQUIRE(pid >= 0);
398 1.1 jruoho
399 1.1 jruoho if (pid == 0) {
400 1.1 jruoho ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
401 1.1 jruoho ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0);
402 1.1 jruoho }
403 1.1 jruoho
404 1.1 jruoho (void)wait(&sta);
405 1.1 jruoho
406 1.1 jruoho ATF_REQUIRE(WIFEXITED(sta) != 0);
407 1.1 jruoho ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV);
408 1.1 jruoho ATF_REQUIRE(munmap(map, 3) == 0);
409 1.1 jruoho }
410 1.1 jruoho
411 1.1 jruoho ATF_TC_CLEANUP(mmap_prot_3, tc)
412 1.1 jruoho {
413 1.1 jruoho (void)unlink(path);
414 1.1 jruoho }
415 1.1 jruoho
416 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_truncate);
417 1.1 jruoho ATF_TC_HEAD(mmap_truncate, tc)
418 1.1 jruoho {
419 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)");
420 1.1 jruoho }
421 1.1 jruoho
422 1.1 jruoho ATF_TC_BODY(mmap_truncate, tc)
423 1.1 jruoho {
424 1.1 jruoho char *map;
425 1.1 jruoho long i;
426 1.1 jruoho int fd;
427 1.1 jruoho
428 1.1 jruoho fd = open(path, O_RDWR | O_CREAT, 0700);
429 1.1 jruoho
430 1.1 jruoho if (fd < 0)
431 1.1 jruoho return;
432 1.1 jruoho
433 1.1 jruoho /*
434 1.1 jruoho * See that ftruncate(2) works
435 1.1 jruoho * while the file is mapped.
436 1.1 jruoho */
437 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page) == 0);
438 1.1 jruoho
439 1.1 jruoho map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE,
440 1.1 jruoho fd, 0);
441 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED);
442 1.1 jruoho
443 1.1 jruoho for (i = 0; i < page; i++)
444 1.1 jruoho map[i] = 'x';
445 1.1 jruoho
446 1.1 jruoho ATF_REQUIRE(ftruncate(fd, 0) == 0);
447 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 8) == 0);
448 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 4) == 0);
449 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 2) == 0);
450 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 12) == 0);
451 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 64) == 0);
452 1.1 jruoho
453 1.11 christos (void)munmap(map, page);
454 1.1 jruoho ATF_REQUIRE(close(fd) == 0);
455 1.1 jruoho }
456 1.1 jruoho
457 1.1 jruoho ATF_TC_CLEANUP(mmap_truncate, tc)
458 1.1 jruoho {
459 1.1 jruoho (void)unlink(path);
460 1.1 jruoho }
461 1.1 jruoho
462 1.8 christos ATF_TC_WITH_CLEANUP(mmap_truncate_signal);
463 1.8 christos ATF_TC_HEAD(mmap_truncate_signal, tc)
464 1.8 christos {
465 1.8 christos atf_tc_set_md_var(tc, "descr",
466 1.8 christos "Test mmap(2) ftruncate(2) causing signal");
467 1.8 christos }
468 1.8 christos
469 1.8 christos ATF_TC_BODY(mmap_truncate_signal, tc)
470 1.8 christos {
471 1.8 christos char *map;
472 1.8 christos long i;
473 1.8 christos int fd, sta;
474 1.8 christos pid_t pid;
475 1.8 christos
476 1.8 christos fd = open(path, O_RDWR | O_CREAT, 0700);
477 1.8 christos
478 1.8 christos if (fd < 0)
479 1.8 christos return;
480 1.8 christos
481 1.8 christos ATF_REQUIRE(write(fd, "foo\n", 5) == 5);
482 1.8 christos
483 1.8 christos map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
484 1.8 christos ATF_REQUIRE(map != MAP_FAILED);
485 1.8 christos
486 1.8 christos sta = 0;
487 1.8 christos for (i = 0; i < 5; i++)
488 1.8 christos sta += map[i];
489 1.8 christos ATF_REQUIRE(sta == 334);
490 1.8 christos
491 1.8 christos ATF_REQUIRE(ftruncate(fd, 0) == 0);
492 1.8 christos pid = fork();
493 1.8 christos ATF_REQUIRE(pid >= 0);
494 1.8 christos
495 1.8 christos if (pid == 0) {
496 1.8 christos ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR);
497 1.9 martin ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR);
498 1.8 christos sta = 0;
499 1.8 christos for (i = 0; i < page; i++)
500 1.8 christos sta += map[i];
501 1.9 martin /* child never will get this far, but the compiler will
502 1.9 martin not know, so better use the values calculated to
503 1.9 martin prevent the access to be optimized out */
504 1.8 christos ATF_REQUIRE(i == 0);
505 1.9 martin ATF_REQUIRE(sta == 0);
506 1.11 christos (void)munmap(map, page);
507 1.11 christos (void)close(fd);
508 1.9 martin return;
509 1.8 christos }
510 1.8 christos
511 1.8 christos (void)wait(&sta);
512 1.8 christos
513 1.8 christos ATF_REQUIRE(WIFEXITED(sta) != 0);
514 1.9 martin if (WEXITSTATUS(sta) == SIGSEGV)
515 1.9 martin atf_tc_fail("child process got SIGSEGV instead of SIGBUS");
516 1.8 christos ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS);
517 1.8 christos ATF_REQUIRE(munmap(map, page) == 0);
518 1.8 christos ATF_REQUIRE(close(fd) == 0);
519 1.8 christos }
520 1.8 christos
521 1.8 christos ATF_TC_CLEANUP(mmap_truncate_signal, tc)
522 1.8 christos {
523 1.8 christos (void)unlink(path);
524 1.8 christos }
525 1.8 christos
526 1.1 jruoho ATF_TC(mmap_va0);
527 1.1 jruoho ATF_TC_HEAD(mmap_va0, tc)
528 1.1 jruoho {
529 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable");
530 1.1 jruoho }
531 1.1 jruoho
532 1.1 jruoho ATF_TC_BODY(mmap_va0, tc)
533 1.1 jruoho {
534 1.1 jruoho int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE;
535 1.1 jruoho size_t len = sizeof(int);
536 1.1 jruoho void *map;
537 1.1 jruoho int val;
538 1.1 jruoho
539 1.1 jruoho /*
540 1.1 jruoho * Make an anonymous fixed mapping at zero address. If the address
541 1.1 jruoho * is restricted as noted in security(7), the syscall should fail.
542 1.1 jruoho */
543 1.1 jruoho if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0)
544 1.1 jruoho atf_tc_fail("failed to read vm.user_va0_disable");
545 1.1 jruoho
546 1.1 jruoho map = mmap(NULL, page, PROT_EXEC, flags, -1, 0);
547 1.1 jruoho map_check(map, val);
548 1.1 jruoho
549 1.1 jruoho map = mmap(NULL, page, PROT_READ, flags, -1, 0);
550 1.1 jruoho map_check(map, val);
551 1.1 jruoho
552 1.1 jruoho map = mmap(NULL, page, PROT_WRITE, flags, -1, 0);
553 1.1 jruoho map_check(map, val);
554 1.1 jruoho
555 1.1 jruoho map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0);
556 1.1 jruoho map_check(map, val);
557 1.1 jruoho
558 1.1 jruoho map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0);
559 1.1 jruoho map_check(map, val);
560 1.1 jruoho }
561 1.1 jruoho
562 1.1 jruoho ATF_TP_ADD_TCS(tp)
563 1.1 jruoho {
564 1.1 jruoho page = sysconf(_SC_PAGESIZE);
565 1.1 jruoho ATF_REQUIRE(page >= 0);
566 1.1 jruoho
567 1.3 jruoho ATF_TP_ADD_TC(tp, mmap_block);
568 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_err);
569 1.2 jruoho ATF_TP_ADD_TC(tp, mmap_loan);
570 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_1);
571 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_2);
572 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_3);
573 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_truncate);
574 1.8 christos ATF_TP_ADD_TC(tp, mmap_truncate_signal);
575 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_va0);
576 1.1 jruoho
577 1.1 jruoho return atf_no_error();
578 1.1 jruoho }
579