]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/memfd_test.c
Add SPDX tags to recently added files
[FreeBSD/FreeBSD.git] / tests / sys / kern / memfd_test.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/fcntl.h>
33 #include <sys/mman.h>
34
35 #include <atf-c.h>
36 #include <errno.h>
37 #include <unistd.h>
38
39 ATF_TC_WITHOUT_HEAD(basic);
40 ATF_TC_BODY(basic, tc)
41 {
42         int fd;
43         char buf[8];
44
45         ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
46
47         /* File size should be initially 0 */
48         ATF_REQUIRE(write(fd, buf, sizeof(buf)) == 0);
49
50         /* ftruncate(2) must succeed without seals */
51         ATF_REQUIRE(ftruncate(fd, sizeof(buf) - 1) == 0);
52
53         ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf) - 1);
54
55         close(fd);
56 }
57
58 ATF_TC_WITHOUT_HEAD(cloexec);
59 ATF_TC_BODY(cloexec, tc)
60 {
61         int fd_nocl, fd_cl;
62
63         ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1);
64         ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1);
65
66         ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0);
67         ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0);
68
69         close(fd_nocl);
70         close(fd_cl);
71 }
72
73 ATF_TC_WITHOUT_HEAD(disallowed_sealing);
74 ATF_TC_BODY(disallowed_sealing, tc)
75 {
76         int fd;
77
78         ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
79         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL);
80         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
81         ATF_REQUIRE(errno == EPERM);
82
83         close(fd);
84 }
85
86 #define BUF_SIZE        1024
87
88 ATF_TC_WITHOUT_HEAD(write_seal);
89 ATF_TC_BODY(write_seal, tc)
90 {
91         int fd;
92         char *addr, buf[BUF_SIZE];
93
94         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
95         ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
96
97         /* Write once, then we'll seal it and try again */
98         ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE);
99         ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
100
101         addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
102         ATF_REQUIRE(addr != MAP_FAILED);
103         ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
104
105         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
106
107         ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1);
108         ATF_REQUIRE(errno == EPERM);
109
110         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
111             fd, 0) == MAP_FAILED);
112         ATF_REQUIRE(errno == EPERM);
113
114         close(fd);
115 }
116
117 ATF_TC_WITHOUT_HEAD(mmap_write_seal);
118 ATF_TC_BODY(mmap_write_seal, tc)
119 {
120         int fd;
121         char *addr, *paddr, *raddr;
122
123         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
124         ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
125
126         /* Map it, both shared and privately */
127         addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
128         ATF_REQUIRE(addr != MAP_FAILED);
129         paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
130         ATF_REQUIRE(paddr != MAP_FAILED);
131         raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
132         ATF_REQUIRE(raddr != MAP_FAILED);
133
134         /* Now try to seal it before unmapping */
135         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
136         ATF_REQUIRE(errno == EBUSY);
137
138         ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
139
140         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
141
142         ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
143         ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
144         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
145             fd, 0) == MAP_FAILED);
146         ATF_REQUIRE(errno == EPERM);
147         paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
148         ATF_REQUIRE(paddr != MAP_FAILED);
149         raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
150         ATF_REQUIRE(raddr != MAP_FAILED);
151         ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
152         ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
153
154         close(fd);
155 }
156
157 static int
158 memfd_truncate_test(int initial_size, int dest_size, int seals)
159 {
160         int err, fd;
161
162         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
163         ATF_REQUIRE(ftruncate(fd, initial_size) == 0);
164
165         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0);
166
167         err = ftruncate(fd, dest_size);
168         if (err != 0)
169                 err = errno;
170         close(fd);
171         return (err);
172 }
173
174 ATF_TC_WITHOUT_HEAD(truncate_seals);
175 ATF_TC_BODY(truncate_seals, tc)
176 {
177
178         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM);
179         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM);
180         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0);
181         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0);
182
183         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) ==
184             EPERM);
185         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
186             EPERM);
187         ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
188             0);
189 }
190
191 ATF_TC_WITHOUT_HEAD(get_seals);
192 ATF_TC_BODY(get_seals, tc)
193 {
194         int fd;
195         int seals;
196
197         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
198         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
199
200         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
201         seals = fcntl(fd, F_GET_SEALS);
202         ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
203
204         close(fd);
205 }
206
207 ATF_TC_WITHOUT_HEAD(dup_seals);
208 ATF_TC_BODY(dup_seals, tc)
209 {
210         char buf[8];
211         int fd, fdx;
212         int seals;
213
214         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
215         ATF_REQUIRE((fdx = dup(fd)) != -1);
216         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
217
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));
221
222         seals = fcntl(fdx, F_GET_SEALS);
223         ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
224
225         /* Make sure the seal's actually being applied at the inode level */
226         ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1);
227         ATF_REQUIRE(errno == EPERM);
228
229         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
230             fdx, 0) == MAP_FAILED);
231         ATF_REQUIRE(errno == EPERM);
232
233         close(fd);
234         close(fdx);
235 }
236
237 ATF_TC_WITHOUT_HEAD(immutable_seals);
238 ATF_TC_BODY(immutable_seals, tc)
239 {
240         int fd;
241
242         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
243
244         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0);
245         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
246         ATF_REQUIRE_MSG(errno == EPERM,
247             "Added unique grow seal after restricting seals");
248
249         close(fd);
250
251         /*
252          * Also check that adding a seal that already exists really doesn't
253          * do anything once we're sealed.
254          */
255         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
256
257         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0);
258         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
259         ATF_REQUIRE_MSG(errno == EPERM,
260             "Added duplicate grow seal after restricting seals");
261         close(fd);
262 }
263
264
265 ATF_TP_ADD_TCS(tp)
266 {
267
268         ATF_TP_ADD_TC(tp, basic);
269         ATF_TP_ADD_TC(tp, cloexec);
270         ATF_TP_ADD_TC(tp, disallowed_sealing);
271         ATF_TP_ADD_TC(tp, write_seal);
272         ATF_TP_ADD_TC(tp, mmap_write_seal);
273         ATF_TP_ADD_TC(tp, truncate_seals);
274         ATF_TP_ADD_TC(tp, get_seals);
275         ATF_TP_ADD_TC(tp, dup_seals);
276         ATF_TP_ADD_TC(tp, immutable_seals);
277         return (atf_no_error());
278 }