The Pedigree Project 0.1
remap-file-pages-contract-test/lifetime.c
1#define _GNU_SOURCE
2#include <signal.h>
3#include <unistd.h>
4
5#include "contract.h"
6#include <sys/mman.h>
7
8static int child_layout(unsigned char* mapping, int fd, int command, int status) {
9 int failed = 0;
10 const size_t page = rp_page;
11 CHECK(!close(fd));
12 CHECK(rp_matches(mapping, 0, page, 0) && rp_matches(mapping + page, 5 * page, page, 0) &&
13 rp_matches(mapping + 2 * page, 2 * page, 2 * page, 0));
14 CHECK(!rp_send(status, 'R') && !rp_receive(command, 'G'));
15 CHECK(mapping[2 * page + 53] == 0xd4);
16 mapping[2 * page + 53] = rp_pattern(2 * page + 53);
17 CHECK(rp_matches(mapping, 0, page, 0) && rp_matches(mapping + page, 5 * page, page, 0) &&
18 rp_matches(mapping + 2 * page, 2 * page, 2 * page, 0));
19 CHECK(!remap_file_pages(mapping + 2 * page, page, 0, 7, 0));
20 CHECK(rp_matches(mapping + 2 * page, 7 * page, page, 0));
21 mapping[page + 33] = 0xe6;
22 CHECK(!rp_send(status, 'D') && !rp_receive(command, 'F'));
23out:
24 return failed;
25}
26
27static int last_descriptor(int backend) {
28 int failed = 0;
29 struct rp_file file = {.fd = -1};
30 int command[2] = {-1, -1}, status[2] = {-1, -1};
31 pid_t child = -1;
32 const size_t page = rp_page;
33 unsigned char *mapping = MAP_FAILED, *alias = MAP_FAILED, *moved = MAP_FAILED;
34 CHECK(!rp_create(&file, backend));
35 mapping = mmap(NULL, 4 * page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
36 alias = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 5 * page);
37 CHECK(mapping != MAP_FAILED && alias != MAP_FAILED);
38 CHECK(!remap_file_pages(mapping + page, page, 0, 5, 0));
39 CHECK(!pipe(command) && !pipe(status));
40 CHECK((child = fork()) >= 0);
41 if (!child) {
42 alarm(15);
43 close(command[1]);
44 close(status[0]);
45 int result = child_layout(mapping, file.fd, command[0], status[1]);
46 fflush(stderr);
47 _exit(result ? 1 : 0);
48 }
49 close(command[0]);
50 command[0] = -1;
51 close(status[1]);
52 status[1] = -1;
53 CHECK(!rp_receive(status[0], 'R'));
54 if (file.path[0]) {
55 CHECK(!unlink(file.path));
56 file.path[0] = 0;
57 }
58 CHECK(!close(file.fd));
59 file.fd = -1;
60 CHECK(!remap_file_pages(mapping, 4 * page, 0, 1, 0));
61 CHECK(rp_matches(mapping, page, 4 * page, 0));
62 mapping[page + 53] = 0xd4;
63 CHECK(!rp_send(command[1], 'G') && !rp_receive(status[0], 'D'));
64 CHECK(alias[33] == 0xe6 && rp_matches(mapping, page, 4 * page, 0));
65 alias[33] = rp_pattern(5 * page + 33);
66 CHECK(!rp_send(command[1], 'F'));
67 int child_status = rp_reap(child, 5000);
68 child = -1;
69 CHECK(child_status == 0);
70
71 CHECK(!mprotect(mapping + page, page, PROT_READ));
72 moved = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
73 CHECK(moved != MAP_FAILED);
74 CHECK(mremap(mapping + page, page, page, MREMAP_MAYMOVE | MREMAP_FIXED, moved) == moved);
75 CHECK(rp_matches(moved, 2 * page, page, 0));
76 CHECK(!remap_file_pages(moved, page, 0, 6, MAP_NONBLOCK));
77 CHECK(!madvise(moved, page, MADV_DONTNEED) && rp_matches(moved, 6 * page, page, 0));
78 CHECK(!mprotect(moved, page, PROT_READ | PROT_WRITE));
79 CHECK(!remap_file_pages(mapping, page, 0, 6, 0));
80 moved[55] = 0xba;
81 CHECK(mapping[55] == 0xba && rp_matches(mapping + 2 * page, 3 * page, 2 * page, 0));
82out:
83 if (child > 0) {
84 kill(child, SIGKILL);
85 rp_reap(child, 5000);
86 }
87 for (int n = 0; n < 2; ++n) {
88 if (command[n] >= 0)
89 close(command[n]);
90 if (status[n] >= 0)
91 close(status[n]);
92 }
93 if (moved != MAP_FAILED)
94 munmap(moved, page);
95 if (alias != MAP_FAILED)
96 munmap(alias, page);
97 if (mapping != MAP_FAILED)
98 munmap(mapping, 4 * page);
99 rp_close(&file);
100 if (failed)
101 fprintf(stderr, "REMAP-FILE-PAGES-CONTRACT: lifetime backend=%d\n", backend);
102 return failed;
103}
104
105int rp_lifetime(void) {
106 for (int backend = RP_MEMFD; backend <= RP_EXT2; ++backend) {
107 if (last_descriptor(backend))
108 return 1;
109 }
110 return 0;
111}