]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/posixshm/memfd_test.c
unbound: Import upstream 0ee44ef3 when ENOBUFS is returned
[FreeBSD/FreeBSD.git] / tests / sys / posixshm / memfd_test.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 #include <sys/fcntl.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32
33 #include <atf-c.h>
34 #include <errno.h>
35 #include <unistd.h>
36
37 ATF_TC_WITHOUT_HEAD(basic);
38 ATF_TC_BODY(basic, tc)
39 {
40         struct stat sb;
41         int fd;
42         char buf[8];
43
44         ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
45
46         /* write(2) should grow us out automatically. */
47         ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf));
48         ATF_REQUIRE(fstat(fd, &sb) == 0);
49         ATF_REQUIRE(sb.st_size == sizeof(buf));
50
51         /* ftruncate(2) must succeed without seals */
52         ATF_REQUIRE(ftruncate(fd, 2 * (sizeof(buf) - 1)) == 0);
53
54         /* write(2) again must not be limited by ftruncate(2) size. */
55         ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf));
56
57         /* Sanity check. */
58         ATF_REQUIRE(fstat(fd, &sb) == 0);
59         ATF_REQUIRE(sb.st_size == 2 * sizeof(buf));
60
61         close(fd);
62 }
63
64 ATF_TC_WITHOUT_HEAD(cloexec);
65 ATF_TC_BODY(cloexec, tc)
66 {
67         int fd_nocl, fd_cl;
68
69         ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1);
70         ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1);
71
72         ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0);
73         ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0);
74
75         close(fd_nocl);
76         close(fd_cl);
77 }
78
79 ATF_TC_WITHOUT_HEAD(disallowed_sealing);
80 ATF_TC_BODY(disallowed_sealing, tc)
81 {
82         int fd;
83
84         ATF_REQUIRE((fd = memfd_create("...", 0)) != -1);
85         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL);
86         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
87         ATF_REQUIRE(errno == EPERM);
88
89         close(fd);
90 }
91
92 #define BUF_SIZE        1024
93
94 ATF_TC_WITHOUT_HEAD(write_seal);
95 ATF_TC_BODY(write_seal, tc)
96 {
97         int fd;
98         char *addr, buf[BUF_SIZE];
99
100         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
101         ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
102
103         /* Write once, then we'll seal it and try again */
104         ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE);
105         ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
106
107         addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
108         ATF_REQUIRE(addr != MAP_FAILED);
109         ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
110
111         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
112
113         ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1);
114         ATF_REQUIRE(errno == EPERM);
115
116         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
117             fd, 0) == MAP_FAILED);
118         ATF_REQUIRE(errno == EACCES);
119
120         close(fd);
121 }
122
123 ATF_TC_WITHOUT_HEAD(mmap_write_seal);
124 ATF_TC_BODY(mmap_write_seal, tc)
125 {
126         int fd;
127         char *addr, *paddr, *raddr;
128
129         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
130         ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0);
131
132         /* Map it, both shared and privately */
133         addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
134         ATF_REQUIRE(addr != MAP_FAILED);
135         paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
136         ATF_REQUIRE(paddr != MAP_FAILED);
137         raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
138         ATF_REQUIRE(raddr != MAP_FAILED);
139
140         /* Now try to seal it before unmapping */
141         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
142         ATF_REQUIRE(errno == EBUSY);
143
144         ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0);
145
146         /*
147          * This should fail, because raddr still exists and it was spawned from
148          * a r/w fd.
149          */
150         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1);
151         ATF_REQUIRE(errno == EBUSY);
152
153         ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
154         /* This one should succeed; only the private mapping remains. */
155         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0);
156
157         ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
158         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
159             fd, 0) == MAP_FAILED);
160         ATF_REQUIRE(errno == EACCES);
161
162         /* Make sure we can still map privately r/w or shared r/o. */
163         paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
164         ATF_REQUIRE(paddr != MAP_FAILED);
165         raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0);
166         ATF_REQUIRE(raddr != MAP_FAILED);
167         ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0);
168         ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0);
169
170         close(fd);
171 }
172
173 static int
174 memfd_truncate_test(int initial_size, int dest_size, int seals)
175 {
176         int err, fd;
177
178         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
179         ATF_REQUIRE(ftruncate(fd, initial_size) == 0);
180
181         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0);
182
183         err = ftruncate(fd, dest_size);
184         if (err != 0)
185                 err = errno;
186         close(fd);
187         return (err);
188 }
189
190 ATF_TC_WITHOUT_HEAD(truncate_seals);
191 ATF_TC_BODY(truncate_seals, tc)
192 {
193
194         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM);
195         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM);
196         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0);
197         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0);
198
199         ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) ==
200             EPERM);
201         ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
202             EPERM);
203         ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) ==
204             0);
205 }
206
207 ATF_TC_WITHOUT_HEAD(get_seals);
208 ATF_TC_BODY(get_seals, tc)
209 {
210         int fd;
211         int seals;
212
213         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
214         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
215
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));
219
220         close(fd);
221 }
222
223 ATF_TC_WITHOUT_HEAD(dup_seals);
224 ATF_TC_BODY(dup_seals, tc)
225 {
226         char buf[8];
227         int fd, fdx;
228         int seals;
229
230         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
231         ATF_REQUIRE((fdx = dup(fd)) != -1);
232         ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0);
233
234         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0);
235         seals = fcntl(fd, F_GET_SEALS);
236         ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
237
238         seals = fcntl(fdx, F_GET_SEALS);
239         ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW));
240
241         /* Make sure the seal's actually being applied at the inode level */
242         ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1);
243         ATF_REQUIRE(errno == EPERM);
244
245         ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED,
246             fdx, 0) == MAP_FAILED);
247         ATF_REQUIRE(errno == EACCES);
248
249         close(fd);
250         close(fdx);
251 }
252
253 ATF_TC_WITHOUT_HEAD(immutable_seals);
254 ATF_TC_BODY(immutable_seals, tc)
255 {
256         int fd;
257
258         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
259
260         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0);
261         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
262         ATF_REQUIRE_MSG(errno == EPERM,
263             "Added unique grow seal after restricting seals");
264
265         close(fd);
266
267         /*
268          * Also check that adding a seal that already exists really doesn't
269          * do anything once we're sealed.
270          */
271         ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1);
272
273         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0);
274         ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1);
275         ATF_REQUIRE_MSG(errno == EPERM,
276             "Added duplicate grow seal after restricting seals");
277         close(fd);
278 }
279
280 ATF_TP_ADD_TCS(tp)
281 {
282
283         ATF_TP_ADD_TC(tp, basic);
284         ATF_TP_ADD_TC(tp, cloexec);
285         ATF_TP_ADD_TC(tp, disallowed_sealing);
286         ATF_TP_ADD_TC(tp, write_seal);
287         ATF_TP_ADD_TC(tp, mmap_write_seal);
288         ATF_TP_ADD_TC(tp, truncate_seals);
289         ATF_TP_ADD_TC(tp, get_seals);
290         ATF_TP_ADD_TC(tp, dup_seals);
291         ATF_TP_ADD_TC(tp, immutable_seals);
292         return (atf_no_error());
293 }