Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/posixshm/memfd_test.c
39534 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 Kyle Evans <[email protected]>
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
}
294
295