The Pedigree Project 0.1
discard.c
1#define _GNU_SOURCE
2#include <signal.h>
3#include <string.h>
4#include <unistd.h>
5
6#include "contract.h"
7#include <sys/ipc.h>
8#include <sys/mman.h>
9#include <sys/shm.h>
10
11static int anonymous_discard(void) {
12 int failed = 0;
13 const size_t p = vm_page;
14 unsigned char* area =
15 mmap(NULL, 4 * p, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
16 unsigned char* target = MAP_FAILED;
17 unsigned char vector[4];
18 CHECK(area != MAP_FAILED);
19 memset(area, 0x71, 4 * p);
20 CHECK(mprotect(area + p, p, PROT_READ) == 0 && mprotect(area + 2 * p, p, PROT_NONE) == 0);
21 CHECK(madvise(area + p, 2 * p, MADV_DONTNEED) == 0);
22 CHECK(mincore(area, 4 * p, vector) == 0 && vector[0] == 1 && vector[1] == 0 && vector[2] == 0 &&
23 vector[3] == 1);
24 CHECK(vm_uniform(area, p, 0x71) && vm_uniform(area + p, p, 0) &&
25 vm_uniform(area + 3 * p, p, 0x71));
26 CHECK(vm_fault(area + p, 1, SIGSEGV) == 0 && vm_fault(area + 2 * p, 0, SIGSEGV) == 0);
27 CHECK(mprotect(area + 2 * p, p, PROT_READ | PROT_WRITE) == 0 && vm_uniform(area + 2 * p, p, 0));
28 CHECK(madvise(area + 1, p, MADV_DONTNEED) == -1 && errno == EINVAL);
29 CHECK(madvise(area, p, MADV_FREE) == -1 && errno == EINVAL);
30 CHECK(madvise(area, p, 0x7fffffff) == -1 && errno == EINVAL);
31 CHECK(madvise(area, 0, MADV_DONTNEED) == 0 && vm_uniform(area, p, 0x71));
32 CHECK(munmap(area + 3 * p, p) == 0);
33 CHECK(madvise(area, 4 * p, MADV_DONTNEED) == -1 && errno == ENOMEM);
34 CHECK(vm_uniform(area, p, 0x71));
35 CHECK(madvise(area, p, MADV_DONTNEED) == 0);
36 CHECK((target = mmap(NULL, p, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED);
37 CHECK(mremap(area, p, p, MREMAP_FIXED | MREMAP_MAYMOVE, target) == target);
38 CHECK(mincore(target, p, vector) == 0 && vector[0] == 0 && vm_uniform(target, p, 0));
39out:
40 if (target != MAP_FAILED)
41 munmap(target, p);
42 if (area != MAP_FAILED)
43 munmap(area, 4 * p);
44 return failed;
45}
46
47static int file_discard(void) {
48 int failed = 0, fd = -1;
49 const size_t p = vm_page;
50 unsigned char *private = MAP_FAILED, *shared = MAP_FAILED, *alias = MAP_FAILED,
51 *target = MAP_FAILED;
52 CHECK((fd = vm_file(3, NULL)) >= 0);
53 CHECK((private = mmap(NULL, 2 * p, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, p)) != MAP_FAILED);
54 CHECK((shared = mmap(NULL, 2 * p, PROT_READ | PROT_WRITE, MAP_SHARED, fd, p)) != MAP_FAILED);
55 CHECK((alias = mmap(NULL, 3 * p, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) != MAP_FAILED);
56 private[0] = 0xe1;
57 shared[p] = 0xe2;
58 CHECK(alias[p] == 0x21 && alias[2 * p] == 0xe2);
59 CHECK(close(fd) == 0);
60 fd = -1;
61 CHECK(madvise(private, 2 * p, MADV_DONTNEED) == 0 && private[0] == 0x21 && private[p] == 0xe2);
62 CHECK(madvise(shared, 2 * p, MADV_DONTNEED) == 0 && shared[0] == 0x21 && shared[p] == 0xe2);
63 CHECK(alias[2 * p] == 0xe2);
64 alias[p] = 0xe3;
65 CHECK(shared[0] == 0xe3);
66 CHECK(mprotect(private, 2 * p, PROT_READ) == 0 && madvise(private, 2 * p, MADV_DONTNEED) == 0);
67 CHECK(private[0] == 0xe3 && private[p] == 0xe2);
68 CHECK(vm_fault(private, 1, SIGSEGV) == 0);
69 CHECK((target = mmap(NULL, 2 * p, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED);
70 CHECK(mremap(private, 2 * p, 2 * p, MREMAP_MAYMOVE | MREMAP_FIXED, target) == target);
71 CHECK(target[0] == 0xe3 && target[p] == 0xe2 && vm_fault(target, 1, SIGSEGV) == 0);
72out:
73 if (fd >= 0)
74 close(fd);
75 if (private != MAP_FAILED)
76 munmap(private, 2 * p);
77 if (shared != MAP_FAILED)
78 munmap(shared, 2 * p);
79 if (alias != MAP_FAILED)
80 munmap(alias, 3 * p);
81 if (target != MAP_FAILED)
82 munmap(target, 2 * p);
83 return failed;
84}
85
86static int shm_discard(void) {
87 int failed = 0, id = -1;
88 const size_t p = vm_page;
89 unsigned char *view = (void*)-1, *alias = (void*)-1;
90 struct shmid_ds status;
91 CHECK((id = shmget(IPC_PRIVATE, 2 * p, 0600)) >= 0);
92 CHECK((view = shmat(id, NULL, 0)) != (void*)-1 && (alias = shmat(id, NULL, 0)) != (void*)-1);
93 memset(view, 0xf1, 2 * p);
94 if (geteuid() == 0)
95 CHECK(shmctl(id, SHM_LOCK, NULL) == 0);
96 CHECK(madvise(view, 2 * p, MADV_DONTNEED) == 0 && vm_uniform(alias, 2 * p, 0xf1) &&
97 vm_uniform(view, 2 * p, 0xf1));
98 CHECK(shmctl(id, IPC_STAT, &status) == 0 && status.shm_nattch == 2 && status.shm_segsz == 2 * p);
99 if (geteuid() == 0)
100 CHECK(shmctl(id, SHM_UNLOCK, NULL) == 0);
101 CHECK(shmctl(id, IPC_RMID, NULL) == 0);
102 CHECK(madvise(view, 2 * p, MADV_DONTNEED) == 0 && madvise(alias, 2 * p, MADV_DONTNEED) == 0);
103 CHECK(vm_uniform(view, 2 * p, 0xf1));
104 alias[0] = 0xf2;
105 CHECK(view[0] == 0xf2);
106out:
107 if (view != (void*)-1)
108 shmdt(view);
109 if (alias != (void*)-1)
110 shmdt(alias);
111 if (id >= 0)
112 shmctl(id, IPC_RMID, NULL);
113 return failed;
114}
115
116static int fork_discard(void) {
117 int failed = 0, gate[2] = {-1, -1};
118 const size_t p = vm_page;
119 pid_t child = -1;
120 unsigned char* area =
121 mmap(NULL, 2 * p, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
122 CHECK(area != MAP_FAILED);
123 memset(area, 0x81, 2 * p);
124 CHECK(pipe(gate) == 0 && (child = fork()) >= 0);
125 if (!child) {
126 alarm(5);
127 char byte;
128 if (read(gate[0], &byte, 1) != 1 || !vm_uniform(area, 2 * p, 0x81))
129 _exit(10);
130 for (int n = 0; n < 8; ++n) {
131 if (madvise(area, 2 * p, MADV_DONTNEED) || !vm_uniform(area, 2 * p, 0))
132 _exit(11);
133 memset(area, 0xd0 + n, 2 * p);
134 vm_pause(2);
135 if (!vm_uniform(area, 2 * p, 0xd0 + n))
136 _exit(12);
137 }
138 _exit(0);
139 }
140 CHECK(write(gate[1], "g", 1) == 1);
141 for (int n = 0; n < 8; ++n) {
142 memset(area, 0xa0 + n, 2 * p);
143 vm_pause(2);
144 CHECK(vm_uniform(area, 2 * p, 0xa0 + n));
145 }
146 int result = vm_reap(child, 3000);
147 child = -1;
148 CHECK(result == 0 && vm_uniform(area, 2 * p, 0xa7));
149out:
150 if (child > 0) {
151 kill(child, SIGKILL);
152 vm_reap(child, 1000);
153 }
154 if (area != MAP_FAILED)
155 munmap(area, 2 * p);
156 for (int n = 0; n < 2; ++n)
157 if (gate[n] >= 0)
158 close(gate[n]);
159 return failed;
160}
161
162int vm_test_discard(void) {
163 return anonymous_discard() || file_discard() || shm_discard() || fork_discard();
164}