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
parent_f(int sock,unsigned long * smap,int child)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
child_f(int sock,unsigned long * smap,int fd)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
main(int argc,char ** argv)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, "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