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