1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 Dmitry Safonov, Arista Networks 4 * 5 * MAP_POPULATE | MAP_PRIVATE should COW VMA pages. 6 */ 7 8 #define _GNU_SOURCE 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <sys/mman.h> 12 #include <sys/socket.h> 13 #include <sys/types.h> 14 #include <sys/wait.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 20 #define MMAP_SZ 4096 21 22 #define BUG_ON(condition, description) \ 23 do { \ 24 if (condition) { \ 25 fprintf(stderr, "[FAIL]\t%s:%d\t%s:%s\n", __func__, \ 26 __LINE__, (description), strerror(errno)); \ 27 exit(1); \ 28 } \ 29 } while (0) 30 31 static int parent_f(int sock, unsigned long *smap, int child) 32 { 33 int status, ret; 34 35 ret = read(sock, &status, sizeof(int)); 36 BUG_ON(ret <= 0, "read(sock)"); 37 38 *smap = 0x22222BAD; 39 ret = msync(smap, MMAP_SZ, MS_SYNC); 40 BUG_ON(ret, "msync()"); 41 42 ret = write(sock, &status, sizeof(int)); 43 BUG_ON(ret <= 0, "write(sock)"); 44 45 waitpid(child, &status, 0); 46 BUG_ON(!WIFEXITED(status), "child in unexpected state"); 47 48 return WEXITSTATUS(status); 49 } 50 51 static int child_f(int sock, unsigned long *smap, int fd) 52 { 53 int ret, buf = 0; 54 55 smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 56 MAP_PRIVATE | MAP_POPULATE, fd, 0); 57 BUG_ON(smap == MAP_FAILED, "mmap()"); 58 59 BUG_ON(*smap != 0xdeadbabe, "MAP_PRIVATE | MAP_POPULATE changed file"); 60 61 ret = write(sock, &buf, sizeof(int)); 62 BUG_ON(ret <= 0, "write(sock)"); 63 64 ret = read(sock, &buf, sizeof(int)); 65 BUG_ON(ret <= 0, "read(sock)"); 66 67 BUG_ON(*smap == 0x22222BAD, "MAP_POPULATE didn't COW private page"); 68 BUG_ON(*smap != 0xdeadbabe, "mapping was corrupted"); 69 70 return 0; 71 } 72 73 int main(int argc, char **argv) 74 { 75 int sock[2], child, ret; 76 FILE *ftmp; 77 unsigned long *smap; 78 79 ftmp = tmpfile(); 80 BUG_ON(ftmp == 0, "tmpfile()"); 81 82 ret = ftruncate(fileno(ftmp), MMAP_SZ); 83 BUG_ON(ret, "ftruncate()"); 84 85 smap = mmap(0, MMAP_SZ, PROT_READ | PROT_WRITE, 86 MAP_SHARED, fileno(ftmp), 0); 87 BUG_ON(smap == MAP_FAILED, "mmap()"); 88 89 *smap = 0xdeadbabe; 90 /* Probably unnecessary, but let it be. */ 91 ret = msync(smap, MMAP_SZ, MS_SYNC); 92 BUG_ON(ret, "msync()"); 93 94 ret = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sock); 95 BUG_ON(ret, "socketpair()"); 96 97 child = fork(); 98 BUG_ON(child == -1, "fork()"); 99 100 if (child) { 101 ret = close(sock[0]); 102 BUG_ON(ret, "close()"); 103 104 return parent_f(sock[1], smap, child); 105 } 106 107 ret = close(sock[1]); 108 BUG_ON(ret, "close()"); 109 110 return child_f(sock[0], smap, fileno(ftmp)); 111 } 112