2 * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/fcntl.h>
37 ATF_TC_WITHOUT_HEAD(basic);
38 ATF_TC_BODY(basic, tc)
43 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
45 /* File size should be initially 0 */
46 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == 0);
48 /* ftruncate(2) must succeed without seals */
49 ATF_REQUIRE(ftruncate(fd, sizeof(buf) - 1) == 0);
51 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf) - 1);
56 ATF_TC_WITHOUT_HEAD(cloexec);
57 ATF_TC_BODY(cloexec, tc)
61 ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1);
62 ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1);
64 ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0);
65 ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0);
71 ATF_TC_WITHOUT_HEAD(disallowed_sealing);
72 ATF_TC_BODY(disallowed_sealing, tc)
76 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
77 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL);
78 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
79 ATF_REQUIRE(errno == EPERM);
86 ATF_TC_WITHOUT_HEAD(write_seal);
87 ATF_TC_BODY(write_seal, tc)
90 char *addr, buf[BUF_SIZE];
92 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
93 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
95 /* Write once, then we'll seal it and try again */
96 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE);
97 ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
99 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
100 ATF_REQUIRE(addr != MAP_FAILED);
101 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
103 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
105 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1);
106 ATF_REQUIRE(errno == EPERM);
108 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
109 fd, 0) == MAP_FAILED);
110 ATF_REQUIRE(errno == EPERM);
115 ATF_TC_WITHOUT_HEAD(mmap_write_seal);
116 ATF_TC_BODY(mmap_write_seal, tc)
119 char *addr, *paddr, *raddr;
121 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
122 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
124 /* Map it, both shared and privately */
125 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
126 ATF_REQUIRE(addr != MAP_FAILED);
127 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
128 ATF_REQUIRE(paddr != MAP_FAILED);
129 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
130 ATF_REQUIRE(raddr != MAP_FAILED);
132 /* Now try to seal it before unmapping */
133 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
134 ATF_REQUIRE(errno == EBUSY);
136 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
138 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
140 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
141 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
142 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
143 fd, 0) == MAP_FAILED);
144 ATF_REQUIRE(errno == EPERM);
145 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
146 ATF_REQUIRE(paddr != MAP_FAILED);
147 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
148 ATF_REQUIRE(raddr != MAP_FAILED);
149 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
150 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
156 memfd_truncate_test(int initial_size, int dest_size, int seals)
160 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
161 ATF_REQUIRE(ftruncate(fd, initial_size) == 0);
163 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0);
165 err = ftruncate(fd, dest_size);
172 ATF_TC_WITHOUT_HEAD(truncate_seals);
173 ATF_TC_BODY(truncate_seals, tc)
176 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM);
177 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM);
178 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0);
179 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0);
181 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) ==
183 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
185 ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
189 ATF_TC_WITHOUT_HEAD(get_seals);
190 ATF_TC_BODY(get_seals, tc)
195 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
196 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
198 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
199 seals = fcntl(fd, F_GET_SEALS);
200 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
205 ATF_TC_WITHOUT_HEAD(dup_seals);
206 ATF_TC_BODY(dup_seals, tc)
212 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
213 ATF_REQUIRE((fdx = dup(fd)) != -1);
214 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
216 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
217 seals = fcntl(fd, F_GET_SEALS);
218 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
220 seals = fcntl(fdx, F_GET_SEALS);
221 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
223 /* Make sure the seal's actually being applied at the inode level */
224 ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1);
225 ATF_REQUIRE(errno == EPERM);
227 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
228 fdx, 0) == MAP_FAILED);
229 ATF_REQUIRE(errno == EPERM);
235 ATF_TC_WITHOUT_HEAD(immutable_seals);
236 ATF_TC_BODY(immutable_seals, tc)
240 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
242 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0);
243 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
244 ATF_REQUIRE_MSG(errno == EPERM,
245 "Added unique grow seal after restricting seals");
250 * Also check that adding a seal that already exists really doesn't
251 * do anything once we're sealed.
253 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
255 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0);
256 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
257 ATF_REQUIRE_MSG(errno == EPERM,
258 "Added duplicate grow seal after restricting seals");
266 ATF_TP_ADD_TC(tp, basic);
267 ATF_TP_ADD_TC(tp, cloexec);
268 ATF_TP_ADD_TC(tp, disallowed_sealing);
269 ATF_TP_ADD_TC(tp, write_seal);
270 ATF_TP_ADD_TC(tp, mmap_write_seal);
271 ATF_TP_ADD_TC(tp, truncate_seals);
272 ATF_TP_ADD_TC(tp, get_seals);
273 ATF_TP_ADD_TC(tp, dup_seals);
274 ATF_TP_ADD_TC(tp, immutable_seals);
275 return (atf_no_error());