The Pedigree Project 0.1
sandbox-contract-test/main.c
1/* Copyright (c) 2026, Pedigree Developers. */
2#define _GNU_SOURCE
3#include <errno.h>
4#include <fcntl.h>
5#include <pthread.h>
6#include <signal.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13#include <sys/socket.h>
14#include <sys/stat.h>
15#include <sys/syscall.h>
16#include <sys/wait.h>
17
18#ifndef SYS_seccomp
19#if defined(__x86_64__)
20#define SYS_seccomp 317
21#elif defined(__aarch64__)
22#define SYS_seccomp 277
23#elif defined(__i386__)
24#define SYS_seccomp 354
25#elif defined(__arm__)
26#define SYS_seccomp 383
27#endif
28#endif
29#ifndef SYS_landlock_create_ruleset
30#define SYS_landlock_create_ruleset 444
31#define SYS_landlock_add_rule 445
32#define SYS_landlock_restrict_self 446
33#endif
34
35#if defined(__x86_64__)
36#define NATIVE_AUDIT_ARCH 0xc000003eU
37#elif defined(__aarch64__)
38#define NATIVE_AUDIT_ARCH 0xc00000b7U
39#elif defined(__i386__)
40#define NATIVE_AUDIT_ARCH 0x40000003U
41#elif defined(__arm__)
42#define NATIVE_AUDIT_ARCH 0x40000028U
43#endif
44
45#define PR_GET_SECCOMP 21
46#define PR_SET_NO_NEW_PRIVS 38
47#define PR_GET_NO_NEW_PRIVS 39
48#define SECCOMP_SET_MODE_FILTER 1
49#define SECCOMP_GET_ACTION_AVAIL 2
50#define SECCOMP_RET_KILL_PROCESS 0x80000000U
51#define SECCOMP_RET_ALLOW 0x7fff0000U
52#define SECCOMP_RET_ERRNO 0x00050000U
53#define LANDLOCK_CREATE_RULESET_VERSION 1
54#define LANDLOCK_RULE_PATH_BENEATH 1
55#define LANDLOCK_READ ((1ULL << 0) | (1ULL << 2) | (1ULL << 3))
56#define LANDLOCK_ABI3_ALL ((1ULL << 15) - 1)
57
58#define CHECK(expression) \
59 do { \
60 if (!(expression)) { \
61 fprintf(stderr, "SANDBOX-CONTRACT: FAIL line=%d %s errno=%d\n", __LINE__, #expression, \
62 errno); \
63 return 1; \
64 } \
65 } while (0)
66
67#define EXPECT(call, expected, error) \
68 do { \
69 errno = 0; \
70 long actualResult = (call); \
71 int actualError = errno; \
72 if (actualResult != (expected) || (actualResult == -1 && actualError != (error))) { \
73 fprintf(stderr, "SANDBOX-CONTRACT: FAIL line=%d %s result=%ld errno=%d expected=%ld/%d\n", \
74 __LINE__, #call, actualResult, actualError, (long)(expected), (error)); \
75 return 1; \
76 } \
77 } while (0)
78
80 uint16_t code;
81 uint8_t jt, jf;
82 uint32_t k;
83};
85 uint16_t count;
86 const struct filter_instruction* instructions;
87};
89 uint64_t handled_access_fs;
90};
92 uint64_t allowed_access;
93 int32_t parent_fd;
94} __attribute__((packed));
95
96struct fixture {
97 char root[256];
98 char inside[320], outside[320];
99 char allowed[384], protected[384], created[384], renamed[384];
100 char inside_link[384], outside_link[384], outside_alias[384];
101};
102
103static int paths(struct fixture* fixture, const char* root) {
104 CHECK(strlen(root) < sizeof(fixture->root));
105 strcpy(fixture->root, root);
106 snprintf(fixture->inside, sizeof(fixture->inside), "%s/inside", root);
107 snprintf(fixture->outside, sizeof(fixture->outside), "%s/outside", root);
108 snprintf(fixture->allowed, sizeof(fixture->allowed), "%s/file", fixture->inside);
109 snprintf(fixture->protected, sizeof(fixture->protected), "%s/file", fixture->outside);
110 snprintf(fixture->created, sizeof(fixture->created), "%s/new", fixture->outside);
111 snprintf(fixture->renamed, sizeof(fixture->renamed), "%s/renamed", fixture->outside);
112 snprintf(fixture->inside_link, sizeof(fixture->inside_link), "%s/points-outside",
113 fixture->inside);
114 snprintf(fixture->outside_link, sizeof(fixture->outside_link), "%s/points-inside",
115 fixture->outside);
116 snprintf(fixture->outside_alias, sizeof(fixture->outside_alias), "%s/alias", fixture->outside);
117 return 0;
118}
119
120static int prepare(const struct fixture* fixture) {
121 CHECK(mkdir(fixture->inside, 0700) == 0);
122 CHECK(mkdir(fixture->outside, 0700) == 0);
123 int fd = open(fixture->protected, O_CREAT | O_EXCL | O_WRONLY, 0600);
124 CHECK(fd >= 0);
125 EXPECT(write(fd, "outside", 7), 7, 0);
126 EXPECT(close(fd), 0, 0);
127 fd = open(fixture->allowed, O_CREAT | O_EXCL | O_WRONLY, 0600);
128 CHECK(fd >= 0);
129 EXPECT(close(fd), 0, 0);
130 EXPECT(link(fixture->allowed, fixture->outside_alias), 0, 0);
131 EXPECT(symlink(fixture->protected, fixture->inside_link), 0, 0);
132 EXPECT(symlink(fixture->allowed, fixture->outside_link), 0, 0);
133 return 0;
134}
135
136static int cleanup(const struct fixture* fixture) {
137 const char* files[] = {fixture->allowed, fixture->protected, fixture->created,
138 fixture->renamed, fixture->inside_link, fixture->outside_link,
139 fixture->outside_alias};
140 int failed = 0;
141 for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); ++i) {
142 if (unlink(files[i]) && errno != ENOENT) {
143 fprintf(stderr, "SANDBOX-CONTRACT: cleanup %s errno=%d\n", files[i], errno);
144 failed = 1;
145 }
146 }
147 const char* directories[] = {fixture->inside, fixture->outside, fixture->root};
148 for (size_t i = 0; i < sizeof(directories) / sizeof(directories[0]); ++i) {
149 if (rmdir(directories[i]) && errno != ENOENT) {
150 fprintf(stderr, "SANDBOX-CONTRACT: cleanup %s errno=%d\n", directories[i], errno);
151 failed = 1;
152 }
153 }
154 return failed;
155}
156
157static int no_new_privileges(void) {
158 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 1UL, 0UL, 0UL, 0UL), -1, EINVAL);
159 EXPECT(syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), -1, EINVAL);
160 EXPECT(syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 2UL, 0UL, 0UL, 0UL), -1, EINVAL);
161 EXPECT(syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 1UL, 1UL, 0UL, 0UL), -1, EINVAL);
162 EXPECT(syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 1UL, 0UL, 0UL, 0UL), 0, 0);
163 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), 1, 0);
164 EXPECT(syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), -1, EINVAL);
165 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), 1, 0);
166 return 0;
167}
168
169static int install_filter(void) {
170 const struct filter_instruction instructions[] = {
171 {0x20, 0, 0, 4}, // Load architecture.
172 {0x15, 1, 0, NATIVE_AUDIT_ARCH},
173 {0x06, 0, 0, SECCOMP_RET_KILL_PROCESS},
174 {0x20, 0, 0, 0}, // Load syscall number.
175 {0x15, 0, 3, SYS_socket},
176 {0x20, 0, 0, 16}, // Load socket domain argument.
177 {0x15, 0, 1, AF_INET},
178 {0x06, 0, 0, SECCOMP_RET_ERRNO | EPERM},
179 {0x06, 0, 0, SECCOMP_RET_ALLOW},
180 };
181 const struct filter_program program = {sizeof(instructions) / sizeof(instructions[0]),
182 instructions};
183 EXPECT(syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &program), 0, 0);
184 EXPECT(syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL), 2, 0);
185 EXPECT(syscall(SYS_socket, AF_INET, SOCK_STREAM, 0), -1, EPERM);
186
187 const struct filter_instruction allow[] = {{0x06, 0, 0, SECCOMP_RET_ALLOW}};
188 const struct filter_program second = {1, allow};
189 EXPECT(syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &second), 0, 0);
190 EXPECT(syscall(SYS_socket, AF_INET, SOCK_STREAM, 0), -1, EPERM);
191 return 0;
192}
193
194static int filter_checks(void) {
195 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), 1, 0);
196 EXPECT(syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL), 2, 0);
197 EXPECT(syscall(SYS_socket, AF_INET, SOCK_STREAM, 0), -1, EPERM);
198 return 0;
199}
200
201static void* inherited_thread(void* unused) {
202 (void)unused;
203 return (void*)(uintptr_t)filter_checks();
204}
205
206static void* filtered_thread(void* unused) {
207 (void)unused;
208 int failed = no_new_privileges() || install_filter();
209 if (!failed) {
210 pthread_t descendant;
211 int error = pthread_create(&descendant, NULL, inherited_thread, NULL);
212 if (!error) {
213 void* result = NULL;
214 error = pthread_join(descendant, &result);
215 failed = result != NULL;
216 }
217 if (error) {
218 fprintf(stderr, "SANDBOX-CONTRACT: descendant pthread error=%d\n", error);
219 failed = 1;
220 }
221 }
222 return (void*)(uintptr_t)failed;
223}
224
225static int thread_isolation(long privileges, long mode) {
226 pthread_t worker;
227 EXPECT(pthread_create(&worker, NULL, filtered_thread, NULL), 0, 0);
228 void* result = NULL;
229 EXPECT(pthread_join(worker, &result), 0, 0);
230 CHECK(result == NULL);
231 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), privileges, 0);
232 EXPECT(syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL), mode, 0);
233 int fd = syscall(SYS_socket, AF_INET, SOCK_STREAM, 0);
234 CHECK(fd >= 0);
235 EXPECT(close(fd), 0, 0);
236 puts("SANDBOX-CONTRACT: pthread inheritance/isolation PASS");
237 return 0;
238}
239
240static int add_path(int ruleset, const char* path, uint64_t access) {
241 int directory = open(path, O_PATH | O_CLOEXEC);
242 CHECK(directory >= 0);
243 const struct path_beneath_attr rule = {access, directory};
244 errno = 0;
245 long result = syscall(SYS_landlock_add_rule, ruleset, LANDLOCK_RULE_PATH_BENEATH, &rule, 0);
246 int saved = errno;
247 close(directory);
248 if (result) {
249 fprintf(stderr, "SANDBOX-CONTRACT: add-rule %s result=%ld errno=%d\n", path, result, saved);
250 return 1;
251 }
252 return 0;
253}
254
255static int install_domain(const struct fixture* fixture) {
256 errno = 0;
257 long abi = syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
258 CHECK(abi >= 3);
259 const struct ruleset_attr attr = {LANDLOCK_ABI3_ALL};
260 int ruleset = syscall(SYS_landlock_create_ruleset, &attr, sizeof(attr), 0);
261 CHECK(ruleset >= 0);
262 int failed = add_path(ruleset, "/", LANDLOCK_READ) ||
263 add_path(ruleset, fixture->inside, LANDLOCK_ABI3_ALL);
264 if (!failed) {
265 errno = 0;
266 long result = syscall(SYS_landlock_restrict_self, ruleset, 0);
267 if (result) {
268 fprintf(stderr, "SANDBOX-CONTRACT: restrict-self result=%ld errno=%d\n", result, errno);
269 failed = 1;
270 }
271 }
272 if (!failed) {
273 failed = add_path(ruleset, "/", LANDLOCK_ABI3_ALL);
274 EXPECT(open(fixture->protected, O_WRONLY), -1, EACCES);
275 EXPECT(syscall(SYS_landlock_restrict_self, ruleset, 0), 0, 0);
276 }
277 close(ruleset);
278 return failed;
279}
280
281static int confined_checks(const struct fixture* fixture, int retained) {
282 CHECK(!filter_checks());
283 int pair[2];
284 EXPECT(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), 0, 0);
285 EXPECT(write(pair[0], "s", 1), 1, 0);
286 char byte;
287 EXPECT(read(pair[1], &byte, 1), 1, 0);
288 CHECK(byte == 's');
289 EXPECT(close(pair[0]), 0, 0);
290 EXPECT(close(pair[1]), 0, 0);
291
292 EXPECT(open(fixture->protected, O_WRONLY), -1, EACCES);
293 EXPECT(open(fixture->protected, O_WRONLY | O_TRUNC), -1, EACCES);
294 EXPECT(open(fixture->created, O_CREAT | O_EXCL | O_WRONLY, 0600), -1, EACCES);
295 EXPECT(truncate(fixture->protected, 0), -1, EACCES);
296 EXPECT(rename(fixture->protected, fixture->renamed), -1, EACCES);
297 EXPECT(open(fixture->inside_link, O_WRONLY), -1, EACCES);
298 EXPECT(open(fixture->outside_alias, O_WRONLY), -1, EACCES);
299
300 int fd = open(fixture->protected, O_RDONLY);
301 CHECK(fd >= 0);
302 char content[7];
303 EXPECT(read(fd, content, sizeof(content)), sizeof(content), 0);
304 CHECK(!memcmp(content, "outside", sizeof(content)));
305 EXPECT(close(fd), 0, 0);
306 fd = open(fixture->allowed, O_CREAT | O_TRUNC | O_RDWR, 0600);
307 CHECK(fd >= 0);
308 EXPECT(write(fd, "allowed", 7), 7, 0);
309 EXPECT(ftruncate(fd, 4), 0, 0);
310 EXPECT(close(fd), 0, 0);
311 EXPECT(truncate(fixture->allowed, 2), 0, 0);
312 fd = open(fixture->outside_link, O_WRONLY);
313 CHECK(fd >= 0);
314 EXPECT(write(fd, "a", 1), 1, 0);
315 EXPECT(close(fd), 0, 0);
316
317 struct stat before, after;
318 EXPECT(fstat(retained, &before), 0, 0);
319 EXPECT(ftruncate(retained, before.st_size), 0, 0);
320 EXPECT(lseek(retained, 0, SEEK_END), before.st_size, 0);
321 EXPECT(write(retained, "+", 1), 1, 0);
322 EXPECT(fstat(retained, &after), 0, 0);
323 CHECK(after.st_size == before.st_size + 1);
324 return 0;
325}
326
327static int reap(pid_t child) {
328 CHECK(child > 0);
329 int status;
330 pid_t result;
331 do {
332 result = waitpid(child, &status, 0);
333 } while (result < 0 && errno == EINTR);
334 CHECK(result == child);
335 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
336 fprintf(stderr, "SANDBOX-CONTRACT: child=%ld status=%d\n", (long)child, status);
337 return 1;
338 }
339 return 0;
340}
341
342static int restricted_child(const struct fixture* fixture, const char* executable) {
343 alarm(60);
344 int retained = open(fixture->protected, O_RDWR);
345 CHECK(retained >= 0);
346 CHECK(!no_new_privileges());
347 CHECK(!install_filter());
348 CHECK(!install_domain(fixture));
349 CHECK(!confined_checks(fixture, retained));
350 pid_t child = fork();
351 if (!child) {
352 alarm(30);
353 if (confined_checks(fixture, retained)) {
354 _exit(1);
355 }
356 char descriptor[32];
357 snprintf(descriptor, sizeof(descriptor), "%d", retained);
358 execl(executable, executable, "--child", fixture->root, descriptor, (char*)NULL);
359 fprintf(stderr, "SANDBOX-CONTRACT: exec %s errno=%d\n", executable, errno);
360 _exit(1);
361 }
362 int failed = reap(child);
363 close(retained);
364 return failed;
365}
366
367static int parent_checks(const struct fixture* fixture, long privileges, long mode) {
368 EXPECT(syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL), privileges, 0);
369 EXPECT(syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL), mode, 0);
370 int fd = syscall(SYS_socket, AF_INET, SOCK_STREAM, 0);
371 CHECK(fd >= 0);
372 EXPECT(close(fd), 0, 0);
373 struct stat info;
374 EXPECT(stat(fixture->protected, &info), 0, 0);
375 CHECK(info.st_size == 10);
376 fd = open(fixture->created, O_CREAT | O_EXCL | O_WRONLY, 0600);
377 CHECK(fd >= 0);
378 EXPECT(write(fd, "parent", 6), 6, 0);
379 EXPECT(close(fd), 0, 0);
380 EXPECT(truncate(fixture->protected, 7), 0, 0);
381 EXPECT(rename(fixture->protected, fixture->renamed), 0, 0);
382 EXPECT(rename(fixture->renamed, fixture->protected), 0, 0);
383 return 0;
384}
385
386#define PROBE(name, call) \
387 do { \
388 errno = 0; \
389 long result = (call); \
390 printf("SANDBOX-PROBE: %s result=%ld errno=%d\n", name, result, errno); \
391 } while (0)
392
393static int probe(void) {
394 PROBE("get-no-new-privs", syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL));
395 PROBE("get-seccomp", syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL));
396 uint32_t action = SECCOMP_RET_ALLOW;
397 PROBE("seccomp-action-allow", syscall(SYS_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &action));
398 PROBE("landlock-abi",
399 syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION));
400 PROBE("set-no-new-privs", syscall(SYS_prctl, PR_SET_NO_NEW_PRIVS, 1UL, 0UL, 0UL, 0UL));
401 const struct filter_instruction allow[] = {{0x06, 0, 0, SECCOMP_RET_ALLOW}};
402 const struct filter_program program = {1, allow};
403 PROBE("seccomp-install", syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &program));
404 const struct ruleset_attr attr = {LANDLOCK_READ};
405 errno = 0;
406 int ruleset = syscall(SYS_landlock_create_ruleset, &attr, sizeof(attr), 0);
407 printf("SANDBOX-PROBE: landlock-create result=%d errno=%d\n", ruleset, errno);
408 int root = open("/", O_PATH | O_CLOEXEC);
409 const struct path_beneath_attr rule = {LANDLOCK_READ, root};
410 PROBE("landlock-add",
411 syscall(SYS_landlock_add_rule, ruleset, LANDLOCK_RULE_PATH_BENEATH, &rule, 0));
412 PROBE("landlock-restrict", syscall(SYS_landlock_restrict_self, ruleset, 0));
413 if (root >= 0) {
414 close(root);
415 }
416 if (ruleset >= 0) {
417 close(ruleset);
418 }
419 puts("SANDBOX-PROBE: DONE");
420 return 0;
421}
422
423static int command_denied(long result, int error, const char* operation) {
424 if (result == -1 && (error == EACCES || error == EPERM || error == EROFS)) {
425 return 0;
426 }
427 fprintf(stderr, "CODEX-SANDBOX-COMMAND: FAIL %s result=%ld errno=%d\n", operation, result, error);
428 return 1;
429}
430
431static int command_check(const char* directory, const char* protected, int writable) {
432 EXPECT(syscall(SYS_socket, AF_INET, SOCK_STREAM, 0), -1, EPERM);
433 struct stat info;
434 EXPECT(stat(protected, &info), 0, 0);
435 CHECK(S_ISREG(info.st_mode));
436 int fd = open(protected, O_RDONLY);
437 CHECK(fd >= 0);
438 char byte;
439 EXPECT(read(fd, &byte, 1), 1, 0);
440 EXPECT(close(fd), 0, 0);
441 errno = 0;
442 fd = open(protected, O_WRONLY);
443 int error = errno;
444 if (fd >= 0) {
445 close(fd);
446 }
447 CHECK(!command_denied(fd, error, "open protected file"));
448 errno = 0;
449 long result = truncate(protected, 0);
450 CHECK(!command_denied(result, errno, "truncate protected file"));
451
452 char path[4096];
453 int length =
454 snprintf(path, sizeof(path), "%s/codex-sandbox-command-%ld", directory, (long)getpid());
455 CHECK(length > 0 && (size_t)length < sizeof(path));
456 errno = 0;
457 fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
458 if (!writable) {
459 CHECK(!command_denied(fd, errno, "create file"));
460 puts("CODEX-SANDBOX-COMMAND: PASS");
461 return 0;
462 }
463 CHECK(fd >= 0);
464 errno = 0;
465 result = write(fd, "codex", 5);
466 error = errno;
467 int failed = result != 5;
468 if (failed) {
469 fprintf(stderr, "CODEX-SANDBOX-COMMAND: FAIL write result=%ld errno=%d\n", result, error);
470 }
471 failed |= close(fd) != 0;
472 failed |= unlink(path) != 0;
473 CHECK(!failed);
474 puts("CODEX-SANDBOX-COMMAND: PASS");
475 return 0;
476}
477
478int namespace_tests(void);
479int namespace_network_test(void);
480
481int main(int argc, char** argv) {
482 setvbuf(stdout, NULL, _IONBF, 0);
483 alarm(90);
484 if (argc == 2 && !strcmp(argv[1], "--network-test")) {
485 return namespace_network_test();
486 }
487 if (argc == 2 && !strcmp(argv[1], "--namespaces-test")) {
488 return namespace_tests();
489 }
490 if (argc == 2 && !strcmp(argv[1], "--probe")) {
491 return probe();
492 }
493 if (argc == 4 && !strcmp(argv[1], "--command-check")) {
494 return command_check(argv[2], argv[3], 1);
495 }
496 if (argc == 3 && !strcmp(argv[1], "--read-only-check")) {
497 return command_check("/tmp", argv[2], 0);
498 }
499 struct fixture fixture;
500 if (argc == 4 && !strcmp(argv[1], "--child")) {
501 CHECK(!paths(&fixture, argv[2]));
502 char* end;
503 long descriptor = strtol(argv[3], &end, 10);
504 CHECK(!*end && descriptor >= 0 && descriptor <= INT32_MAX);
505 return confined_checks(&fixture, descriptor);
506 }
507 CHECK(argc == 1);
508 EXPECT(openat(AT_FDCWD, "", O_RDONLY), -1, ENOENT);
509 char executable[4096];
510 if (!realpath(argv[0], executable)) {
511 ssize_t length = readlink("/proc/self/exe", executable, sizeof(executable) - 1);
512 CHECK(length > 0 && (size_t)length < sizeof(executable) - 1);
513 executable[length] = 0;
514 }
515 long privileges = syscall(SYS_prctl, PR_GET_NO_NEW_PRIVS, 0UL, 0UL, 0UL, 0UL);
516 long mode = syscall(SYS_prctl, PR_GET_SECCOMP, 0UL, 0UL, 0UL, 0UL);
517 CHECK(privileges >= 0 && mode >= 0);
518 CHECK(!thread_isolation(privileges, mode));
519 char directory[256];
520 snprintf(directory, sizeof(directory), "/tmp/sandbox-contract-%ld", (long)getpid());
521 CHECK(!paths(&fixture, directory));
522 CHECK(mkdir(fixture.root, 0700) == 0);
523 int failed = prepare(&fixture);
524 if (!failed) {
525 pid_t child = fork();
526 if (!child) {
527 _exit(restricted_child(&fixture, executable));
528 }
529 failed = reap(child);
530 if (!failed) {
531 failed = parent_checks(&fixture, privileges, mode);
532 }
533 }
534 failed |= cleanup(&fixture);
535 puts(failed ? "SANDBOX-CONTRACT: FAIL" : "SANDBOX-CONTRACT: PASS");
536 return failed;
537}