The Pedigree Project 0.1
remap-file-pages-contract-test/admission.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/ipc.h>
8#include <sys/mman.h>
9#include <sys/shm.h>
10#include <sys/stat.h>
11
12static int invalid_ranges(void) {
13 int failed = 0, shmid = -1;
14 struct rp_file file = {.fd = -1};
15 const size_t page = rp_page;
16 unsigned char *mapping = MAP_FAILED, *private = MAP_FAILED, *hole = MAP_FAILED;
17 unsigned char* shared_memory = (void*)-1;
18 volatile unsigned char stack_byte = 0x73;
19 CHECK(!rp_create(&file, RP_MEMFD));
20 mapping = mmap(NULL, 4 * page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
21 private = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE, file.fd, 0);
22 hole = mmap(NULL, 3 * page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
23 CHECK(mapping != MAP_FAILED && private != MAP_FAILED && hole != MAP_FAILED);
24 CHECK(remap_file_pages(mapping, page, PROT_READ, 1, 0) == -1 && errno == EINVAL);
25 CHECK(remap_file_pages(mapping, 0, 0, 1, 0) == -1 && errno == EINVAL);
26 CHECK(remap_file_pages(mapping, page - 1, 0, 1, 0) == -1 && errno == EINVAL);
27 CHECK(remap_file_pages(mapping, 2 * page, 0, SIZE_MAX, 0) == -1 && errno == EINVAL);
28 CHECK(remap_file_pages(mapping, page, 0, (size_t)INT64_MAX / page + 1, 0) == -1 &&
29 errno == EOVERFLOW);
30 CHECK(remap_file_pages((void*)(UINTPTR_MAX - page + 1), 2 * page, 0, 0, 0) == -1 &&
31 errno == EINVAL);
32 CHECK(remap_file_pages(NULL, page, 0, 0, 0) == -1 && errno == EINVAL);
33 CHECK(rp_matches(mapping, 0, 4 * page, 0));
34 private[71] = 0xd6;
35 CHECK(remap_file_pages(private, page, 0, 1, 0) == -1 && errno == EINVAL);
36 CHECK(private[71] == 0xd6 && mapping[71] == rp_pattern(71));
37 CHECK(!munmap(hole + page, page));
38 CHECK(remap_file_pages(hole, 3 * page, 0, 3, 0) == -1 && errno == EINVAL);
39 CHECK(rp_matches(hole, 0, page, 0) && rp_matches(hole + 2 * page, 2 * page, page, 0));
40 CHECK(!mprotect(mapping + page, page, PROT_READ));
41 CHECK(remap_file_pages(mapping, 2 * page, 0, 4, 0) == -1 && errno == EINVAL);
42 CHECK(rp_matches(mapping, 0, 4 * page, 0));
43 CHECK(!mprotect(mapping, 2 * page, PROT_READ | PROT_WRITE));
44 CHECK(!remap_file_pages(mapping, 2 * page, 0, 4, 0));
45 CHECK(rp_matches(mapping, 4 * page, 2 * page, 0));
46 CHECK(!mprotect(mapping, 2 * page, PROT_READ));
47 CHECK(!remap_file_pages(mapping, 2 * page, 0, 2, 0));
48 CHECK(rp_matches(mapping, 2 * page, 2 * page, 0) && !rp_fault(mapping, SIGSEGV, 1));
49 CHECK(!mprotect(mapping, page, PROT_NONE));
50 CHECK(!remap_file_pages(mapping, page, 0, 6, 0));
51 CHECK(!rp_fault(mapping, SIGSEGV, 0));
52 CHECK(!mprotect(mapping, page, PROT_READ));
53 CHECK(rp_matches(mapping, 6 * page, page, 0));
54
55 CHECK(remap_file_pages((void*)&stack_byte, page, 0, 0, 0) == -1 && errno == EOPNOTSUPP);
56 CHECK(stack_byte == 0x73);
57 CHECK((shmid = shmget(IPC_PRIVATE, page, IPC_CREAT | 0600)) >= 0);
58 CHECK((shared_memory = shmat(shmid, NULL, 0)) != (void*)-1);
59 CHECK(!shmctl(shmid, IPC_RMID, NULL));
60 shmid = -1;
61 shared_memory[0] = 0x49;
62 CHECK(remap_file_pages(shared_memory, page, 0, 0, 0) == -1 && errno == EOPNOTSUPP);
63 CHECK(shared_memory[0] == 0x49);
64out:
65 if (shared_memory != (void*)-1)
66 shmdt(shared_memory);
67 if (shmid >= 0)
68 shmctl(shmid, IPC_RMID, NULL);
69 if (hole != MAP_FAILED)
70 munmap(hole, 3 * page);
71 if (private != MAP_FAILED)
72 munmap(private, page);
73 if (mapping != MAP_FAILED)
74 munmap(mapping, 4 * page);
75 rp_close(&file);
76 return failed;
77}
78
79static int separate_opens(int backend) {
80 int failed = 0, other = -1, readonly = -1;
81 struct rp_file file = {.fd = -1};
82 const size_t page = rp_page;
83 unsigned char *area = MAP_FAILED, *read_mapping = MAP_FAILED;
84 struct stat first, second;
85 CHECK(!rp_create(&file, backend));
86 CHECK((other = rp_open_alias(&file)) >= 0 && (readonly = open(file.path, O_RDONLY)) >= 0);
87 CHECK(!fstat(file.fd, &first) && !fstat(other, &second) && first.st_ino == second.st_ino &&
88 first.st_dev == second.st_dev);
89 area = mmap(NULL, 2 * page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
90 CHECK(area != MAP_FAILED);
91 CHECK(mmap(area, page, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, file.fd, 0) == area);
92 CHECK(mmap(area + page, page, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, other, page) ==
93 area + page);
94 CHECK(remap_file_pages(area, 2 * page, 0, 4, 0) == -1 && errno == EINVAL);
95 CHECK(rp_matches(area, 0, 2 * page, 0));
96 read_mapping = mmap(NULL, page, PROT_READ, MAP_SHARED, readonly, 0);
97 CHECK(read_mapping != MAP_FAILED);
98 CHECK(remap_file_pages(read_mapping, page, 0, 1, 0) == -1 && errno == EINVAL);
99 CHECK(rp_matches(read_mapping, 0, page, 0));
100out:
101 if (read_mapping != MAP_FAILED)
102 munmap(read_mapping, page);
103 if (area != MAP_FAILED)
104 munmap(area, 2 * page);
105 if (readonly >= 0)
106 close(readonly);
107 if (other >= 0)
108 close(other);
109 rp_close(&file);
110 return failed;
111}
112
113static int seals(void) {
114 int failed = 0;
115 struct rp_file file = {.fd = -1};
116 const size_t page = rp_page;
117 unsigned char* mapping = MAP_FAILED;
118 CHECK(!rp_create(&file, RP_MEMFD));
119 mapping = mmap(NULL, 3 * page, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
120 CHECK(mapping != MAP_FAILED && rp_matches(mapping, 0, 3 * page, 0));
121 CHECK(!fcntl(file.fd, F_ADD_SEALS, F_SEAL_FUTURE_WRITE));
122 CHECK(remap_file_pages(mapping, 3 * page, 0, 2, 0) == -1 && errno == EPERM);
123 CHECK(rp_matches(mapping, 0, 3 * page, 0));
124 CHECK(!mprotect(mapping, 3 * page, PROT_READ));
125 CHECK(mmap(mapping + 2 * page, page, PROT_READ, MAP_SHARED | MAP_FIXED, file.fd, 2 * page) ==
126 mapping + 2 * page);
127 CHECK(remap_file_pages(mapping, 3 * page, 0, 2, 0) == -1 && errno == EINVAL);
128 CHECK(rp_matches(mapping, 0, 3 * page, 0));
129 CHECK(!remap_file_pages(mapping, 2 * page, 0, 2, MAP_NONBLOCK));
130 CHECK(!remap_file_pages(mapping, 3 * page, 0, 2, MAP_NONBLOCK));
131 CHECK(rp_matches(mapping, 2 * page, 3 * page, 0));
132 CHECK(mprotect(mapping, 3 * page, PROT_READ | PROT_WRITE) == -1 && errno == EACCES);
133 CHECK(!fcntl(file.fd, F_ADD_SEALS, F_SEAL_WRITE));
134 CHECK(!remap_file_pages(mapping, 3 * page, 0, 4, 0));
135 CHECK(rp_matches(mapping, 4 * page, 3 * page, 0));
136out:
137 if (mapping != MAP_FAILED)
138 munmap(mapping, 3 * page);
139 rp_close(&file);
140 return failed;
141}
142
143int rp_admission(void) {
144 return invalid_ranges() || separate_opens(RP_RAMFS) || separate_opens(RP_EXT2) || seals();
145}