2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/fcntl.h>
39 ATF_TC_WITHOUT_HEAD(basic);
40 ATF_TC_BODY(basic, tc)
46 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
48 /* write(2) should grow us out automatically. */
49 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf));
50 ATF_REQUIRE(fstat(fd, &sb) == 0);
51 ATF_REQUIRE(sb.st_size == sizeof(buf));
53 /* ftruncate(2) must succeed without seals */
54 ATF_REQUIRE(ftruncate(fd, 2 * (sizeof(buf) - 1)) == 0);
56 /* write(2) again must not be limited by ftruncate(2) size. */
57 ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf));
60 ATF_REQUIRE(fstat(fd, &sb) == 0);
61 ATF_REQUIRE(sb.st_size == 2 * sizeof(buf));
66 ATF_TC_WITHOUT_HEAD(cloexec);
67 ATF_TC_BODY(cloexec, tc)
71 ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1);
72 ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1);
74 ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0);
75 ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0);
81 ATF_TC_WITHOUT_HEAD(disallowed_sealing);
82 ATF_TC_BODY(disallowed_sealing, tc)
86 ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
87 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL);
88 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
89 ATF_REQUIRE(errno == EPERM);
96 ATF_TC_WITHOUT_HEAD(write_seal);
97 ATF_TC_BODY(write_seal, tc)
100 char *addr, buf[BUF_SIZE];
102 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
103 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
105 /* Write once, then we'll seal it and try again */
106 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE);
107 ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
109 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
110 ATF_REQUIRE(addr != MAP_FAILED);
111 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
113 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
115 ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1);
116 ATF_REQUIRE(errno == EPERM);
118 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
119 fd, 0) == MAP_FAILED);
120 ATF_REQUIRE(errno == EACCES);
125 ATF_TC_WITHOUT_HEAD(mmap_write_seal);
126 ATF_TC_BODY(mmap_write_seal, tc)
129 char *addr, *paddr, *raddr;
131 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
132 ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
134 /* Map it, both shared and privately */
135 addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
136 ATF_REQUIRE(addr != MAP_FAILED);
137 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
138 ATF_REQUIRE(paddr != MAP_FAILED);
139 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
140 ATF_REQUIRE(raddr != MAP_FAILED);
142 /* Now try to seal it before unmapping */
143 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
144 ATF_REQUIRE(errno == EBUSY);
146 ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
149 * This should fail, because raddr still exists and it was spawned from
152 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
153 ATF_REQUIRE(errno == EBUSY);
155 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
156 /* This one should succeed; only the private mapping remains. */
157 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
159 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
160 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
161 fd, 0) == MAP_FAILED);
162 ATF_REQUIRE(errno == EACCES);
164 /* Make sure we can still map privately r/w or shared r/o. */
165 paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
166 ATF_REQUIRE(paddr != MAP_FAILED);
167 raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
168 ATF_REQUIRE(raddr != MAP_FAILED);
169 ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
170 ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
176 memfd_truncate_test(int initial_size, int dest_size, int seals)
180 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
181 ATF_REQUIRE(ftruncate(fd, initial_size) == 0);
183 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0);
185 err = ftruncate(fd, dest_size);
192 ATF_TC_WITHOUT_HEAD(truncate_seals);
193 ATF_TC_BODY(truncate_seals, tc)
196 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM);
197 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM);
198 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0);
199 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0);
201 ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) ==
203 ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
205 ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
209 ATF_TC_WITHOUT_HEAD(get_seals);
210 ATF_TC_BODY(get_seals, tc)
215 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
216 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
218 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
219 seals = fcntl(fd, F_GET_SEALS);
220 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
225 ATF_TC_WITHOUT_HEAD(dup_seals);
226 ATF_TC_BODY(dup_seals, tc)
232 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
233 ATF_REQUIRE((fdx = dup(fd)) != -1);
234 ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
236 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
237 seals = fcntl(fd, F_GET_SEALS);
238 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
240 seals = fcntl(fdx, F_GET_SEALS);
241 ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
243 /* Make sure the seal's actually being applied at the inode level */
244 ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1);
245 ATF_REQUIRE(errno == EPERM);
247 ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
248 fdx, 0) == MAP_FAILED);
249 ATF_REQUIRE(errno == EACCES);
255 ATF_TC_WITHOUT_HEAD(immutable_seals);
256 ATF_TC_BODY(immutable_seals, tc)
260 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
262 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0);
263 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
264 ATF_REQUIRE_MSG(errno == EPERM,
265 "Added unique grow seal after restricting seals");
270 * Also check that adding a seal that already exists really doesn't
271 * do anything once we're sealed.
273 ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
275 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0);
276 ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
277 ATF_REQUIRE_MSG(errno == EPERM,
278 "Added duplicate grow seal after restricting seals");
285 ATF_TP_ADD_TC(tp, basic);
286 ATF_TP_ADD_TC(tp, cloexec);
287 ATF_TP_ADD_TC(tp, disallowed_sealing);
288 ATF_TP_ADD_TC(tp, write_seal);
289 ATF_TP_ADD_TC(tp, mmap_write_seal);
290 ATF_TP_ADD_TC(tp, truncate_seals);
291 ATF_TP_ADD_TC(tp, get_seals);
292 ATF_TP_ADD_TC(tp, dup_seals);
293 ATF_TP_ADD_TC(tp, immutable_seals);
294 return (atf_no_error());