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