19ed77019SAugustin Cavalier /* 29ed77019SAugustin Cavalier * Copyright 2023, Haiku, Inc. All rights reserved. 39ed77019SAugustin Cavalier * Distributed under the terms of the MIT License. 49ed77019SAugustin Cavalier */ 59ed77019SAugustin Cavalier 69ed77019SAugustin Cavalier #include <stdio.h> 779572316STrung Nguyen #include <stdlib.h> 89ed77019SAugustin Cavalier #include <string.h> 99ed77019SAugustin Cavalier #include <fcntl.h> 109ed77019SAugustin Cavalier #include <sys/mman.h> 1179572316STrung Nguyen #include <unistd.h> 129ed77019SAugustin Cavalier #include <OS.h> 139ed77019SAugustin Cavalier 149ed77019SAugustin Cavalier 15bdcc293fSTrung Nguyen int gTestFd = -1; 169ed77019SAugustin Cavalier 17bdcc293fSTrung Nguyen 18bdcc293fSTrung Nguyen int 19bdcc293fSTrung Nguyen map_negative_offset_test() 20bdcc293fSTrung Nguyen { 219ed77019SAugustin Cavalier // should fail (negative offset) 22bdcc293fSTrung Nguyen void* ptr = mmap(NULL, B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, -4096); 23bdcc293fSTrung Nguyen if (ptr != MAP_FAILED) { 249ed77019SAugustin Cavalier printf("map-negative-offset unexpectedly succeeded!\n"); 259ed77019SAugustin Cavalier return -1; 269ed77019SAugustin Cavalier } 27bdcc293fSTrung Nguyen return 0; 28bdcc293fSTrung Nguyen } 299ed77019SAugustin Cavalier 30bdcc293fSTrung Nguyen 31bdcc293fSTrung Nguyen int 32bdcc293fSTrung Nguyen map_cut_compare_test() 33bdcc293fSTrung Nguyen { 34bdcc293fSTrung Nguyen uint8* ptr1 = (uint8*)mmap(NULL, 16 * B_PAGE_SIZE, PROT_READ, MAP_PRIVATE, gTestFd, 0); 359ed77019SAugustin Cavalier uint8 chunk[128]; 369ed77019SAugustin Cavalier memcpy(chunk, &ptr1[3 * B_PAGE_SIZE], sizeof(chunk)); 379ed77019SAugustin Cavalier 389ed77019SAugustin Cavalier // now cut the area 399ed77019SAugustin Cavalier uint8* ptr2 = (uint8*)mmap(&ptr1[B_PAGE_SIZE], B_PAGE_SIZE, 409ed77019SAugustin Cavalier PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); 419ed77019SAugustin Cavalier 429ed77019SAugustin Cavalier // validate that the area after the cut still has the expected data 439ed77019SAugustin Cavalier int status = memcmp(&ptr1[3 * B_PAGE_SIZE], chunk, sizeof(chunk)); 449ed77019SAugustin Cavalier if (status != 0) { 459ed77019SAugustin Cavalier printf("map-cut-compare test failed!\n"); 469ed77019SAugustin Cavalier return status; 479ed77019SAugustin Cavalier } 48bdcc293fSTrung Nguyen return 0; 49bdcc293fSTrung Nguyen } 50bdcc293fSTrung Nguyen 51bdcc293fSTrung Nguyen 52bdcc293fSTrung Nguyen int 53bdcc293fSTrung Nguyen map_protect_cut_test() 54bdcc293fSTrung Nguyen { 55bdcc293fSTrung Nguyen uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, 56bdcc293fSTrung Nguyen MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 57bdcc293fSTrung Nguyen 58bdcc293fSTrung Nguyen // make the tail accessible 59bdcc293fSTrung Nguyen mprotect(ptr + B_PAGE_SIZE * 3, B_PAGE_SIZE, PROT_READ | PROT_WRITE); 60bdcc293fSTrung Nguyen 61bdcc293fSTrung Nguyen // store any value 62bdcc293fSTrung Nguyen ptr[B_PAGE_SIZE * 3] = 'a'; 63bdcc293fSTrung Nguyen 64bdcc293fSTrung Nguyen // cut the area in the middle, before the accessible tail 65bdcc293fSTrung Nguyen mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_READ | PROT_WRITE, 66bdcc293fSTrung Nguyen MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 67bdcc293fSTrung Nguyen 68bdcc293fSTrung Nguyen // validate that this does not crash 69bdcc293fSTrung Nguyen if (ptr[B_PAGE_SIZE * 3] != 'a') { 70bdcc293fSTrung Nguyen printf("map-protect-cut test failed!\n"); 71bdcc293fSTrung Nguyen return -1; 72bdcc293fSTrung Nguyen } 73bdcc293fSTrung Nguyen return 0; 74bdcc293fSTrung Nguyen } 75bdcc293fSTrung Nguyen 76bdcc293fSTrung Nguyen 77bdcc293fSTrung Nguyen int 7879572316STrung Nguyen map_cut_fork_test() 7979572316STrung Nguyen { 8079572316STrung Nguyen char name[24]; 8179572316STrung Nguyen sprintf(name, "/shm-mmap-cut-fork-test-%d", getpid()); 8279572316STrung Nguyen name[sizeof(name) - 1] = '\0'; 8379572316STrung Nguyen shm_unlink(name); 8479572316STrung Nguyen int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); 8579572316STrung Nguyen shm_unlink(name); 8679572316STrung Nguyen 8779572316STrung Nguyen if (fd < 0) { 8879572316STrung Nguyen printf("failed to create temporary file!\n"); 8979572316STrung Nguyen return fd; 9079572316STrung Nguyen } 9179572316STrung Nguyen 9279572316STrung Nguyen ftruncate(fd, B_PAGE_SIZE * 4); 9379572316STrung Nguyen 9479572316STrung Nguyen uint8* ptr = (uint8*)mmap(NULL, B_PAGE_SIZE * 4, PROT_NONE, MAP_PRIVATE, 9579572316STrung Nguyen fd, 0); 9679572316STrung Nguyen 97*c0a12a6bSAugustin Cavalier // we can close the FD as mmap acquires another reference to the vnode 98*c0a12a6bSAugustin Cavalier close(fd); 99*c0a12a6bSAugustin Cavalier 10079572316STrung Nguyen // make the head accessible and also force the kernel to allocate the 10179572316STrung Nguyen // page_protections array 10279572316STrung Nguyen mprotect(ptr, B_PAGE_SIZE, PROT_READ | PROT_WRITE); 10379572316STrung Nguyen 10479572316STrung Nguyen // store any value 10579572316STrung Nguyen ptr[0] = 'a'; 10679572316STrung Nguyen 10779572316STrung Nguyen // cut the area in the middle 10879572316STrung Nguyen mmap(ptr + B_PAGE_SIZE, B_PAGE_SIZE, PROT_NONE, 10979572316STrung Nguyen MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 11079572316STrung Nguyen 11179572316STrung Nguyen // validate that the fork does not crash the kernel 11279572316STrung Nguyen int pid = fork(); 11379572316STrung Nguyen 11479572316STrung Nguyen if (pid == 0) 11579572316STrung Nguyen { 11679572316STrung Nguyen exit(0); 11779572316STrung Nguyen } 11879572316STrung Nguyen else if (pid < 0) 11979572316STrung Nguyen { 12079572316STrung Nguyen printf("failed to fork the test process!\n"); 12179572316STrung Nguyen return pid; 12279572316STrung Nguyen } 12379572316STrung Nguyen 12479572316STrung Nguyen int status; 12579572316STrung Nguyen waitpid(pid, &status, 0); 12679572316STrung Nguyen 12779572316STrung Nguyen // validate that this does not crash 12879572316STrung Nguyen if (ptr[0] != 'a') { 12979572316STrung Nguyen printf("map-cut-fork test failed!\n"); 13079572316STrung Nguyen return -1; 13179572316STrung Nguyen } 13279572316STrung Nguyen return 0; 13379572316STrung Nguyen } 13479572316STrung Nguyen 13579572316STrung Nguyen 13679572316STrung Nguyen int 137bdcc293fSTrung Nguyen main() 138bdcc293fSTrung Nguyen { 139bdcc293fSTrung Nguyen gTestFd = open("/boot/system/lib/libroot.so", O_CLOEXEC | O_RDONLY); 140bdcc293fSTrung Nguyen if (gTestFd < 0) 141bdcc293fSTrung Nguyen return -1; 142bdcc293fSTrung Nguyen 143bdcc293fSTrung Nguyen int status; 144bdcc293fSTrung Nguyen 145bdcc293fSTrung Nguyen if ((status = map_negative_offset_test()) != 0) 146bdcc293fSTrung Nguyen return status; 147bdcc293fSTrung Nguyen 148bdcc293fSTrung Nguyen if ((status = map_cut_compare_test()) != 0) 149bdcc293fSTrung Nguyen return status; 150bdcc293fSTrung Nguyen 151bdcc293fSTrung Nguyen if ((status = map_protect_cut_test()) != 0) 152bdcc293fSTrung Nguyen return status; 1539ed77019SAugustin Cavalier 15479572316STrung Nguyen if ((status = map_cut_fork_test()) != 0) 15579572316STrung Nguyen return status; 15679572316STrung Nguyen 1579ed77019SAugustin Cavalier return 0; 1589ed77019SAugustin Cavalier } 159