The Pedigree Project 0.1
memfd-contract-test/creation.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/stat.h>
8#include <sys/uio.h>
9
10static int names_and_flags(void) {
11 int failed = 0, plain = -1, first = -1, second = -1, long_fd = -1;
12 const size_t page = sysconf(_SC_PAGESIZE);
13 char* denied = MAP_FAILED;
14 mode_t mask = umask(0077);
15 struct stat st, other;
16 char name[251];
17 CHECK((plain = memfd_create("", 0)) >= 0);
18 CHECK(fcntl(plain, F_GET_SEALS) == F_SEAL_SEAL);
19 CHECK(fcntl(plain, F_ADD_SEALS, F_SEAL_GROW) == -1 && errno == EPERM);
20 CHECK(fcntl(plain, F_ADD_SEALS, 0) == -1 && errno == EPERM);
21 CHECK(fcntl(plain, F_GET_SEALS) == F_SEAL_SEAL);
22 CHECK((fcntl(plain, F_GETFL) & O_ACCMODE) == O_RDWR);
23 CHECK(fcntl(plain, F_GETFD) == 0);
24 CHECK(!fstat(plain, &st) && S_ISREG(st.st_mode) && (st.st_mode & 07777) == 0777 &&
25 st.st_nlink == 0 && st.st_size == 0 && st.st_uid == geteuid() && st.st_gid == getegid());
26 CHECK(read(plain, name, 1) == 0);
27 CHECK(lseek(plain, 17, SEEK_SET) == 17 && lseek(plain, 0, SEEK_END) == 0);
28 CHECK((first = memfd_create("same label", MFD_ALLOW_SEALING | MFD_CLOEXEC)) >= 0);
29 CHECK((second = memfd_create("same label", MFD_ALLOW_SEALING)) >= 0);
30 CHECK(fcntl(first, F_GET_SEALS) == 0 && fcntl(second, F_GET_SEALS) == 0);
31 CHECK(fcntl(first, F_GETFD) == FD_CLOEXEC && fcntl(second, F_GETFD) == 0);
32 CHECK(!fstat(first, &st) && !fstat(second, &other) &&
33 (st.st_ino != other.st_ino || st.st_dev != other.st_dev));
34 CHECK(write(first, "a", 1) == 1 && !mf_size(second, 0));
35 CHECK(!fcntl(first, F_ADD_SEALS, F_SEAL_GROW) && fcntl(second, F_GET_SEALS) == 0);
36 memset(name, 'n', sizeof(name));
37 name[249] = 0;
38 CHECK((long_fd = memfd_create(name, MFD_ALLOW_SEALING)) >= 0);
39 name[249] = 'n';
40 name[250] = 0;
41 CHECK(memfd_create(name, 0) == -1 && errno == EINVAL);
42 CHECK(memfd_create("invalid", 0x80000000U) == -1 && errno == EINVAL);
43 CHECK(memfd_create("huge", MFD_HUGETLB) == -1 && errno == EINVAL);
44 denied = mmap(NULL, page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
45 CHECK(denied != MAP_FAILED);
46 CHECK(memfd_create(denied, 0) == -1 && errno == EFAULT);
47out:
48 umask(mask);
49 if (denied != MAP_FAILED)
50 munmap(denied, page);
51 if (long_fd >= 0)
52 close(long_fd);
53 if (second >= 0)
54 close(second);
55 if (first >= 0)
56 close(first);
57 if (plain >= 0)
58 close(plain);
59 return failed;
60}
61static int ordinary_io(void) {
62 int failed = 0, fd = -1, alias = -1, regular = -1;
63 char bytes[16] = {0};
64 char path[128];
65 snprintf(path, sizeof(path), "/tmp/memfd-regular-%ld", (long)getpid());
66 CHECK((fd = memfd_create("io", MFD_ALLOW_SEALING)) >= 0);
67 CHECK(write(fd, "abcd", 4) == 4 && pwrite(fd, "XY", 2, 1) == 2);
68 CHECK(lseek(fd, 0, SEEK_CUR) == 4 && !mf_contents(fd, 0, "aXYd", 4));
69 CHECK((alias = dup(fd)) >= 0);
70 CHECK(lseek(alias, 1, SEEK_SET) == 1 && read(fd, bytes, 2) == 2 && !memcmp(bytes, "XY", 2));
71 CHECK(lseek(alias, 0, SEEK_CUR) == 3);
72 struct iovec vector[] = {{"12", 2}, {"34", 2}};
73 CHECK(pwritev(fd, vector, 2, 4) == 4 && lseek(fd, 0, SEEK_CUR) == 3);
74 CHECK(!mf_contents(fd, 0, "aXYd1234", 8));
75 CHECK(lseek(fd, 0, SEEK_END) == 8 && writev(fd, vector, 2) == 4);
76 CHECK(!ftruncate(fd, 16) && !mf_contents(fd, 12, "\0\0\0\0", 4));
77 struct iovec input[] = {{bytes, 3}, {bytes + 3, 5}};
78 CHECK(preadv(fd, input, 2, 4) == 8 && !memcmp(bytes, "12341234", 8));
79 CHECK(!fcntl(alias, F_SETFL, O_APPEND));
80 CHECK((fcntl(fd, F_GETFL) & O_APPEND) && write(fd, "!", 1) == 1 && !mf_size(fd, 17));
81 CHECK(!mf_contents(fd, 16, "!", 1));
82 CHECK((regular = open(path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0);
83 CHECK(fcntl(regular, F_GET_SEALS) == -1 && errno == EINVAL);
84 CHECK(fcntl(regular, F_ADD_SEALS, F_SEAL_GROW) == -1 && errno == EINVAL);
85 CHECK(fcntl(-1, F_GET_SEALS) == -1 && errno == EBADF);
86out:
87 if (regular >= 0) {
88 close(regular);
89 unlink(path);
90 }
91 if (alias >= 0)
92 close(alias);
93 if (fd >= 0)
94 close(fd);
95 return failed;
96}
97int memfd_creation(void) {
98 return names_and_flags() || ordinary_io();
99}