1 1.18 riastrad /* $NetBSD: t_mmap.c,v 1.18 2022/06/04 23:09:18 riastradh 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.18 riastrad __RCSID("$NetBSD: t_mmap.c,v 1.18 2022/06/04 23:09:18 riastradh 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.17 gson #include <pthread.h> 78 1.1 jruoho 79 1.1 jruoho static long page = 0; 80 1.1 jruoho static char path[] = "mmap"; 81 1.1 jruoho static void map_check(void *, int); 82 1.1 jruoho static void map_sighandler(int); 83 1.2 jruoho static void testloan(void *, void *, char, int); 84 1.2 jruoho 85 1.2 jruoho #define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */ 86 1.1 jruoho 87 1.1 jruoho static void 88 1.1 jruoho map_check(void *map, int flag) 89 1.1 jruoho { 90 1.1 jruoho 91 1.1 jruoho if (flag != 0) { 92 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED); 93 1.1 jruoho return; 94 1.1 jruoho } 95 1.1 jruoho 96 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED); 97 1.1 jruoho ATF_REQUIRE(munmap(map, page) == 0); 98 1.1 jruoho } 99 1.1 jruoho 100 1.2 jruoho void 101 1.2 jruoho testloan(void *vp, void *vp2, char pat, int docheck) 102 1.2 jruoho { 103 1.2 jruoho char buf[BUFSIZE]; 104 1.2 jruoho char backup[BUFSIZE]; 105 1.2 jruoho ssize_t nwritten; 106 1.2 jruoho ssize_t nread; 107 1.2 jruoho int fds[2]; 108 1.2 jruoho int val; 109 1.2 jruoho 110 1.2 jruoho val = BUFSIZE; 111 1.2 jruoho 112 1.2 jruoho if (docheck != 0) 113 1.2 jruoho (void)memcpy(backup, vp, BUFSIZE); 114 1.2 jruoho 115 1.2 jruoho if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0) 116 1.2 jruoho atf_tc_fail("socketpair() failed"); 117 1.2 jruoho 118 1.2 jruoho val = BUFSIZE; 119 1.2 jruoho 120 1.2 jruoho if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0) 121 1.2 jruoho atf_tc_fail("setsockopt() failed, SO_RCVBUF"); 122 1.2 jruoho 123 1.2 jruoho val = BUFSIZE; 124 1.2 jruoho 125 1.2 jruoho if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0) 126 1.2 jruoho atf_tc_fail("setsockopt() failed, SO_SNDBUF"); 127 1.2 jruoho 128 1.2 jruoho if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0) 129 1.2 jruoho atf_tc_fail("fcntl() failed"); 130 1.2 jruoho 131 1.2 jruoho nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page); 132 1.2 jruoho 133 1.2 jruoho if (nwritten == -1) 134 1.2 jruoho atf_tc_fail("write() failed"); 135 1.2 jruoho 136 1.2 jruoho /* Break loan. */ 137 1.2 jruoho (void)memset(vp2, pat, BUFSIZE); 138 1.2 jruoho 139 1.2 jruoho nread = read(fds[1], buf + page, BUFSIZE - page); 140 1.2 jruoho 141 1.2 jruoho if (nread == -1) 142 1.2 jruoho atf_tc_fail("read() failed"); 143 1.2 jruoho 144 1.2 jruoho if (nread != nwritten) 145 1.2 jruoho atf_tc_fail("too short read"); 146 1.2 jruoho 147 1.2 jruoho if (docheck != 0 && memcmp(backup, buf + page, nread) != 0) 148 1.2 jruoho atf_tc_fail("data mismatch"); 149 1.2 jruoho 150 1.2 jruoho ATF_REQUIRE(close(fds[0]) == 0); 151 1.2 jruoho ATF_REQUIRE(close(fds[1]) == 0); 152 1.2 jruoho } 153 1.2 jruoho 154 1.1 jruoho static void 155 1.1 jruoho map_sighandler(int signo) 156 1.1 jruoho { 157 1.1 jruoho _exit(signo); 158 1.1 jruoho } 159 1.1 jruoho 160 1.3 jruoho ATF_TC(mmap_block); 161 1.3 jruoho ATF_TC_HEAD(mmap_block, tc) 162 1.3 jruoho { 163 1.3 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device"); 164 1.5 martin atf_tc_set_md_var(tc, "require.user", "root"); 165 1.3 jruoho } 166 1.3 jruoho 167 1.3 jruoho ATF_TC_BODY(mmap_block, tc) 168 1.3 jruoho { 169 1.5 martin static const int mib[] = { CTL_HW, HW_DISKNAMES }; 170 1.5 martin static const unsigned int miblen = __arraycount(mib); 171 1.5 martin char *map, *dk, *drives, dev[PATH_MAX]; 172 1.5 martin size_t len; 173 1.5 martin int fd = -1; 174 1.3 jruoho 175 1.14 jruoho atf_tc_skip("The test case causes a panic " \ 176 1.14 jruoho "(PR kern/38889, PR kern/46592)"); 177 1.3 jruoho 178 1.5 martin ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0); 179 1.5 martin drives = malloc(len); 180 1.5 martin ATF_REQUIRE(drives != NULL); 181 1.5 martin ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0); 182 1.5 martin for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) { 183 1.13 christos if (strncmp(dk, "dk", 2) == 0) 184 1.13 christos snprintf(dev, sizeof(dev), _PATH_DEV "%s", dk); 185 1.13 christos else 186 1.13 christos snprintf(dev, sizeof(dev), _PATH_DEV "%s%c", dk, 187 1.13 christos 'a' + RAW_PART); 188 1.5 martin fprintf(stderr, "trying: %s\n", dev); 189 1.3 jruoho 190 1.5 martin if ((fd = open(dev, O_RDONLY)) >= 0) { 191 1.5 martin (void)fprintf(stderr, "using %s\n", dev); 192 1.3 jruoho break; 193 1.13 christos } else 194 1.13 christos (void)fprintf(stderr, "%s: %s\n", dev, strerror(errno)); 195 1.3 jruoho } 196 1.5 martin free(drives); 197 1.3 jruoho 198 1.5 martin if (fd < 0) 199 1.4 jruoho atf_tc_skip("failed to find suitable block device"); 200 1.3 jruoho 201 1.3 jruoho map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0); 202 1.13 christos ATF_REQUIRE_MSG(map != MAP_FAILED, "mmap: %s", strerror(errno)); 203 1.3 jruoho 204 1.3 jruoho (void)fprintf(stderr, "first byte %x\n", *map); 205 1.3 jruoho ATF_REQUIRE(close(fd) == 0); 206 1.3 jruoho (void)fprintf(stderr, "first byte %x\n", *map); 207 1.3 jruoho 208 1.3 jruoho ATF_REQUIRE(munmap(map, 4096) == 0); 209 1.3 jruoho } 210 1.3 jruoho 211 1.1 jruoho ATF_TC(mmap_err); 212 1.1 jruoho ATF_TC_HEAD(mmap_err, tc) 213 1.1 jruoho { 214 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)"); 215 1.1 jruoho } 216 1.1 jruoho 217 1.1 jruoho ATF_TC_BODY(mmap_err, tc) 218 1.1 jruoho { 219 1.16 gson void *addr = (void *)-1; 220 1.1 jruoho void *map; 221 1.1 jruoho 222 1.1 jruoho errno = 0; 223 1.1 jruoho map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0); 224 1.1 jruoho 225 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED); 226 1.1 jruoho ATF_REQUIRE(errno == EBADF); 227 1.1 jruoho 228 1.1 jruoho errno = 0; 229 1.16 gson map = mmap(addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0); 230 1.1 jruoho 231 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED); 232 1.15 gson ATF_REQUIRE_MSG(errno == EINVAL, "errno %d != EINVAL", errno); 233 1.1 jruoho 234 1.1 jruoho errno = 0; 235 1.1 jruoho map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0); 236 1.1 jruoho 237 1.1 jruoho ATF_REQUIRE(map == MAP_FAILED); 238 1.1 jruoho ATF_REQUIRE(errno == EINVAL); 239 1.1 jruoho } 240 1.1 jruoho 241 1.2 jruoho ATF_TC_WITH_CLEANUP(mmap_loan); 242 1.2 jruoho ATF_TC_HEAD(mmap_loan, tc) 243 1.2 jruoho { 244 1.2 jruoho atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)"); 245 1.2 jruoho } 246 1.2 jruoho 247 1.2 jruoho ATF_TC_BODY(mmap_loan, tc) 248 1.2 jruoho { 249 1.2 jruoho char buf[BUFSIZE]; 250 1.2 jruoho char *vp, *vp2; 251 1.2 jruoho int fd; 252 1.2 jruoho 253 1.2 jruoho fd = open(path, O_RDWR | O_CREAT, 0600); 254 1.2 jruoho ATF_REQUIRE(fd >= 0); 255 1.2 jruoho 256 1.2 jruoho (void)memset(buf, 'x', sizeof(buf)); 257 1.2 jruoho (void)write(fd, buf, sizeof(buf)); 258 1.2 jruoho 259 1.2 jruoho vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 260 1.2 jruoho MAP_FILE | MAP_PRIVATE, fd, 0); 261 1.2 jruoho 262 1.2 jruoho ATF_REQUIRE(vp != MAP_FAILED); 263 1.2 jruoho 264 1.2 jruoho vp2 = vp; 265 1.2 jruoho 266 1.2 jruoho testloan(vp, vp2, 'A', 0); 267 1.2 jruoho testloan(vp, vp2, 'B', 1); 268 1.2 jruoho 269 1.2 jruoho ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); 270 1.2 jruoho 271 1.2 jruoho vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 272 1.2 jruoho MAP_FILE | MAP_SHARED, fd, 0); 273 1.2 jruoho 274 1.2 jruoho vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, 275 1.2 jruoho MAP_FILE | MAP_SHARED, fd, 0); 276 1.2 jruoho 277 1.2 jruoho ATF_REQUIRE(vp != MAP_FAILED); 278 1.2 jruoho ATF_REQUIRE(vp2 != MAP_FAILED); 279 1.2 jruoho 280 1.2 jruoho testloan(vp, vp2, 'E', 1); 281 1.2 jruoho 282 1.2 jruoho ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); 283 1.2 jruoho ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0); 284 1.2 jruoho } 285 1.2 jruoho 286 1.2 jruoho ATF_TC_CLEANUP(mmap_loan, tc) 287 1.2 jruoho { 288 1.2 jruoho (void)unlink(path); 289 1.2 jruoho } 290 1.2 jruoho 291 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_prot_1); 292 1.1 jruoho ATF_TC_HEAD(mmap_prot_1, tc) 293 1.1 jruoho { 294 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1"); 295 1.1 jruoho } 296 1.1 jruoho 297 1.1 jruoho ATF_TC_BODY(mmap_prot_1, tc) 298 1.1 jruoho { 299 1.1 jruoho void *map; 300 1.1 jruoho int fd; 301 1.1 jruoho 302 1.1 jruoho /* 303 1.1 jruoho * Open a file write-only and try to 304 1.1 jruoho * map it read-only. This should fail. 305 1.1 jruoho */ 306 1.1 jruoho fd = open(path, O_WRONLY | O_CREAT, 0700); 307 1.1 jruoho 308 1.1 jruoho if (fd < 0) 309 1.1 jruoho return; 310 1.1 jruoho 311 1.1 jruoho ATF_REQUIRE(write(fd, "XXX", 3) == 3); 312 1.1 jruoho 313 1.1 jruoho map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 314 1.1 jruoho map_check(map, 1); 315 1.1 jruoho 316 1.1 jruoho map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0); 317 1.1 jruoho map_check(map, 0); 318 1.1 jruoho 319 1.1 jruoho ATF_REQUIRE(close(fd) == 0); 320 1.1 jruoho } 321 1.1 jruoho 322 1.1 jruoho ATF_TC_CLEANUP(mmap_prot_1, tc) 323 1.1 jruoho { 324 1.1 jruoho (void)unlink(path); 325 1.1 jruoho } 326 1.1 jruoho 327 1.1 jruoho ATF_TC(mmap_prot_2); 328 1.1 jruoho ATF_TC_HEAD(mmap_prot_2, tc) 329 1.1 jruoho { 330 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2"); 331 1.1 jruoho } 332 1.1 jruoho 333 1.1 jruoho ATF_TC_BODY(mmap_prot_2, tc) 334 1.1 jruoho { 335 1.1 jruoho char buf[2]; 336 1.1 jruoho void *map; 337 1.1 jruoho pid_t pid; 338 1.1 jruoho int sta; 339 1.1 jruoho 340 1.1 jruoho /* 341 1.1 jruoho * Make a PROT_NONE mapping and try to access it. 342 1.1 jruoho * If we catch a SIGSEGV, all works as expected. 343 1.1 jruoho */ 344 1.1 jruoho map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); 345 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED); 346 1.1 jruoho 347 1.1 jruoho pid = fork(); 348 1.1 jruoho ATF_REQUIRE(pid >= 0); 349 1.1 jruoho 350 1.1 jruoho if (pid == 0) { 351 1.1 jruoho ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 352 1.1 jruoho ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); 353 1.1 jruoho } 354 1.1 jruoho 355 1.1 jruoho (void)wait(&sta); 356 1.1 jruoho 357 1.1 jruoho ATF_REQUIRE(WIFEXITED(sta) != 0); 358 1.1 jruoho ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); 359 1.1 jruoho ATF_REQUIRE(munmap(map, page) == 0); 360 1.1 jruoho } 361 1.1 jruoho 362 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_prot_3); 363 1.1 jruoho ATF_TC_HEAD(mmap_prot_3, tc) 364 1.1 jruoho { 365 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3"); 366 1.1 jruoho } 367 1.1 jruoho 368 1.1 jruoho ATF_TC_BODY(mmap_prot_3, tc) 369 1.1 jruoho { 370 1.1 jruoho char buf[2]; 371 1.1 jruoho int fd, sta; 372 1.1 jruoho void *map; 373 1.1 jruoho pid_t pid; 374 1.1 jruoho 375 1.1 jruoho /* 376 1.1 jruoho * Open a file, change the permissions 377 1.1 jruoho * to read-only, and try to map it as 378 1.1 jruoho * PROT_NONE. This should succeed, but 379 1.1 jruoho * the access should generate SIGSEGV. 380 1.1 jruoho */ 381 1.1 jruoho fd = open(path, O_RDWR | O_CREAT, 0700); 382 1.1 jruoho 383 1.1 jruoho if (fd < 0) 384 1.1 jruoho return; 385 1.1 jruoho 386 1.1 jruoho ATF_REQUIRE(write(fd, "XXX", 3) == 3); 387 1.1 jruoho ATF_REQUIRE(close(fd) == 0); 388 1.1 jruoho ATF_REQUIRE(chmod(path, 0444) == 0); 389 1.1 jruoho 390 1.1 jruoho fd = open(path, O_RDONLY); 391 1.1 jruoho ATF_REQUIRE(fd != -1); 392 1.1 jruoho 393 1.1 jruoho map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); 394 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED); 395 1.1 jruoho 396 1.1 jruoho pid = fork(); 397 1.1 jruoho 398 1.1 jruoho ATF_REQUIRE(pid >= 0); 399 1.1 jruoho 400 1.1 jruoho if (pid == 0) { 401 1.1 jruoho ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 402 1.1 jruoho ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); 403 1.1 jruoho } 404 1.1 jruoho 405 1.1 jruoho (void)wait(&sta); 406 1.1 jruoho 407 1.1 jruoho ATF_REQUIRE(WIFEXITED(sta) != 0); 408 1.1 jruoho ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); 409 1.1 jruoho ATF_REQUIRE(munmap(map, 3) == 0); 410 1.1 jruoho } 411 1.1 jruoho 412 1.1 jruoho ATF_TC_CLEANUP(mmap_prot_3, tc) 413 1.1 jruoho { 414 1.1 jruoho (void)unlink(path); 415 1.1 jruoho } 416 1.1 jruoho 417 1.17 gson ATF_TC(mmap_reprotect_race); 418 1.17 gson 419 1.17 gson ATF_TC_HEAD(mmap_reprotect_race, tc) 420 1.17 gson { 421 1.17 gson atf_tc_set_md_var(tc, "descr", "Test for the race condition of PR 52239"); 422 1.17 gson } 423 1.17 gson 424 1.17 gson const int mmap_reprotect_race_npages = 13; 425 1.17 gson const int mmap_reprotect_iterations = 1000000; 426 1.17 gson 427 1.17 gson static void * 428 1.17 gson mmap_reprotect_race_thread(void *arg) 429 1.17 gson { 430 1.17 gson int i, r; 431 1.17 gson void *p; 432 1.17 gson 433 1.17 gson for (i = 0; i < mmap_reprotect_iterations; i++) { 434 1.17 gson /* Get some unrelated memory */ 435 1.17 gson p = mmap(0, mmap_reprotect_race_npages * page, 436 1.17 gson PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); 437 1.17 gson ATF_REQUIRE(p); 438 1.17 gson r = munmap(p, mmap_reprotect_race_npages * page); 439 1.17 gson ATF_REQUIRE(r == 0); 440 1.17 gson } 441 1.17 gson return 0; 442 1.17 gson } 443 1.17 gson 444 1.17 gson ATF_TC_BODY(mmap_reprotect_race, tc) 445 1.17 gson { 446 1.17 gson pthread_t thread; 447 1.17 gson void *p, *q; 448 1.17 gson int i, r; 449 1.17 gson 450 1.17 gson r = pthread_create(&thread, 0, mmap_reprotect_race_thread, 0); 451 1.17 gson ATF_REQUIRE(r == 0); 452 1.17 gson 453 1.17 gson for (i = 0; i < mmap_reprotect_iterations; i++) { 454 1.17 gson /* Get a placeholder region */ 455 1.17 gson p = mmap(0, mmap_reprotect_race_npages * page, 456 1.17 gson PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); 457 1.17 gson if (p == MAP_FAILED) 458 1.17 gson atf_tc_fail("mmap: %s", strerror(errno)); 459 1.17 gson 460 1.17 gson /* Upgrade placeholder to read/write access */ 461 1.17 gson q = mmap(p, mmap_reprotect_race_npages * page, 462 1.17 gson PROT_READ|PROT_WRITE, 463 1.17 gson MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); 464 1.17 gson if (q == MAP_FAILED) 465 1.17 gson atf_tc_fail("update mmap: %s", strerror(errno)); 466 1.17 gson ATF_REQUIRE(q == p); 467 1.17 gson 468 1.17 gson /* Free it */ 469 1.17 gson r = munmap(q, mmap_reprotect_race_npages * page); 470 1.17 gson if (r != 0) 471 1.17 gson atf_tc_fail("munmap: %s", strerror(errno)); 472 1.17 gson } 473 1.17 gson pthread_join(thread, NULL); 474 1.17 gson } 475 1.17 gson 476 1.1 jruoho ATF_TC_WITH_CLEANUP(mmap_truncate); 477 1.1 jruoho ATF_TC_HEAD(mmap_truncate, tc) 478 1.1 jruoho { 479 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)"); 480 1.1 jruoho } 481 1.1 jruoho 482 1.1 jruoho ATF_TC_BODY(mmap_truncate, tc) 483 1.1 jruoho { 484 1.1 jruoho char *map; 485 1.1 jruoho long i; 486 1.1 jruoho int fd; 487 1.1 jruoho 488 1.1 jruoho fd = open(path, O_RDWR | O_CREAT, 0700); 489 1.1 jruoho 490 1.1 jruoho if (fd < 0) 491 1.1 jruoho return; 492 1.1 jruoho 493 1.1 jruoho /* 494 1.1 jruoho * See that ftruncate(2) works 495 1.1 jruoho * while the file is mapped. 496 1.1 jruoho */ 497 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page) == 0); 498 1.1 jruoho 499 1.1 jruoho map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 500 1.1 jruoho fd, 0); 501 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED); 502 1.1 jruoho 503 1.1 jruoho for (i = 0; i < page; i++) 504 1.1 jruoho map[i] = 'x'; 505 1.1 jruoho 506 1.1 jruoho ATF_REQUIRE(ftruncate(fd, 0) == 0); 507 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 8) == 0); 508 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 4) == 0); 509 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 2) == 0); 510 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 12) == 0); 511 1.1 jruoho ATF_REQUIRE(ftruncate(fd, page / 64) == 0); 512 1.1 jruoho 513 1.11 christos (void)munmap(map, page); 514 1.1 jruoho ATF_REQUIRE(close(fd) == 0); 515 1.1 jruoho } 516 1.1 jruoho 517 1.1 jruoho ATF_TC_CLEANUP(mmap_truncate, tc) 518 1.1 jruoho { 519 1.1 jruoho (void)unlink(path); 520 1.1 jruoho } 521 1.1 jruoho 522 1.8 christos ATF_TC_WITH_CLEANUP(mmap_truncate_signal); 523 1.8 christos ATF_TC_HEAD(mmap_truncate_signal, tc) 524 1.8 christos { 525 1.8 christos atf_tc_set_md_var(tc, "descr", 526 1.8 christos "Test mmap(2) ftruncate(2) causing signal"); 527 1.8 christos } 528 1.8 christos 529 1.8 christos ATF_TC_BODY(mmap_truncate_signal, tc) 530 1.8 christos { 531 1.8 christos char *map; 532 1.8 christos long i; 533 1.8 christos int fd, sta; 534 1.8 christos pid_t pid; 535 1.8 christos 536 1.8 christos fd = open(path, O_RDWR | O_CREAT, 0700); 537 1.8 christos 538 1.8 christos if (fd < 0) 539 1.8 christos return; 540 1.8 christos 541 1.8 christos ATF_REQUIRE(write(fd, "foo\n", 5) == 5); 542 1.8 christos 543 1.8 christos map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 544 1.8 christos ATF_REQUIRE(map != MAP_FAILED); 545 1.8 christos 546 1.8 christos sta = 0; 547 1.8 christos for (i = 0; i < 5; i++) 548 1.8 christos sta += map[i]; 549 1.8 christos ATF_REQUIRE(sta == 334); 550 1.8 christos 551 1.8 christos ATF_REQUIRE(ftruncate(fd, 0) == 0); 552 1.8 christos pid = fork(); 553 1.8 christos ATF_REQUIRE(pid >= 0); 554 1.8 christos 555 1.8 christos if (pid == 0) { 556 1.8 christos ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR); 557 1.9 martin ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); 558 1.8 christos sta = 0; 559 1.8 christos for (i = 0; i < page; i++) 560 1.8 christos sta += map[i]; 561 1.9 martin /* child never will get this far, but the compiler will 562 1.9 martin not know, so better use the values calculated to 563 1.9 martin prevent the access to be optimized out */ 564 1.8 christos ATF_REQUIRE(i == 0); 565 1.9 martin ATF_REQUIRE(sta == 0); 566 1.11 christos (void)munmap(map, page); 567 1.11 christos (void)close(fd); 568 1.9 martin return; 569 1.8 christos } 570 1.8 christos 571 1.8 christos (void)wait(&sta); 572 1.8 christos 573 1.8 christos ATF_REQUIRE(WIFEXITED(sta) != 0); 574 1.9 martin if (WEXITSTATUS(sta) == SIGSEGV) 575 1.9 martin atf_tc_fail("child process got SIGSEGV instead of SIGBUS"); 576 1.8 christos ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS); 577 1.8 christos ATF_REQUIRE(munmap(map, page) == 0); 578 1.8 christos ATF_REQUIRE(close(fd) == 0); 579 1.8 christos } 580 1.8 christos 581 1.8 christos ATF_TC_CLEANUP(mmap_truncate_signal, tc) 582 1.8 christos { 583 1.8 christos (void)unlink(path); 584 1.8 christos } 585 1.8 christos 586 1.1 jruoho ATF_TC(mmap_va0); 587 1.1 jruoho ATF_TC_HEAD(mmap_va0, tc) 588 1.1 jruoho { 589 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable"); 590 1.1 jruoho } 591 1.1 jruoho 592 1.1 jruoho ATF_TC_BODY(mmap_va0, tc) 593 1.1 jruoho { 594 1.1 jruoho int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE; 595 1.1 jruoho size_t len = sizeof(int); 596 1.1 jruoho void *map; 597 1.1 jruoho int val; 598 1.1 jruoho 599 1.1 jruoho /* 600 1.1 jruoho * Make an anonymous fixed mapping at zero address. If the address 601 1.1 jruoho * is restricted as noted in security(7), the syscall should fail. 602 1.1 jruoho */ 603 1.1 jruoho if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0) 604 1.1 jruoho atf_tc_fail("failed to read vm.user_va0_disable"); 605 1.1 jruoho 606 1.1 jruoho map = mmap(NULL, page, PROT_EXEC, flags, -1, 0); 607 1.1 jruoho map_check(map, val); 608 1.1 jruoho 609 1.1 jruoho map = mmap(NULL, page, PROT_READ, flags, -1, 0); 610 1.1 jruoho map_check(map, val); 611 1.1 jruoho 612 1.1 jruoho map = mmap(NULL, page, PROT_WRITE, flags, -1, 0); 613 1.1 jruoho map_check(map, val); 614 1.1 jruoho 615 1.1 jruoho map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0); 616 1.1 jruoho map_check(map, val); 617 1.1 jruoho 618 1.1 jruoho map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0); 619 1.1 jruoho map_check(map, val); 620 1.1 jruoho } 621 1.1 jruoho 622 1.18 riastrad static void 623 1.18 riastrad test_mmap_hint(uintptr_t hintaddr) 624 1.18 riastrad { 625 1.18 riastrad void *hint = (void *)hintaddr; 626 1.18 riastrad void *map1 = MAP_FAILED, *map2 = MAP_FAILED, *map3 = MAP_FAILED; 627 1.18 riastrad 628 1.18 riastrad map1 = mmap(hint, page, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 629 1.18 riastrad if (map1 == MAP_FAILED) { 630 1.18 riastrad atf_tc_fail_nonfatal("mmap1 hint=%p: errno=%d", hint, errno); 631 1.18 riastrad goto out; 632 1.18 riastrad } 633 1.18 riastrad map2 = mmap(map1, page, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 634 1.18 riastrad if (map2 == MAP_FAILED) { 635 1.18 riastrad atf_tc_fail_nonfatal("mmap2 hint=%p map1=%p failed: errno=%d", 636 1.18 riastrad hint, map1, errno); 637 1.18 riastrad goto out; 638 1.18 riastrad } 639 1.18 riastrad map3 = mmap(hint, page, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 640 1.18 riastrad if (map3 == MAP_FAILED) { 641 1.18 riastrad atf_tc_fail_nonfatal("mmap3 hint=%p map1=%p failed: errno=%d", 642 1.18 riastrad hint, map1, errno); 643 1.18 riastrad goto out; 644 1.18 riastrad } 645 1.18 riastrad out: 646 1.18 riastrad if (map3 != MAP_FAILED) { 647 1.18 riastrad ATF_CHECK_MSG(munmap(map3, page) == 0, "munmap3 %p hint=%p", 648 1.18 riastrad map3, hint); 649 1.18 riastrad } 650 1.18 riastrad if (map2 != MAP_FAILED) { 651 1.18 riastrad ATF_CHECK_MSG(munmap(map2, page) == 0, "munmap2 %p hint=%p", 652 1.18 riastrad map2, hint); 653 1.18 riastrad } 654 1.18 riastrad if (map1 != MAP_FAILED) { 655 1.18 riastrad ATF_CHECK_MSG(munmap(map1, page) == 0, "munmap1 %p hint=%p", 656 1.18 riastrad map1, hint); 657 1.18 riastrad } 658 1.18 riastrad } 659 1.18 riastrad 660 1.18 riastrad ATF_TC(mmap_hint); 661 1.18 riastrad ATF_TC_HEAD(mmap_hint, tc) 662 1.18 riastrad { 663 1.18 riastrad atf_tc_set_md_var(tc, "descr", "Test mmap with hints"); 664 1.18 riastrad } 665 1.18 riastrad ATF_TC_BODY(mmap_hint, tc) 666 1.18 riastrad { 667 1.18 riastrad static const int minaddress_mib[] = { CTL_VM, VM_MINADDRESS }; 668 1.18 riastrad static const int maxaddress_mib[] = { CTL_VM, VM_MAXADDRESS }; 669 1.18 riastrad long minaddress, maxaddress; 670 1.18 riastrad size_t minaddresssz = sizeof(minaddress); 671 1.18 riastrad size_t maxaddresssz = sizeof(maxaddress); 672 1.18 riastrad 673 1.18 riastrad ATF_REQUIRE_MSG(sysctl(minaddress_mib, __arraycount(minaddress_mib), 674 1.18 riastrad &minaddress, &minaddresssz, NULL, 0) == 0, 675 1.18 riastrad "sysctl vm.minaddress: errno=%d", errno); 676 1.18 riastrad ATF_REQUIRE_MSG(sysctl(maxaddress_mib, __arraycount(maxaddress_mib), 677 1.18 riastrad &maxaddress, &maxaddresssz, NULL, 0) == 0, 678 1.18 riastrad "sysctl vm.maxaddress: errno=%d", errno); 679 1.18 riastrad 680 1.18 riastrad test_mmap_hint(0); 681 1.18 riastrad test_mmap_hint(-1); 682 1.18 riastrad test_mmap_hint(page); 683 1.18 riastrad test_mmap_hint(minaddress); 684 1.18 riastrad test_mmap_hint(maxaddress); 685 1.18 riastrad } 686 1.18 riastrad 687 1.1 jruoho ATF_TP_ADD_TCS(tp) 688 1.1 jruoho { 689 1.1 jruoho page = sysconf(_SC_PAGESIZE); 690 1.1 jruoho ATF_REQUIRE(page >= 0); 691 1.1 jruoho 692 1.3 jruoho ATF_TP_ADD_TC(tp, mmap_block); 693 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_err); 694 1.2 jruoho ATF_TP_ADD_TC(tp, mmap_loan); 695 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_1); 696 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_2); 697 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_prot_3); 698 1.17 gson ATF_TP_ADD_TC(tp, mmap_reprotect_race); 699 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_truncate); 700 1.8 christos ATF_TP_ADD_TC(tp, mmap_truncate_signal); 701 1.1 jruoho ATF_TP_ADD_TC(tp, mmap_va0); 702 1.18 riastrad ATF_TP_ADD_TC(tp, mmap_hint); 703 1.1 jruoho 704 1.1 jruoho return atf_no_error(); 705 1.1 jruoho } 706