The Pedigree Project 0.1
memfd-contract-test/seals.c
1#define _GNU_SOURCE
2#include <string.h>
3#include <unistd.h>
4
5#include "contract.h"
6#include <sys/mman.h>
7#include <sys/uio.h>
8
9static int additive_and_size(void) {
10 int failed = 0, fd = -1;
11 char original[64];
12 memset(original, 'a', sizeof(original));
13 CHECK((fd = mf_make(sizeof(original))) >= 0);
14 CHECK(pwrite(fd, original, sizeof(original), 0) == sizeof(original));
15 CHECK(!fcntl(fd, F_ADD_SEALS, 0) && fcntl(fd, F_GET_SEALS) == 0);
16 CHECK(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | 0x20) == -1 && errno == EINVAL);
17 CHECK(fcntl(fd, F_GET_SEALS) == 0 && !mf_size(fd, 64));
18 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_GROW));
19 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_GROW));
20 CHECK(ftruncate(fd, 65) == -1 && errno == EPERM);
21 CHECK(pwrite(fd, "z", 1, 64) == -1 && errno == EPERM);
22 CHECK(!mf_size(fd, 64) && !mf_contents(fd, 0, original, 64));
23 CHECK(!ftruncate(fd, 32));
24 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK));
25 CHECK(ftruncate(fd, 31) == -1 && errno == EPERM);
26 CHECK(!mf_size(fd, 32) && !mf_contents(fd, 0, original, 32));
27 CHECK(!ftruncate(fd, 32));
28 CHECK(lseek(fd, 31, SEEK_SET) == 31);
29 CHECK(write(fd, "zz", 2) == -1 && errno == EPERM);
30 CHECK(lseek(fd, 0, SEEK_CUR) == 31 && !mf_contents(fd, 0, original, 32));
31 CHECK(pwrite(fd, "b", 1, 0) == 1);
32 CHECK(!fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_FUTURE_WRITE | F_SEAL_SEAL));
33 const int all = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_WRITE | F_SEAL_FUTURE_WRITE | F_SEAL_SEAL;
34 CHECK(fcntl(fd, F_GET_SEALS) == all);
35 CHECK(fcntl(fd, F_ADD_SEALS, 0) == -1 && errno == EPERM);
36 CHECK(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1 && errno == EPERM);
37 CHECK(fcntl(fd, F_GET_SEALS) == all);
38out:
39 if (fd >= 0)
40 close(fd);
41 return failed;
42}
43static int denied_writes(int seal) {
44 int failed = 0, fd = -1;
45 const size_t page = sysconf(_SC_PAGESIZE);
46 char* private = MAP_FAILED;
47 char original[64], zeros[32] = {0};
48 memset(original, 'q', sizeof(original));
49 struct iovec vector[] = {{"x", 1}, {"y", 1}};
50 CHECK((fd = mf_make(page)) >= 0);
51 CHECK(pwrite(fd, original, sizeof(original), 0) == sizeof(original));
52 CHECK(!fcntl(fd, F_ADD_SEALS, seal));
53 CHECK(lseek(fd, 7, SEEK_SET) == 7);
54 CHECK(write(fd, "x", 1) == -1 && errno == EPERM);
55 CHECK(lseek(fd, 0, SEEK_CUR) == 7);
56 CHECK(pwrite(fd, "x", 1, 0) == -1 && errno == EPERM);
57 CHECK(writev(fd, vector, 2) == -1 && errno == EPERM);
58 CHECK(pwritev(fd, vector, 2, 0) == -1 && errno == EPERM);
59 CHECK(lseek(fd, 0, SEEK_CUR) == 7 && !mf_contents(fd, 0, original, 64));
60 CHECK(!fcntl(fd, F_SETFL, O_APPEND));
61 CHECK(write(fd, "x", 1) == -1 && errno == EPERM);
62 CHECK(lseek(fd, 0, SEEK_CUR) == 7 && !mf_size(fd, page));
63 CHECK(write(fd, "", 0) == 0 && pwrite(fd, "", 0, page + 1) == 0);
64 CHECK(!mf_size(fd, page) && fcntl(fd, F_GET_SEALS) == seal);
65 CHECK(!fcntl(fd, F_SETFL, 0));
66 CHECK(!ftruncate(fd, 32) && !ftruncate(fd, 64));
67 CHECK(!mf_contents(fd, 0, original, 32) && !mf_contents(fd, 32, zeros, 32));
68 CHECK(!ftruncate(fd, page));
69 private = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
70 CHECK(private != MAP_FAILED && private[0] == 'q');
71 private[0] = 'p';
72 CHECK(private[0] == 'p' && !mf_contents(fd, 0, "q", 1));
73out:
74 if (private != MAP_FAILED)
75 munmap(private, page);
76 if (fd >= 0)
77 close(fd);
78 return failed;
79}
80int memfd_seals(void) {
81 return additive_and_size() || denied_writes(F_SEAL_WRITE) || denied_writes(F_SEAL_FUTURE_WRITE);
82}