Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/capsicum-test/fcntl.cc
39475 views
1
// Test that fcntl works in capability mode.
2
#include <sys/types.h>
3
#include <sys/stat.h>
4
#include <fcntl.h>
5
#include <sys/types.h>
6
#include <sys/socket.h>
7
#include <sys/mman.h>
8
#include <sys/stat.h>
9
#include <fcntl.h>
10
#include <unistd.h>
11
#include <stdint.h>
12
13
#include <string>
14
#include <map>
15
16
#include "capsicum.h"
17
#include "capsicum-test.h"
18
#include "syscalls.h"
19
20
// Ensure that fcntl() works consistently for both regular file descriptors and
21
// capability-wrapped ones.
22
FORK_TEST(Fcntl, Basic) {
23
cap_rights_t rights;
24
cap_rights_init(&rights, CAP_READ, CAP_FCNTL);
25
26
typedef std::map<std::string, int> FileMap;
27
28
// Open some files of different types, and wrap them in capabilities.
29
FileMap files;
30
files["file"] = open("/etc/passwd", O_RDONLY);
31
EXPECT_OK(files["file"]);
32
files["socket"] = socket(PF_LOCAL, SOCK_STREAM, 0);
33
EXPECT_OK(files["socket"]);
34
char shm_name[128];
35
sprintf(shm_name, "/capsicum-test-%d", getuid());
36
files["SHM"] = shm_open(shm_name, (O_CREAT|O_RDWR), 0600);
37
if ((files["SHM"] == -1) && errno == ENOSYS) {
38
// shm_open() is not implemented in user-mode Linux.
39
files.erase("SHM");
40
} else {
41
EXPECT_OK(files["SHM"]);
42
}
43
44
FileMap caps;
45
for (FileMap::iterator ii = files.begin(); ii != files.end(); ++ii) {
46
std::string key = ii->first + " cap";
47
caps[key] = dup(ii->second);
48
EXPECT_OK(cap_rights_limit(caps[key], &rights));
49
EXPECT_OK(caps[key]) << " on " << ii->first;
50
}
51
52
FileMap all(files);
53
all.insert(files.begin(), files.end());
54
55
EXPECT_OK(cap_enter()); // Enter capability mode.
56
57
// Ensure that we can fcntl() all the files that we opened above.
58
cap_rights_t r_ro;
59
cap_rights_init(&r_ro, CAP_READ);
60
for (FileMap::iterator ii = all.begin(); ii != all.end(); ++ii) {
61
EXPECT_OK(fcntl(ii->second, F_GETFL, 0)) << " on " << ii->first;
62
int cap = dup(ii->second);
63
EXPECT_OK(cap) << " on " << ii->first;
64
EXPECT_OK(cap_rights_limit(cap, &r_ro)) << " on " << ii->first;
65
EXPECT_EQ(-1, fcntl(cap, F_GETFL, 0)) << " on " << ii->first;
66
EXPECT_EQ(ENOTCAPABLE, errno) << " on " << ii->first;
67
close(cap);
68
}
69
for (FileMap::iterator ii = all.begin(); ii != all.end(); ++ii) {
70
close(ii->second);
71
}
72
shm_unlink(shm_name);
73
}
74
75
// Supported fcntl(2) operations:
76
// FreeBSD10 FreeBSD9.1: Linux: Rights: Summary:
77
// F_DUPFD F_DUPFD F_DUPFD NONE as dup(2)
78
// F_DUPFD_CLOEXEC F_DUPFD_CLOEXEC NONE as dup(2) with close-on-exec
79
// F_DUP2FD F_DUP2FD NONE as dup2(2)
80
// F_DUP2FD_CLOEXEC NONE as dup2(2) with close-on-exec
81
// F_GETFD F_GETFD F_GETFD NONE get close-on-exec flag
82
// F_SETFD F_SETFD F_SETFD NONE set close-on-exec flag
83
// * F_GETFL F_GETFL F_GETFL FCNTL get file status flag
84
// * F_SETFL F_SETFL F_SETFL FCNTL set file status flag
85
// * F_GETOWN F_GETOWN F_GETOWN FCNTL get pid receiving SIGIO/SIGURG
86
// * F_SETOWN F_SETOWN F_SETOWN FCNTL set pid receiving SIGIO/SIGURG
87
// * F_GETOWN_EX FCNTL get pid/thread receiving SIGIO/SIGURG
88
// * F_SETOWN_EX FCNTL set pid/thread receiving SIGIO/SIGURG
89
// F_GETLK F_GETLK F_GETLK FLOCK get lock info
90
// F_SETLK F_SETLK F_SETLK FLOCK set lock info
91
// F_SETLK_REMOTE FLOCK set lock info
92
// F_SETLKW F_SETLKW F_SETLKW FLOCK set lock info (blocking)
93
// F_READAHEAD F_READAHEAD NONE set or clear readahead amount
94
// F_RDAHEAD F_RDAHEAD NONE set or clear readahead amount to 128KB
95
// F_GETSIG POLL_EVENT+FSIGNAL get signal sent when I/O possible
96
// F_SETSIG POLL_EVENT+FSIGNAL set signal sent when I/O possible
97
// F_GETLEASE FLOCK+FSIGNAL get lease on file descriptor
98
// F_SETLEASE FLOCK+FSIGNAL set new lease on file descriptor
99
// F_NOTIFY NOTIFY generate signal on changes (dnotify)
100
// F_GETPIPE_SZ GETSOCKOPT get pipe size
101
// F_SETPIPE_SZ SETSOCKOPT set pipe size
102
// F_GET_SEAL FSTAT get memfd seals
103
// F_ADD_SEAL FCHMOD set memfd seal
104
// If HAVE_CAP_FCNTLS_LIMIT is defined, then fcntl(2) operations that require
105
// CAP_FCNTL (marked with * above) can be further limited with cap_fcntls_limit(2).
106
namespace {
107
#define FCNTL_NUM_RIGHTS 9
108
cap_rights_t fcntl_rights[FCNTL_NUM_RIGHTS];
109
void InitRights() {
110
cap_rights_init(&(fcntl_rights[0]), 0); // Later code assumes this is at [0]
111
cap_rights_init(&(fcntl_rights[1]), CAP_READ, CAP_WRITE);
112
cap_rights_init(&(fcntl_rights[2]), CAP_FCNTL);
113
cap_rights_init(&(fcntl_rights[3]), CAP_FLOCK);
114
#ifdef CAP_FSIGNAL
115
cap_rights_init(&(fcntl_rights[4]), CAP_EVENT, CAP_FSIGNAL);
116
cap_rights_init(&(fcntl_rights[5]), CAP_FLOCK, CAP_FSIGNAL);
117
#else
118
cap_rights_init(&(fcntl_rights[4]), 0);
119
cap_rights_init(&(fcntl_rights[5]), 0);
120
#endif
121
#ifdef CAP_NOTIFY
122
cap_rights_init(&(fcntl_rights[6]), CAP_NOTIFY);
123
#else
124
cap_rights_init(&(fcntl_rights[6]), 0);
125
#endif
126
cap_rights_init(&(fcntl_rights[7]), CAP_SETSOCKOPT);
127
cap_rights_init(&(fcntl_rights[8]), CAP_GETSOCKOPT);
128
}
129
130
int CheckFcntl(unsigned long long right, int caps[FCNTL_NUM_RIGHTS], int cmd, long arg, const char* context) {
131
SCOPED_TRACE(context);
132
cap_rights_t rights;
133
cap_rights_init(&rights, right);
134
int ok_index = -1;
135
for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
136
if (cap_rights_contains(&(fcntl_rights[ii]), &rights)) {
137
if (ok_index == -1) ok_index = ii;
138
continue;
139
}
140
EXPECT_NOTCAPABLE(fcntl(caps[ii], cmd, arg));
141
}
142
EXPECT_NE(-1, ok_index);
143
int rc = fcntl(caps[ok_index], cmd, arg);
144
EXPECT_OK(rc);
145
return rc;
146
}
147
} // namespace
148
149
#define CHECK_FCNTL(right, caps, cmd, arg) \
150
CheckFcntl(right, caps, cmd, arg, "fcntl(" #cmd ") expect " #right)
151
152
TEST(Fcntl, Commands) {
153
InitRights();
154
int fd = open(TmpFile("cap_fcntl_cmds"), O_RDWR|O_CREAT, 0644);
155
EXPECT_OK(fd);
156
write(fd, "TEST", 4);
157
int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
158
EXPECT_OK(sock);
159
int caps[FCNTL_NUM_RIGHTS];
160
int sock_caps[FCNTL_NUM_RIGHTS];
161
for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
162
caps[ii] = dup(fd);
163
EXPECT_OK(caps[ii]);
164
EXPECT_OK(cap_rights_limit(caps[ii], &(fcntl_rights[ii])));
165
sock_caps[ii] = dup(sock);
166
EXPECT_OK(sock_caps[ii]);
167
EXPECT_OK(cap_rights_limit(sock_caps[ii], &(fcntl_rights[ii])));
168
}
169
170
// Check the things that need no rights against caps[0].
171
int newfd = fcntl(caps[0], F_DUPFD, 0);
172
EXPECT_OK(newfd);
173
// dup()'ed FD should have same rights.
174
cap_rights_t rights;
175
cap_rights_init(&rights, 0);
176
EXPECT_OK(cap_rights_get(newfd, &rights));
177
EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
178
close(newfd);
179
#ifdef HAVE_F_DUP2FD
180
EXPECT_OK(fcntl(caps[0], F_DUP2FD, newfd));
181
// dup2()'ed FD should have same rights.
182
EXPECT_OK(cap_rights_get(newfd, &rights));
183
EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
184
close(newfd);
185
#endif
186
187
EXPECT_OK(fcntl(caps[0], F_GETFD, 0));
188
EXPECT_OK(fcntl(caps[0], F_SETFD, 0));
189
190
// Check operations that need CAP_FCNTL.
191
int fd_flag = CHECK_FCNTL(CAP_FCNTL, caps, F_GETFL, 0);
192
EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, caps, F_SETFL, fd_flag));
193
int owner = CHECK_FCNTL(CAP_FCNTL, sock_caps, F_GETOWN, 0);
194
EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, sock_caps, F_SETOWN, owner));
195
196
// Check an operation needing CAP_FLOCK.
197
struct flock fl;
198
memset(&fl, 0, sizeof(fl));
199
fl.l_type = F_RDLCK;
200
fl.l_whence = SEEK_SET;
201
fl.l_start = 0;
202
fl.l_len = 1;
203
EXPECT_EQ(0, CHECK_FCNTL(CAP_FLOCK, caps, F_GETLK, (long)&fl));
204
205
for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
206
close(sock_caps[ii]);
207
close(caps[ii]);
208
}
209
close(sock);
210
close(fd);
211
unlink(TmpFile("cap_fcntl_cmds"));
212
}
213
214
TEST(Fcntl, WriteLock) {
215
int fd = open(TmpFile("cap_fcntl_readlock"), O_RDWR|O_CREAT, 0644);
216
EXPECT_OK(fd);
217
write(fd, "TEST", 4);
218
219
int cap = dup(fd);
220
cap_rights_t rights;
221
cap_rights_init(&rights, CAP_FCNTL, CAP_READ, CAP_WRITE, CAP_FLOCK);
222
EXPECT_OK(cap_rights_limit(cap, &rights));
223
224
struct flock fl;
225
memset(&fl, 0, sizeof(fl));
226
fl.l_type = F_WRLCK;
227
fl.l_whence = SEEK_SET;
228
fl.l_start = 0;
229
fl.l_len = 1;
230
// Write-Lock
231
EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
232
233
// Check write-locked (from another process).
234
pid_t child = fork();
235
if (child == 0) {
236
fl.l_type = F_WRLCK;
237
fl.l_whence = SEEK_SET;
238
fl.l_start = 0;
239
fl.l_len = 1;
240
EXPECT_OK(fcntl(fd, F_GETLK, (long)&fl));
241
EXPECT_NE(F_UNLCK, fl.l_type);
242
exit(HasFailure());
243
}
244
int status;
245
EXPECT_EQ(child, waitpid(child, &status, 0));
246
int rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
247
EXPECT_EQ(0, rc);
248
249
// Unlock
250
fl.l_type = F_UNLCK;
251
fl.l_whence = SEEK_SET;
252
fl.l_start = 0;
253
fl.l_len = 1;
254
EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
255
256
close(cap);
257
close(fd);
258
unlink(TmpFile("cap_fcntl_readlock"));
259
}
260
261
#ifdef HAVE_CAP_FCNTLS_LIMIT
262
TEST(Fcntl, SubRightNormalFD) {
263
int fd = open(TmpFile("cap_fcntl_subrightnorm"), O_RDWR|O_CREAT, 0644);
264
EXPECT_OK(fd);
265
266
// Restrict the fcntl(2) subrights of a normal FD.
267
EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
268
int fd_flag = fcntl(fd, F_GETFL, 0);
269
EXPECT_OK(fd_flag);
270
EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
271
272
// Expect to have all capabilities.
273
cap_rights_t rights;
274
EXPECT_OK(cap_rights_get(fd, &rights));
275
cap_rights_t all;
276
CAP_SET_ALL(&all);
277
EXPECT_RIGHTS_EQ(&all, &rights);
278
cap_fcntl_t fcntls;
279
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
280
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
281
282
// Can't widen the subrights.
283
EXPECT_NOTCAPABLE(cap_fcntls_limit(fd, CAP_FCNTL_GETFL|CAP_FCNTL_SETFL));
284
285
close(fd);
286
unlink(TmpFile("cap_fcntl_subrightnorm"));
287
}
288
289
TEST(Fcntl, PreserveSubRights) {
290
int fd = open(TmpFile("cap_fcntl_subrightpreserve"), O_RDWR|O_CREAT, 0644);
291
EXPECT_OK(fd);
292
293
cap_rights_t rights;
294
cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FCNTL);
295
EXPECT_OK(cap_rights_limit(fd, &rights));
296
EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
297
298
cap_rights_t cur_rights;
299
cap_fcntl_t fcntls;
300
EXPECT_OK(cap_rights_get(fd, &cur_rights));
301
EXPECT_RIGHTS_EQ(&rights, &cur_rights);
302
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
303
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
304
305
// Limiting the top-level rights leaves the subrights unaffected...
306
cap_rights_clear(&rights, CAP_READ);
307
EXPECT_OK(cap_rights_limit(fd, &rights));
308
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
309
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
310
311
// ... until we remove CAP_FCNTL.
312
cap_rights_clear(&rights, CAP_FCNTL);
313
EXPECT_OK(cap_rights_limit(fd, &rights));
314
EXPECT_OK(cap_fcntls_get(fd, &fcntls));
315
EXPECT_EQ((cap_fcntl_t)0, fcntls);
316
EXPECT_EQ(-1, cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
317
318
close(fd);
319
unlink(TmpFile("cap_fcntl_subrightpreserve"));
320
}
321
322
TEST(Fcntl, FLSubRights) {
323
int fd = open(TmpFile("cap_fcntl_subrights"), O_RDWR|O_CREAT, 0644);
324
EXPECT_OK(fd);
325
write(fd, "TEST", 4);
326
cap_rights_t rights;
327
cap_rights_init(&rights, CAP_FCNTL);
328
EXPECT_OK(cap_rights_limit(fd, &rights));
329
330
// Check operations that need CAP_FCNTL with subrights pristine => OK.
331
int fd_flag = fcntl(fd, F_GETFL, 0);
332
EXPECT_OK(fd_flag);
333
EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
334
335
// Check operations that need CAP_FCNTL with all subrights => OK.
336
EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_ALL));
337
fd_flag = fcntl(fd, F_GETFL, 0);
338
EXPECT_OK(fd_flag);
339
EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
340
341
// Check operations that need CAP_FCNTL with specific subrights.
342
int fd_get = dup(fd);
343
int fd_set = dup(fd);
344
EXPECT_OK(cap_fcntls_limit(fd_get, CAP_FCNTL_GETFL));
345
EXPECT_OK(cap_fcntls_limit(fd_set, CAP_FCNTL_SETFL));
346
347
fd_flag = fcntl(fd_get, F_GETFL, 0);
348
EXPECT_OK(fd_flag);
349
EXPECT_NOTCAPABLE(fcntl(fd_set, F_GETFL, 0));
350
EXPECT_OK(fcntl(fd_set, F_SETFL, fd_flag));
351
EXPECT_NOTCAPABLE(fcntl(fd_get, F_SETFL, fd_flag));
352
close(fd_get);
353
close(fd_set);
354
355
// Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
356
EXPECT_OK(cap_fcntls_limit(fd, 0));
357
EXPECT_NOTCAPABLE(fcntl(fd, F_GETFL, 0));
358
EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
359
360
close(fd);
361
unlink(TmpFile("cap_fcntl_subrights"));
362
}
363
364
TEST(Fcntl, OWNSubRights) {
365
int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
366
EXPECT_OK(sock);
367
cap_rights_t rights;
368
cap_rights_init(&rights, CAP_FCNTL);
369
EXPECT_OK(cap_rights_limit(sock, &rights));
370
371
// Check operations that need CAP_FCNTL with no subrights => OK.
372
int owner = fcntl(sock, F_GETOWN, 0);
373
EXPECT_OK(owner);
374
EXPECT_OK(fcntl(sock, F_SETOWN, owner));
375
376
// Check operations that need CAP_FCNTL with all subrights => OK.
377
EXPECT_OK(cap_fcntls_limit(sock, CAP_FCNTL_ALL));
378
owner = fcntl(sock, F_GETOWN, 0);
379
EXPECT_OK(owner);
380
EXPECT_OK(fcntl(sock, F_SETOWN, owner));
381
382
// Check operations that need CAP_FCNTL with specific subrights.
383
int sock_get = dup(sock);
384
int sock_set = dup(sock);
385
EXPECT_OK(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN));
386
EXPECT_OK(cap_fcntls_limit(sock_set, CAP_FCNTL_SETOWN));
387
owner = fcntl(sock_get, F_GETOWN, 0);
388
EXPECT_OK(owner);
389
EXPECT_NOTCAPABLE(fcntl(sock_set, F_GETOWN, 0));
390
EXPECT_OK(fcntl(sock_set, F_SETOWN, owner));
391
EXPECT_NOTCAPABLE(fcntl(sock_get, F_SETOWN, owner));
392
// Also check we can retrieve the subrights.
393
cap_fcntl_t fcntls;
394
EXPECT_OK(cap_fcntls_get(sock_get, &fcntls));
395
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETOWN, fcntls);
396
EXPECT_OK(cap_fcntls_get(sock_set, &fcntls));
397
EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_SETOWN, fcntls);
398
// And that we can't widen the subrights.
399
EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
400
EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_set, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
401
close(sock_get);
402
close(sock_set);
403
404
// Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
405
EXPECT_OK(cap_fcntls_limit(sock, 0));
406
EXPECT_NOTCAPABLE(fcntl(sock, F_GETOWN, 0));
407
EXPECT_NOTCAPABLE(fcntl(sock, F_SETOWN, owner));
408
409
close(sock);
410
}
411
#endif
412
413