The Pedigree Project 0.1
resize.c
1#define _GNU_SOURCE
2#include <fcntl.h>
3#include <signal.h>
4#include <unistd.h>
5
6#include "contract.h"
7#include <sys/mman.h>
8
9static int resize_backend(int backend) {
10 int failed = 0;
11 struct rp_file file = {.fd = -1};
12 int alias_fd = -1;
13 unsigned char* mapping = MAP_FAILED;
14 unsigned char* alias = MAP_FAILED;
15 const size_t boundary = rp_page + 137;
16 CHECK(rp_create(&file, backend) == 0);
17 alias_fd = rp_open_alias(&file);
18 CHECK(alias_fd >= 0);
19 mapping = mmap(NULL, 4 * rp_page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
20 alias = mmap(NULL, 2 * rp_page, PROT_READ | PROT_WRITE, MAP_SHARED, alias_fd, 0);
21 CHECK(mapping != MAP_FAILED && alias != MAP_FAILED);
22 CHECK(remap_file_pages(mapping, rp_page, 0, 6, 0) == 0);
23 CHECK(remap_file_pages(mapping + 2 * rp_page, rp_page, 0, 6, 0) == 0);
24 CHECK(remap_file_pages(mapping + 3 * rp_page, rp_page, 0, 0, 0) == 0);
25 CHECK(remap_file_pages(alias, rp_page, 0, 6, 0) == 0);
26 CHECK(rp_matches(mapping, 6 * rp_page, rp_page, 0));
27 CHECK(rp_matches(mapping + rp_page, rp_page, rp_page, 0));
28 CHECK(rp_matches(mapping + 2 * rp_page, 6 * rp_page, rp_page, 0));
29 CHECK(rp_matches(mapping + 3 * rp_page, 0, rp_page, 0));
30 CHECK(rp_matches(alias, 6 * rp_page, rp_page, 0));
31 CHECK(rp_matches(alias + rp_page, rp_page, rp_page, 0));
32 mapping[19] = 0xa1;
33 CHECK(mapping[2 * rp_page + 19] == 0xa1 && alias[19] == 0xa1);
34
35 CHECK(ftruncate(alias_fd, boundary) == 0);
36 CHECK(rp_size(file.fd, boundary) == 0 && rp_size(alias_fd, boundary) == 0);
37 // Check residency before a read can reload a mistakenly discarded backing page.
38 CHECK(rp_resident(mapping, 4, 0xa, "rebiased shrink main") == 0);
39 CHECK(rp_resident(alias, 2, 0x2, "rebiased shrink alias") == 0);
40 CHECK(rp_fault(mapping, SIGBUS, 0) == 0);
41 CHECK(rp_fault(mapping + 2 * rp_page, SIGBUS, 0) == 0);
42 CHECK(rp_fault(alias, SIGBUS, 0) == 0);
43 CHECK(rp_matches(mapping + 3 * rp_page, 0, rp_page, 0));
44 CHECK(rp_matches(mapping + rp_page, rp_page, 137, 0));
45 CHECK(rp_matches(alias + rp_page, rp_page, 137, 0));
46 CHECK(rp_matches(mapping + boundary, boundary, rp_page - 137, 1));
47 CHECK(rp_matches(alias + boundary, boundary, rp_page - 137, 1));
48 CHECK(rp_contents(file.fd, 0, boundary, 0) == 0);
49
50 CHECK(ftruncate(alias_fd, 8 * rp_page) == 0 && rp_size(file.fd, 8 * rp_page) == 0);
51 CHECK(rp_contents(file.fd, boundary, 8 * rp_page - boundary, 1) == 0);
52 CHECK(rp_matches(mapping, 6 * rp_page, rp_page, 1));
53 CHECK(rp_matches(mapping + 2 * rp_page, 6 * rp_page, rp_page, 1));
54 CHECK(rp_matches(alias, 6 * rp_page, rp_page, 1));
55 CHECK(rp_matches(mapping + 3 * rp_page, 0, rp_page, 0));
56 CHECK(rp_matches(mapping + rp_page, rp_page, 137, 0));
57 CHECK(rp_matches(mapping + boundary, boundary, rp_page - 137, 1));
58 mapping[2 * rp_page + 73] = 0xd4;
59 CHECK(mapping[73] == 0xd4 && alias[73] == 0xd4);
60 alias[74] = 0x9a;
61 CHECK(mapping[74] == 0x9a && mapping[2 * rp_page + 74] == 0x9a);
62 unsigned char bytes[2] = {0};
63 CHECK(pread(alias_fd, bytes, sizeof(bytes), 6 * rp_page + 73) == (ssize_t)sizeof(bytes));
64 CHECK(bytes[0] == 0xd4 && bytes[1] == 0x9a);
65 CHECK(msync(mapping, 4 * rp_page, MS_SYNC) == 0);
66out:
67 if (alias != MAP_FAILED)
68 munmap(alias, 2 * rp_page);
69 if (mapping != MAP_FAILED)
70 munmap(mapping, 4 * rp_page);
71 if (alias_fd >= 0)
72 close(alias_fd);
73 rp_close(&file);
74 if (failed)
75 fprintf(stderr, "REMAP-FILE-PAGES-CONTRACT: resize backend=%d\n", backend);
76 return failed;
77}
78
79static int sealed_shrink(void) {
80 int failed = 0;
81 struct rp_file file = {.fd = -1};
82 unsigned char* mapping = MAP_FAILED;
83 CHECK(rp_create(&file, RP_MEMFD) == 0);
84 mapping = mmap(NULL, 2 * rp_page, PROT_READ, MAP_SHARED, file.fd, 0);
85 CHECK(mapping != MAP_FAILED && remap_file_pages(mapping, 2 * rp_page, 0, 6, 0) == 0);
86 CHECK(rp_matches(mapping, 6 * rp_page, 2 * rp_page, 0));
87 CHECK(fcntl(file.fd, F_ADD_SEALS, F_SEAL_SHRINK) == 0);
88 errno = 0;
89 CHECK(ftruncate(file.fd, rp_page) == -1 && errno == EPERM);
90 CHECK(rp_size(file.fd, 8 * rp_page) == 0);
91 CHECK(rp_resident(mapping, 2, 3, "sealed shrink preserved aliases") == 0);
92 CHECK(rp_matches(mapping, 6 * rp_page, 2 * rp_page, 0));
93out:
94 if (mapping != MAP_FAILED)
95 munmap(mapping, 2 * rp_page);
96 rp_close(&file);
97 return failed;
98}
99
100int rp_resize(void) {
101 for (int backend = RP_MEMFD; backend <= RP_EXT2; ++backend) {
102 if (resize_backend(backend))
103 return 1;
104 }
105 return sealed_shrink();
106}