The Pedigree Project 0.1
executable-file-contract-test/mappings.c
1/* Copyright (c) 2026, Pedigree Developers. */
2#define _GNU_SOURCE
3#include <fcntl.h>
4#include <signal.h>
5#include <string.h>
6#include <unistd.h>
7
8#include "contract.h"
9#include <sys/mman.h>
10#include <sys/stat.h>
11
12int ef_mutations(void) {
13 int failed = 0, fd = -1, other = -1, probe = -1;
14 char path[PATH_MAX] = {0}, alias[PATH_MAX] = {0};
15 unsigned char* map = MAP_FAILED;
16 CHECK((fd = ef_create("mutations", path)) >= 0);
17 if (ef_ext2) {
18 snprintf(alias, sizeof(alias), "%s/hardlink", ef_directory);
19 CHECK(!link(path, alias));
20 }
21 CHECK((other = open(ef_ext2 ? alias : path, O_RDWR | O_CLOEXEC)) >= 0);
22 map = mmap(NULL, 3 * ef_page, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
23 CHECK(map != MAP_FAILED && map[0] == 0x31);
24 CHECK(lseek(fd, 17, SEEK_SET) == 17);
25 CHECK(write(fd, "x", 1) == -1 && errno == ETXTBSY);
26 CHECK(lseek(fd, 0, SEEK_CUR) == 17);
27 CHECK(pwrite(other, "x", 1, ef_page + 3) == -1 && errno == ETXTBSY);
28 CHECK(ftruncate(other, 0) == -1 && errno == ETXTBSY);
29 CHECK(ftruncate(fd, 4 * ef_page) == -1 && errno == ETXTBSY);
30 CHECK(fallocate(other, 0, 0, 4 * ef_page) == -1 && errno == ETXTBSY);
31 probe = open(ef_ext2 ? alias : path, O_WRONLY | O_TRUNC);
32 CHECK(probe == -1 && errno == ETXTBSY);
33 CHECK((probe = open(path, O_WRONLY | O_CLOEXEC)) >= 0);
34 CHECK(write(probe, "x", 1) == -1 && errno == ETXTBSY);
35 struct stat metadata;
36 unsigned char bytes[32];
37 CHECK(!fstat(other, &metadata) && metadata.st_size == (off_t)(3 * ef_page));
38 CHECK(pread(other, bytes, sizeof(bytes), ef_page) == sizeof(bytes));
39 for (size_t n = 0; n < sizeof(bytes); ++n)
40 CHECK(bytes[n] == 0x31);
41 CHECK(!munmap(map, 3 * ef_page));
42 map = MAP_FAILED;
43 CHECK(pwrite(other, "y", 1, 0) == 1 && !ftruncate(fd, ef_page));
44out:
45 if (map != MAP_FAILED)
46 munmap(map, 3 * ef_page);
47 if (probe >= 0)
48 close(probe);
49 if (other >= 0)
50 close(other);
51 if (fd >= 0)
52 close(fd);
53 if (*alias)
54 unlink(alias);
55 if (*path)
56 unlink(path);
57 return failed;
58}
59
60int ef_lifetime(void) {
61 int failed = 0, fd = -1, ready[2] = {-1, -1}, gate[2] = {-1, -1};
62 char path[PATH_MAX] = {0};
63 unsigned char* map = MAP_FAILED;
64 pid_t child = -1;
65 CHECK((fd = ef_create("lifetime", path)) >= 0);
66 map = mmap(NULL, 3 * ef_page, PROT_READ, MAP_PRIVATE, fd, 0);
67 CHECK(map != MAP_FAILED);
68 CHECK(!mprotect(map, 3 * ef_page, PROT_READ | PROT_EXEC));
69 CHECK(!munmap(map + ef_page, ef_page));
70 CHECK(!mprotect(map, ef_page, PROT_READ));
71 CHECK(!pipe(ready) && !pipe(gate));
72 CHECK((child = fork()) >= 0);
73 if (!child) {
74 alarm(10);
75 close(ready[0]);
76 close(gate[1]);
77 if (ef_send(ready[1], 'r') || ef_receive(gate[0], 'g') || map[2 * ef_page] != 0x31 ||
78 munmap(map, ef_page) || mprotect(map + 2 * ef_page, ef_page, PROT_READ) ||
79 munmap(map + 2 * ef_page, ef_page))
80 _exit(1);
81 _exit(0);
82 }
83 close(ready[1]);
84 ready[1] = -1;
85 close(gate[0]);
86 gate[0] = -1;
87 CHECK(!ef_receive(ready[0], 'r'));
88 CHECK(!munmap(map, ef_page));
89 CHECK(pwrite(fd, "x", 1, 0) == -1 && errno == ETXTBSY);
90 CHECK(!munmap(map + 2 * ef_page, ef_page));
91 map = MAP_FAILED;
92 CHECK(pwrite(fd, "x", 1, 0) == -1 && errno == ETXTBSY);
93 CHECK(!ef_send(gate[1], 'g'));
94 int status = ef_reap(child);
95 child = -1;
96 CHECK(!status && pwrite(fd, "x", 1, 0) == 1);
97out:
98 if (child > 0) {
99 kill(child, SIGKILL);
100 ef_reap(child);
101 }
102 if (map != MAP_FAILED) {
103 munmap(map, ef_page);
104 munmap(map + 2 * ef_page, ef_page);
105 }
106 for (int n = 0; n < 2; ++n) {
107 if (ready[n] >= 0)
108 close(ready[n]);
109 if (gate[n] >= 0)
110 close(gate[n]);
111 }
112 if (fd >= 0)
113 close(fd);
114 if (*path)
115 unlink(path);
116 return failed;
117}
118
119int ef_conflicts(void) {
120 int failed = 0, fd = -1, readonly = -1;
121 char path[PATH_MAX] = {0};
122 void *shared = MAP_FAILED, *private = MAP_FAILED, *probe = MAP_FAILED;
123 CHECK((fd = ef_create("conflicts", path)) >= 0);
124 CHECK((readonly = open(path, O_RDONLY | O_CLOEXEC)) >= 0);
125 shared = mmap(NULL, ef_page, PROT_READ, MAP_SHARED, fd, 0);
126 CHECK(shared != MAP_FAILED);
127 private = mmap(NULL, ef_page, PROT_READ, MAP_PRIVATE, fd, 0);
128 CHECK(private != MAP_FAILED);
129 probe = mmap(NULL, ef_page, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
130 CHECK(probe == MAP_FAILED && errno == ETXTBSY);
131 CHECK(mprotect(private, ef_page, PROT_READ | PROT_EXEC) == -1 && errno == ETXTBSY);
132 CHECK(pwrite(fd, "x", 1, 0) == 1);
133 CHECK(!mprotect(shared, ef_page, PROT_READ | PROT_WRITE));
134 ((volatile unsigned char*)shared)[0] = 0x32;
135 CHECK(!munmap(shared, ef_page));
136 shared = MAP_FAILED;
137 CHECK(!mprotect(private, ef_page, PROT_READ | PROT_EXEC));
138 probe = mmap(NULL, ef_page, PROT_READ, MAP_SHARED, fd, 0);
139 CHECK(probe == MAP_FAILED && errno == ETXTBSY);
140 probe = mmap(NULL, ef_page, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
141 CHECK(probe == MAP_FAILED && errno == ETXTBSY);
142 shared = mmap(NULL, ef_page, PROT_READ, MAP_SHARED, readonly, 0);
143 CHECK(shared != MAP_FAILED);
144 CHECK(mprotect(shared, ef_page, PROT_READ | PROT_WRITE) == -1 && errno == EACCES);
145 CHECK(!munmap(shared, ef_page) && !munmap(private, ef_page));
146 shared = private = MAP_FAILED;
147 CHECK(pwrite(fd, "x", 1, 0) == 1);
148 probe = mmap(NULL, ef_page, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
149 CHECK(probe != MAP_FAILED);
150 ((volatile unsigned char*)probe)[0] = 0x34;
151 CHECK(pwrite(fd, "x", 1, 0) == 1);
152out:
153 if (probe != MAP_FAILED)
154 munmap(probe, ef_page);
155 if (shared != MAP_FAILED)
156 munmap(shared, ef_page);
157 if (private != MAP_FAILED)
158 munmap(private, ef_page);
159 if (readonly >= 0)
160 close(readonly);
161 if (fd >= 0)
162 close(fd);
163 if (*path)
164 unlink(path);
165 return failed;
166}
167
168int ef_ordinary(void) {
169 int failed = 0, fd = -1;
170 char path[PATH_MAX] = {0};
171 unsigned char* map = MAP_FAILED;
172 CHECK((fd = ef_create("ordinary", path)) >= 0);
173 map = mmap(NULL, 3 * ef_page, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
174 CHECK(map != MAP_FAILED && map[0] == 0x31);
175 map[0] = 0x43;
176 CHECK(pwrite(fd, "z", 1, 1) == 1);
177 unsigned char byte;
178 CHECK(pread(fd, &byte, 1, 0) == 1 && byte == 0x31);
179 CHECK(map[0] == 0x43);
180 CHECK(!ftruncate(fd, ef_page) && !ftruncate(fd, 3 * ef_page));
181 CHECK(map[2 * ef_page] == 0 && map[0] == 0x43);
182out:
183 if (map != MAP_FAILED)
184 munmap(map, 3 * ef_page);
185 if (fd >= 0)
186 close(fd);
187 if (*path)
188 unlink(path);
189 return failed;
190}