xref: /freebsd/contrib/capsicum-test/capability-fd.cc (revision 8ac5aef8f354384d727d3d25b8d4c195596647c1)
1*8ac5aef8SEnji Cooper #include <stdio.h>
2*8ac5aef8SEnji Cooper #include <unistd.h>
3*8ac5aef8SEnji Cooper #include <sys/file.h>
4*8ac5aef8SEnji Cooper #include <sys/types.h>
5*8ac5aef8SEnji Cooper #include <sys/wait.h>
6*8ac5aef8SEnji Cooper #include <sys/stat.h>
7*8ac5aef8SEnji Cooper #include <sys/mman.h>
8*8ac5aef8SEnji Cooper #include <sys/select.h>
9*8ac5aef8SEnji Cooper #include <sys/socket.h>
10*8ac5aef8SEnji Cooper #include <sys/time.h>
11*8ac5aef8SEnji Cooper #include <errno.h>
12*8ac5aef8SEnji Cooper #include <fcntl.h>
13*8ac5aef8SEnji Cooper #include <poll.h>
14*8ac5aef8SEnji Cooper #include <stdint.h>
15*8ac5aef8SEnji Cooper 
16*8ac5aef8SEnji Cooper #include "capsicum.h"
17*8ac5aef8SEnji Cooper #include "syscalls.h"
18*8ac5aef8SEnji Cooper #include "capsicum-test.h"
19*8ac5aef8SEnji Cooper 
20*8ac5aef8SEnji Cooper /* Utilities for printing rights information */
21*8ac5aef8SEnji Cooper /* Written in C style to allow for: */
22*8ac5aef8SEnji Cooper /* TODO(drysdale): migrate these to somewhere in libcaprights/ */
23*8ac5aef8SEnji Cooper #define RIGHTS_INFO(RR) { (RR), #RR}
24*8ac5aef8SEnji Cooper typedef struct {
25*8ac5aef8SEnji Cooper   uint64_t right;
26*8ac5aef8SEnji Cooper   const char* name;
27*8ac5aef8SEnji Cooper } right_info;
28*8ac5aef8SEnji Cooper static right_info known_rights[] = {
29*8ac5aef8SEnji Cooper   /* Rights that are common to all versions of Capsicum */
30*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_READ),
31*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_WRITE),
32*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEEK_TELL),
33*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEEK),
34*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PREAD),
35*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PWRITE),
36*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP),
37*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_R),
38*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_W),
39*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_X),
40*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RW),
41*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RX),
42*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_WX),
43*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RWX),
44*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CREATE),
45*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FEXECVE),
46*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSYNC),
47*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FTRUNCATE),
48*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LOOKUP),
49*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHDIR),
50*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHFLAGS),
51*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CHFLAGSAT),
52*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHMOD),
53*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHMODAT),
54*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHOWN),
55*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHOWNAT),
56*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCNTL),
57*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FLOCK),
58*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FPATHCONF),
59*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSCK),
60*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTAT),
61*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTATAT),
62*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTATFS),
63*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FUTIMES),
64*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FUTIMESAT),
65*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKDIRAT),
66*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKFIFOAT),
67*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKNODAT),
68*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RENAMEAT_SOURCE),
69*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SYMLINKAT),
70*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_UNLINKAT),
71*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACCEPT),
72*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BIND),
73*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CONNECT),
74*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETPEERNAME),
75*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETSOCKNAME),
76*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETSOCKOPT),
77*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LISTEN),
78*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PEELOFF),
79*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RECV),
80*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEND),
81*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SETSOCKOPT),
82*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SHUTDOWN),
83*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BINDAT),
84*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CONNECTAT),
85*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_SOURCE),
86*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RENAMEAT_TARGET),
87*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SOCK_CLIENT),
88*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SOCK_SERVER),
89*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MAC_GET),
90*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MAC_SET),
91*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_GETVALUE),
92*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_POST),
93*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_WAIT),
94*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EVENT),
95*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE_EVENT),
96*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_IOCTL),
97*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_TTYHOOK),
98*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDWAIT),
99*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDGETPID),
100*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDKILL),
101*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_DELETE),
102*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_GET),
103*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_LIST),
104*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_SET),
105*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_CHECK),
106*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_DELETE),
107*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_GET),
108*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_SET),
109*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE_CHANGE),
110*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE),
111*8ac5aef8SEnji Cooper   /* Rights that are only present in some version or some OS, and so are #ifdef'ed */
112*8ac5aef8SEnji Cooper   /* LINKAT got split */
113*8ac5aef8SEnji Cooper #ifdef CAP_LINKAT
114*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT),
115*8ac5aef8SEnji Cooper #endif
116*8ac5aef8SEnji Cooper #ifdef CAP_LINKAT_SOURCE
117*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_SOURCE),
118*8ac5aef8SEnji Cooper #endif
119*8ac5aef8SEnji Cooper #ifdef CAP_LINKAT_TARGET
120*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_TARGET),
121*8ac5aef8SEnji Cooper #endif
122*8ac5aef8SEnji Cooper   /* Linux aliased some FD operations for pdgetpid/pdkill */
123*8ac5aef8SEnji Cooper #ifdef CAP_PDGETPID_FREEBSD
124*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDGETPID_FREEBSD),
125*8ac5aef8SEnji Cooper #endif
126*8ac5aef8SEnji Cooper #ifdef CAP_PDKILL_FREEBSD
127*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDKILL_FREEBSD),
128*8ac5aef8SEnji Cooper #endif
129*8ac5aef8SEnji Cooper   /* Linux-specific rights */
130*8ac5aef8SEnji Cooper #ifdef CAP_FSIGNAL
131*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSIGNAL),
132*8ac5aef8SEnji Cooper #endif
133*8ac5aef8SEnji Cooper #ifdef CAP_EPOLL_CTL
134*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EPOLL_CTL),
135*8ac5aef8SEnji Cooper #endif
136*8ac5aef8SEnji Cooper #ifdef CAP_NOTIFY
137*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_NOTIFY),
138*8ac5aef8SEnji Cooper #endif
139*8ac5aef8SEnji Cooper #ifdef CAP_SETNS
140*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SETNS),
141*8ac5aef8SEnji Cooper #endif
142*8ac5aef8SEnji Cooper #ifdef CAP_PERFMON
143*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PERFMON),
144*8ac5aef8SEnji Cooper #endif
145*8ac5aef8SEnji Cooper #ifdef CAP_BPF
146*8ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BPF),
147*8ac5aef8SEnji Cooper #endif
148*8ac5aef8SEnji Cooper   /* Rights in later versions of FreeBSD (>10.0) */
149*8ac5aef8SEnji Cooper };
150*8ac5aef8SEnji Cooper 
151*8ac5aef8SEnji Cooper void ShowCapRights(FILE *out, int fd) {
152*8ac5aef8SEnji Cooper   size_t ii;
153*8ac5aef8SEnji Cooper   bool first = true;
154*8ac5aef8SEnji Cooper   cap_rights_t rights;
155*8ac5aef8SEnji Cooper   CAP_SET_NONE(&rights);
156*8ac5aef8SEnji Cooper   if (cap_rights_get(fd, &rights) < 0) {
157*8ac5aef8SEnji Cooper     fprintf(out, "Failed to get rights for fd %d: errno %d\n", fd, errno);
158*8ac5aef8SEnji Cooper     return;
159*8ac5aef8SEnji Cooper   }
160*8ac5aef8SEnji Cooper 
161*8ac5aef8SEnji Cooper   /* First print out all known rights */
162*8ac5aef8SEnji Cooper   size_t num_known = (sizeof(known_rights)/sizeof(known_rights[0]));
163*8ac5aef8SEnji Cooper   for (ii = 0; ii < num_known; ii++) {
164*8ac5aef8SEnji Cooper     if (cap_rights_is_set(&rights, known_rights[ii].right)) {
165*8ac5aef8SEnji Cooper       if (!first) fprintf(out, ",");
166*8ac5aef8SEnji Cooper       first = false;
167*8ac5aef8SEnji Cooper       fprintf(out, "%s", known_rights[ii].name);
168*8ac5aef8SEnji Cooper     }
169*8ac5aef8SEnji Cooper   }
170*8ac5aef8SEnji Cooper   /* Now repeat the loop, clearing rights we know of; this needs to be
171*8ac5aef8SEnji Cooper    * a separate loop because some named rights overlap.
172*8ac5aef8SEnji Cooper    */
173*8ac5aef8SEnji Cooper   for (ii = 0; ii < num_known; ii++) {
174*8ac5aef8SEnji Cooper     cap_rights_clear(&rights, known_rights[ii].right);
175*8ac5aef8SEnji Cooper   }
176*8ac5aef8SEnji Cooper   /* The following relies on the internal structure of cap_rights_t to
177*8ac5aef8SEnji Cooper    * try to show rights we don't know about. */
178*8ac5aef8SEnji Cooper   for (ii = 0; ii < (size_t)CAPARSIZE(&rights); ii++) {
179*8ac5aef8SEnji Cooper     uint64_t bits = (rights.cr_rights[0] & 0x01ffffffffffffffULL);
180*8ac5aef8SEnji Cooper     if (bits != 0) {
181*8ac5aef8SEnji Cooper       uint64_t which = 1;
182*8ac5aef8SEnji Cooper       for (which = 1; which < 0x0200000000000000 ; which <<= 1) {
183*8ac5aef8SEnji Cooper         if (bits & which) {
184*8ac5aef8SEnji Cooper           if (!first) fprintf(out, ",");
185*8ac5aef8SEnji Cooper           fprintf(out, "CAP_RIGHT(%d, 0x%016llxULL)", (int)ii, (long long unsigned)which);
186*8ac5aef8SEnji Cooper         }
187*8ac5aef8SEnji Cooper       }
188*8ac5aef8SEnji Cooper     }
189*8ac5aef8SEnji Cooper   }
190*8ac5aef8SEnji Cooper   fprintf(out, "\n");
191*8ac5aef8SEnji Cooper }
192*8ac5aef8SEnji Cooper 
193*8ac5aef8SEnji Cooper void ShowAllCapRights(FILE *out) {
194*8ac5aef8SEnji Cooper   int fd;
195*8ac5aef8SEnji Cooper   struct rlimit limits;
196*8ac5aef8SEnji Cooper   if (getrlimit(RLIMIT_NOFILE, &limits) != 0) {
197*8ac5aef8SEnji Cooper     fprintf(out, "Failed to getrlimit for max FDs: errno %d\n", errno);
198*8ac5aef8SEnji Cooper     return;
199*8ac5aef8SEnji Cooper   }
200*8ac5aef8SEnji Cooper   for (fd = 0; fd < (int)limits.rlim_cur; fd++) {
201*8ac5aef8SEnji Cooper     if (fcntl(fd, F_GETFD, 0) != 0) {
202*8ac5aef8SEnji Cooper       continue;
203*8ac5aef8SEnji Cooper     }
204*8ac5aef8SEnji Cooper     fprintf(out, "fd %d: ", fd);
205*8ac5aef8SEnji Cooper     ShowCapRights(out, fd);
206*8ac5aef8SEnji Cooper   }
207*8ac5aef8SEnji Cooper }
208*8ac5aef8SEnji Cooper 
209*8ac5aef8SEnji Cooper FORK_TEST(Capability, CapNew) {
210*8ac5aef8SEnji Cooper   cap_rights_t r_rws;
211*8ac5aef8SEnji Cooper   cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
212*8ac5aef8SEnji Cooper   cap_rights_t r_all;
213*8ac5aef8SEnji Cooper   CAP_SET_ALL(&r_all);
214*8ac5aef8SEnji Cooper 
215*8ac5aef8SEnji Cooper   int cap_fd = dup(STDOUT_FILENO);
216*8ac5aef8SEnji Cooper   cap_rights_t rights;
217*8ac5aef8SEnji Cooper   CAP_SET_NONE(&rights);
218*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &rights));
219*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_all, &rights);
220*8ac5aef8SEnji Cooper 
221*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
222*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rws));
223*8ac5aef8SEnji Cooper   if (cap_fd < 0) return;
224*8ac5aef8SEnji Cooper   int rc = write(cap_fd, "OK!\n", 4);
225*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
226*8ac5aef8SEnji Cooper   EXPECT_EQ(4, rc);
227*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &rights));
228*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
229*8ac5aef8SEnji Cooper 
230*8ac5aef8SEnji Cooper   // dup/dup2 should preserve rights.
231*8ac5aef8SEnji Cooper   int cap_dup = dup(cap_fd);
232*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dup);
233*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
234*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
235*8ac5aef8SEnji Cooper   close(cap_dup);
236*8ac5aef8SEnji Cooper   EXPECT_OK(dup2(cap_fd, cap_dup));
237*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
238*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
239*8ac5aef8SEnji Cooper   close(cap_dup);
240*8ac5aef8SEnji Cooper #ifdef HAVE_DUP3
241*8ac5aef8SEnji Cooper   EXPECT_OK(dup3(cap_fd, cap_dup, 0));
242*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
243*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
244*8ac5aef8SEnji Cooper   close(cap_dup);
245*8ac5aef8SEnji Cooper #endif
246*8ac5aef8SEnji Cooper 
247*8ac5aef8SEnji Cooper   // Try to get a disjoint set of rights in a sub-capability.
248*8ac5aef8SEnji Cooper   cap_rights_t r_rs;
249*8ac5aef8SEnji Cooper   cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
250*8ac5aef8SEnji Cooper   cap_rights_t r_rsmapchmod;
251*8ac5aef8SEnji Cooper   cap_rights_init(&r_rsmapchmod, CAP_READ, CAP_SEEK, CAP_MMAP, CAP_FCHMOD);
252*8ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
253*8ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
254*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(cap_rights_limit(cap_cap_fd, &r_rsmapchmod));
255*8ac5aef8SEnji Cooper 
256*8ac5aef8SEnji Cooper   // Dump rights info to stderr (mostly to ensure that Show[All]CapRights()
257*8ac5aef8SEnji Cooper   // is working.
258*8ac5aef8SEnji Cooper   ShowAllCapRights(stderr);
259*8ac5aef8SEnji Cooper 
260*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_fd));
261*8ac5aef8SEnji Cooper }
262*8ac5aef8SEnji Cooper 
263*8ac5aef8SEnji Cooper FORK_TEST(Capability, CapEnter) {
264*8ac5aef8SEnji Cooper   EXPECT_EQ(0, cap_enter());
265*8ac5aef8SEnji Cooper }
266*8ac5aef8SEnji Cooper 
267*8ac5aef8SEnji Cooper FORK_TEST(Capability, BasicInterception) {
268*8ac5aef8SEnji Cooper   cap_rights_t r_0;
269*8ac5aef8SEnji Cooper   cap_rights_init(&r_0, 0);
270*8ac5aef8SEnji Cooper   int cap_fd = dup(1);
271*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
272*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_0));
273*8ac5aef8SEnji Cooper 
274*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
275*8ac5aef8SEnji Cooper 
276*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode
277*8ac5aef8SEnji Cooper 
278*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
279*8ac5aef8SEnji Cooper 
280*8ac5aef8SEnji Cooper   // Create a new capability which does have write permission
281*8ac5aef8SEnji Cooper   cap_rights_t r_ws;
282*8ac5aef8SEnji Cooper   cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
283*8ac5aef8SEnji Cooper   int cap_fd2 = dup(1);
284*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd2);
285*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd2, &r_ws));
286*8ac5aef8SEnji Cooper   EXPECT_OK(write(cap_fd2, "", 0));
287*8ac5aef8SEnji Cooper 
288*8ac5aef8SEnji Cooper   // Tidy up.
289*8ac5aef8SEnji Cooper   if (cap_fd >= 0) close(cap_fd);
290*8ac5aef8SEnji Cooper   if (cap_fd2 >= 0) close(cap_fd2);
291*8ac5aef8SEnji Cooper }
292*8ac5aef8SEnji Cooper 
293*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, OpenAtDirectoryTraversal, TmpFile("cap_openat_testfile")) {
294*8ac5aef8SEnji Cooper   int dir = open(tmpdir.c_str(), O_RDONLY);
295*8ac5aef8SEnji Cooper   EXPECT_OK(dir);
296*8ac5aef8SEnji Cooper 
297*8ac5aef8SEnji Cooper   cap_enter();
298*8ac5aef8SEnji Cooper 
299*8ac5aef8SEnji Cooper   int file = openat(dir, "cap_openat_testfile", O_RDONLY|O_CREAT, 0644);
300*8ac5aef8SEnji Cooper   EXPECT_OK(file);
301*8ac5aef8SEnji Cooper 
302*8ac5aef8SEnji Cooper   // Test that we are confined to /tmp, and cannot
303*8ac5aef8SEnji Cooper   // escape using absolute paths or ../.
304*8ac5aef8SEnji Cooper   int new_file = openat(dir, "../dev/null", O_RDONLY);
305*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
306*8ac5aef8SEnji Cooper 
307*8ac5aef8SEnji Cooper   new_file = openat(dir, "..", O_RDONLY);
308*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
309*8ac5aef8SEnji Cooper 
310*8ac5aef8SEnji Cooper   new_file = openat(dir, "/dev/null", O_RDONLY);
311*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
312*8ac5aef8SEnji Cooper 
313*8ac5aef8SEnji Cooper   new_file = openat(dir, "/", O_RDONLY);
314*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
315*8ac5aef8SEnji Cooper 
316*8ac5aef8SEnji Cooper   // Tidy up.
317*8ac5aef8SEnji Cooper   close(file);
318*8ac5aef8SEnji Cooper   close(dir);
319*8ac5aef8SEnji Cooper }
320*8ac5aef8SEnji Cooper 
321*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, FileInSync, TmpFile("cap_file_sync")) {
322*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_file_sync"), O_RDWR|O_CREAT, 0644);
323*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
324*8ac5aef8SEnji Cooper   const char* message = "Hello capability world";
325*8ac5aef8SEnji Cooper   EXPECT_OK(write(fd, message, strlen(message)));
326*8ac5aef8SEnji Cooper 
327*8ac5aef8SEnji Cooper   cap_rights_t r_rsstat;
328*8ac5aef8SEnji Cooper   cap_rights_init(&r_rsstat, CAP_READ, CAP_SEEK, CAP_FSTAT);
329*8ac5aef8SEnji Cooper 
330*8ac5aef8SEnji Cooper   int cap_fd = dup(fd);
331*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
332*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rsstat));
333*8ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
334*8ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
335*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_cap_fd, &r_rsstat));
336*8ac5aef8SEnji Cooper 
337*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
338*8ac5aef8SEnji Cooper 
339*8ac5aef8SEnji Cooper   // Changes to one file descriptor affect the others.
340*8ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(fd, 1, SEEK_SET));
341*8ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(fd, 0, SEEK_CUR));
342*8ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(cap_fd, 0, SEEK_CUR));
343*8ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(cap_cap_fd, 0, SEEK_CUR));
344*8ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_fd, 3, SEEK_SET));
345*8ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(fd, 0, SEEK_CUR));
346*8ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_fd, 0, SEEK_CUR));
347*8ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_cap_fd, 0, SEEK_CUR));
348*8ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_cap_fd, 5, SEEK_SET));
349*8ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(fd, 0, SEEK_CUR));
350*8ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_fd, 0, SEEK_CUR));
351*8ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_cap_fd, 0, SEEK_CUR));
352*8ac5aef8SEnji Cooper 
353*8ac5aef8SEnji Cooper   close(cap_cap_fd);
354*8ac5aef8SEnji Cooper   close(cap_fd);
355*8ac5aef8SEnji Cooper   close(fd);
356*8ac5aef8SEnji Cooper }
357*8ac5aef8SEnji Cooper 
358*8ac5aef8SEnji Cooper // Create a capability on /tmp that does not allow CAP_WRITE,
359*8ac5aef8SEnji Cooper // and check that this restriction is inherited through openat().
360*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Inheritance, TmpFile("cap_openat_write_testfile")) {
361*8ac5aef8SEnji Cooper   int dir = open(tmpdir.c_str(), O_RDONLY);
362*8ac5aef8SEnji Cooper   EXPECT_OK(dir);
363*8ac5aef8SEnji Cooper 
364*8ac5aef8SEnji Cooper   cap_rights_t r_rl;
365*8ac5aef8SEnji Cooper   cap_rights_init(&r_rl, CAP_READ, CAP_LOOKUP);
366*8ac5aef8SEnji Cooper 
367*8ac5aef8SEnji Cooper   int cap_dir = dup(dir);
368*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dir);
369*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dir, &r_rl));
370*8ac5aef8SEnji Cooper 
371*8ac5aef8SEnji Cooper   const char *filename = "cap_openat_write_testfile";
372*8ac5aef8SEnji Cooper   int file = openat(dir, filename, O_WRONLY|O_CREAT, 0644);
373*8ac5aef8SEnji Cooper   EXPECT_OK(file);
374*8ac5aef8SEnji Cooper   EXPECT_EQ(5, write(file, "TEST\n", 5));
375*8ac5aef8SEnji Cooper   if (file >= 0) close(file);
376*8ac5aef8SEnji Cooper 
377*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());
378*8ac5aef8SEnji Cooper   file = openat(cap_dir, filename, O_RDONLY);
379*8ac5aef8SEnji Cooper   EXPECT_OK(file);
380*8ac5aef8SEnji Cooper 
381*8ac5aef8SEnji Cooper   cap_rights_t rights;
382*8ac5aef8SEnji Cooper   cap_rights_init(&rights, 0);
383*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(file, &rights));
384*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rl, &rights);
385*8ac5aef8SEnji Cooper   if (file >= 0) close(file);
386*8ac5aef8SEnji Cooper 
387*8ac5aef8SEnji Cooper   file = openat(cap_dir, filename, O_WRONLY|O_APPEND);
388*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(file);
389*8ac5aef8SEnji Cooper   if (file > 0) close(file);
390*8ac5aef8SEnji Cooper 
391*8ac5aef8SEnji Cooper   if (dir > 0) close(dir);
392*8ac5aef8SEnji Cooper   if (cap_dir > 0) close(cap_dir);
393*8ac5aef8SEnji Cooper }
394*8ac5aef8SEnji Cooper 
395*8ac5aef8SEnji Cooper 
396*8ac5aef8SEnji Cooper // Ensure that, if the capability had enough rights for the system call to
397*8ac5aef8SEnji Cooper // pass, then it did. Otherwise, ensure that the errno is ENOTCAPABLE;
398*8ac5aef8SEnji Cooper // capability restrictions should kick in before any other error logic.
399*8ac5aef8SEnji Cooper #define CHECK_RIGHT_RESULT(result, rights, ...) do {    \
400*8ac5aef8SEnji Cooper   cap_rights_t rights_needed;                           \
401*8ac5aef8SEnji Cooper   cap_rights_init(&rights_needed, __VA_ARGS__);         \
402*8ac5aef8SEnji Cooper   if (cap_rights_contains(&rights, &rights_needed)) {   \
403*8ac5aef8SEnji Cooper     EXPECT_OK(result) << std::endl                      \
404*8ac5aef8SEnji Cooper                       << " need: " << rights_needed     \
405*8ac5aef8SEnji Cooper                       << std::endl                      \
406*8ac5aef8SEnji Cooper                       << " got:  " << rights;           \
407*8ac5aef8SEnji Cooper   } else {                                              \
408*8ac5aef8SEnji Cooper     EXPECT_EQ(-1, result) << " need: " << rights_needed \
409*8ac5aef8SEnji Cooper                           << std::endl                  \
410*8ac5aef8SEnji Cooper                           << " got:  "<< rights;        \
411*8ac5aef8SEnji Cooper     EXPECT_EQ(ENOTCAPABLE, errno);                      \
412*8ac5aef8SEnji Cooper   }                                                     \
413*8ac5aef8SEnji Cooper } while (0)
414*8ac5aef8SEnji Cooper 
415*8ac5aef8SEnji Cooper #define EXPECT_MMAP_NOTCAPABLE(result) do {         \
416*8ac5aef8SEnji Cooper   void *rv = result;                                \
417*8ac5aef8SEnji Cooper   EXPECT_EQ(MAP_FAILED, rv);                        \
418*8ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);                    \
419*8ac5aef8SEnji Cooper   if (rv != MAP_FAILED) munmap(rv, getpagesize());  \
420*8ac5aef8SEnji Cooper } while (0)
421*8ac5aef8SEnji Cooper 
422*8ac5aef8SEnji Cooper #define EXPECT_MMAP_OK(result) do {                     \
423*8ac5aef8SEnji Cooper   void *rv = result;                                    \
424*8ac5aef8SEnji Cooper   EXPECT_NE(MAP_FAILED, rv) << " with errno " << errno; \
425*8ac5aef8SEnji Cooper   if (rv != MAP_FAILED) munmap(rv, getpagesize());      \
426*8ac5aef8SEnji Cooper } while (0)
427*8ac5aef8SEnji Cooper 
428*8ac5aef8SEnji Cooper 
429*8ac5aef8SEnji Cooper // As above, but for the special mmap() case: unmap after successful mmap().
430*8ac5aef8SEnji Cooper #define CHECK_RIGHT_MMAP_RESULT(result, rights, ...) do { \
431*8ac5aef8SEnji Cooper   cap_rights_t rights_needed;                             \
432*8ac5aef8SEnji Cooper   cap_rights_init(&rights_needed, __VA_ARGS__);           \
433*8ac5aef8SEnji Cooper   if (cap_rights_contains(&rights, &rights_needed)) {     \
434*8ac5aef8SEnji Cooper     EXPECT_MMAP_OK(result);                               \
435*8ac5aef8SEnji Cooper   } else {                                                \
436*8ac5aef8SEnji Cooper     EXPECT_MMAP_NOTCAPABLE(result);                       \
437*8ac5aef8SEnji Cooper   }                                                       \
438*8ac5aef8SEnji Cooper } while (0)
439*8ac5aef8SEnji Cooper 
440*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Mmap, TmpFile("cap_mmap_operations")) {
441*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_mmap_operations"), O_RDWR | O_CREAT, 0644);
442*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
443*8ac5aef8SEnji Cooper   if (fd < 0) return;
444*8ac5aef8SEnji Cooper 
445*8ac5aef8SEnji Cooper   cap_rights_t r_0;
446*8ac5aef8SEnji Cooper   cap_rights_init(&r_0, 0);
447*8ac5aef8SEnji Cooper   cap_rights_t r_mmap;
448*8ac5aef8SEnji Cooper   cap_rights_init(&r_mmap, CAP_MMAP);
449*8ac5aef8SEnji Cooper   cap_rights_t r_r;
450*8ac5aef8SEnji Cooper   cap_rights_init(&r_r, CAP_PREAD);
451*8ac5aef8SEnji Cooper   cap_rights_t r_rmmap;
452*8ac5aef8SEnji Cooper   cap_rights_init(&r_rmmap, CAP_PREAD, CAP_MMAP);
453*8ac5aef8SEnji Cooper 
454*8ac5aef8SEnji Cooper   // If we're missing a capability, it will fail.
455*8ac5aef8SEnji Cooper   int cap_none = dup(fd);
456*8ac5aef8SEnji Cooper   EXPECT_OK(cap_none);
457*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_none, &r_0));
458*8ac5aef8SEnji Cooper   int cap_mmap = dup(fd);
459*8ac5aef8SEnji Cooper   EXPECT_OK(cap_mmap);
460*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_mmap, &r_mmap));
461*8ac5aef8SEnji Cooper   int cap_read = dup(fd);
462*8ac5aef8SEnji Cooper   EXPECT_OK(cap_read);
463*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_read, &r_r));
464*8ac5aef8SEnji Cooper   int cap_both = dup(fd);
465*8ac5aef8SEnji Cooper   EXPECT_OK(cap_both);
466*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_both, &r_rmmap));
467*8ac5aef8SEnji Cooper 
468*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
469*8ac5aef8SEnji Cooper 
470*8ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_none, 0));
471*8ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_mmap, 0));
472*8ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_read, 0));
473*8ac5aef8SEnji Cooper 
474*8ac5aef8SEnji Cooper   EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_both, 0));
475*8ac5aef8SEnji Cooper 
476*8ac5aef8SEnji Cooper   // A call with MAP_ANONYMOUS should succeed without any capability requirements.
477*8ac5aef8SEnji Cooper   EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
478*8ac5aef8SEnji Cooper 
479*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_both));
480*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_read));
481*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_mmap));
482*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_none));
483*8ac5aef8SEnji Cooper   EXPECT_OK(close(fd));
484*8ac5aef8SEnji Cooper }
485*8ac5aef8SEnji Cooper 
486*8ac5aef8SEnji Cooper // Given a file descriptor, create a capability with specific rights and
487*8ac5aef8SEnji Cooper // make sure only those rights work.
488*8ac5aef8SEnji Cooper #define TRY_FILE_OPS(fd, ...) do {       \
489*8ac5aef8SEnji Cooper   cap_rights_t rights;                   \
490*8ac5aef8SEnji Cooper   cap_rights_init(&rights, __VA_ARGS__); \
491*8ac5aef8SEnji Cooper   TryFileOps((fd), rights);              \
492*8ac5aef8SEnji Cooper } while (0)
493*8ac5aef8SEnji Cooper 
494*8ac5aef8SEnji Cooper static void TryFileOps(int fd, cap_rights_t rights) {
495*8ac5aef8SEnji Cooper   int cap_fd = dup(fd);
496*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
497*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &rights));
498*8ac5aef8SEnji Cooper   if (cap_fd < 0) return;
499*8ac5aef8SEnji Cooper   cap_rights_t erights;
500*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &erights));
501*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
502*8ac5aef8SEnji Cooper 
503*8ac5aef8SEnji Cooper   // Check creation of a capability from a capability.
504*8ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
505*8ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
506*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_cap_fd, &rights));
507*8ac5aef8SEnji Cooper   EXPECT_NE(cap_fd, cap_cap_fd);
508*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_cap_fd, &erights));
509*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
510*8ac5aef8SEnji Cooper   close(cap_cap_fd);
511*8ac5aef8SEnji Cooper 
512*8ac5aef8SEnji Cooper   char ch;
513*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(read(cap_fd, &ch, sizeof(ch)), rights, CAP_READ, CAP_SEEK_ASWAS);
514*8ac5aef8SEnji Cooper 
515*8ac5aef8SEnji Cooper   ssize_t len1 = pread(cap_fd, &ch, sizeof(ch), 0);
516*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(len1, rights, CAP_PREAD);
517*8ac5aef8SEnji Cooper   ssize_t len2 = pread(cap_fd, &ch, sizeof(ch), 0);
518*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(len2, rights, CAP_PREAD);
519*8ac5aef8SEnji Cooper   EXPECT_EQ(len1, len2);
520*8ac5aef8SEnji Cooper 
521*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(write(cap_fd, &ch, sizeof(ch)), rights, CAP_WRITE, CAP_SEEK_ASWAS);
522*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(pwrite(cap_fd, &ch, sizeof(ch), 0), rights, CAP_PWRITE);
523*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(lseek(cap_fd, 0, SEEK_SET), rights, CAP_SEEK);
524*8ac5aef8SEnji Cooper 
525*8ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGS
526*8ac5aef8SEnji Cooper   // Note: this is not expected to work over NFS.
527*8ac5aef8SEnji Cooper   struct statfs sf;
528*8ac5aef8SEnji Cooper   EXPECT_OK(fstatfs(fd, &sf));
529*8ac5aef8SEnji Cooper   bool is_nfs = (strncmp("nfs", sf.f_fstypename, sizeof(sf.f_fstypename)) == 0);
530*8ac5aef8SEnji Cooper   if (!is_nfs) {
531*8ac5aef8SEnji Cooper     CHECK_RIGHT_RESULT(fchflags(cap_fd, UF_NODUMP), rights, CAP_FCHFLAGS);
532*8ac5aef8SEnji Cooper   }
533*8ac5aef8SEnji Cooper #endif
534*8ac5aef8SEnji Cooper 
535*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, cap_fd, 0),
536*8ac5aef8SEnji Cooper                           rights, CAP_MMAP);
537*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, cap_fd, 0),
538*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_R);
539*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, cap_fd, 0),
540*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_W);
541*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, cap_fd, 0),
542*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_X);
543*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, cap_fd, 0),
544*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_RW);
545*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED, cap_fd, 0),
546*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_RX);
547*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED, cap_fd, 0),
548*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_WX);
549*8ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, cap_fd, 0),
550*8ac5aef8SEnji Cooper                           rights, CAP_MMAP_RWX);
551*8ac5aef8SEnji Cooper 
552*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fsync(cap_fd), rights, CAP_FSYNC);
553*8ac5aef8SEnji Cooper #ifdef HAVE_SYNC_FILE_RANGE
554*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(sync_file_range(cap_fd, 0, 1, 0), rights, CAP_FSYNC, CAP_SEEK);
555*8ac5aef8SEnji Cooper #endif
556*8ac5aef8SEnji Cooper 
557*8ac5aef8SEnji Cooper   int rc = fcntl(cap_fd, F_GETFL);
558*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
559*8ac5aef8SEnji Cooper   rc = fcntl(cap_fd, F_SETFL, rc);
560*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
561*8ac5aef8SEnji Cooper 
562*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fchown(cap_fd, -1, -1), rights, CAP_FCHOWN);
563*8ac5aef8SEnji Cooper 
564*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fchmod(cap_fd, 0644), rights, CAP_FCHMOD);
565*8ac5aef8SEnji Cooper 
566*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_SH), rights, CAP_FLOCK);
567*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_UN), rights, CAP_FLOCK);
568*8ac5aef8SEnji Cooper 
569*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(ftruncate(cap_fd, 0), rights, CAP_FTRUNCATE);
570*8ac5aef8SEnji Cooper 
571*8ac5aef8SEnji Cooper   struct stat sb;
572*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fstat(cap_fd, &sb), rights, CAP_FSTAT);
573*8ac5aef8SEnji Cooper 
574*8ac5aef8SEnji Cooper   struct statfs cap_sf;
575*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fstatfs(cap_fd, &cap_sf), rights, CAP_FSTATFS);
576*8ac5aef8SEnji Cooper 
577*8ac5aef8SEnji Cooper #ifdef HAVE_FPATHCONF
578*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fpathconf(cap_fd, _PC_NAME_MAX), rights, CAP_FPATHCONF);
579*8ac5aef8SEnji Cooper #endif
580*8ac5aef8SEnji Cooper 
581*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(futimes(cap_fd, NULL), rights, CAP_FUTIMES);
582*8ac5aef8SEnji Cooper 
583*8ac5aef8SEnji Cooper   struct pollfd pollfd;
584*8ac5aef8SEnji Cooper   pollfd.fd = cap_fd;
585*8ac5aef8SEnji Cooper   pollfd.events = POLLIN | POLLERR | POLLHUP;
586*8ac5aef8SEnji Cooper   pollfd.revents = 0;
587*8ac5aef8SEnji Cooper   int ret = poll(&pollfd, 1, 0);
588*8ac5aef8SEnji Cooper   if (cap_rights_is_set(&rights, CAP_EVENT)) {
589*8ac5aef8SEnji Cooper     EXPECT_OK(ret);
590*8ac5aef8SEnji Cooper   } else {
591*8ac5aef8SEnji Cooper     EXPECT_NE(0, (pollfd.revents & POLLNVAL));
592*8ac5aef8SEnji Cooper   }
593*8ac5aef8SEnji Cooper 
594*8ac5aef8SEnji Cooper   struct timeval tv;
595*8ac5aef8SEnji Cooper   tv.tv_sec = 0;
596*8ac5aef8SEnji Cooper   tv.tv_usec = 100;
597*8ac5aef8SEnji Cooper   fd_set rset;
598*8ac5aef8SEnji Cooper   FD_ZERO(&rset);
599*8ac5aef8SEnji Cooper   FD_SET(cap_fd, &rset);
600*8ac5aef8SEnji Cooper   fd_set wset;
601*8ac5aef8SEnji Cooper   FD_ZERO(&wset);
602*8ac5aef8SEnji Cooper   FD_SET(cap_fd, &wset);
603*8ac5aef8SEnji Cooper   ret = select(cap_fd+1, &rset, &wset, NULL, &tv);
604*8ac5aef8SEnji Cooper   if (cap_rights_is_set(&rights, CAP_EVENT)) {
605*8ac5aef8SEnji Cooper     EXPECT_OK(ret);
606*8ac5aef8SEnji Cooper   } else {
607*8ac5aef8SEnji Cooper     EXPECT_NOTCAPABLE(ret);
608*8ac5aef8SEnji Cooper   }
609*8ac5aef8SEnji Cooper 
610*8ac5aef8SEnji Cooper   // TODO(FreeBSD): kqueue
611*8ac5aef8SEnji Cooper 
612*8ac5aef8SEnji Cooper   EXPECT_OK(close(cap_fd));
613*8ac5aef8SEnji Cooper }
614*8ac5aef8SEnji Cooper 
615*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Operations, TmpFile("cap_fd_operations")) {
616*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_fd_operations"), O_RDWR | O_CREAT, 0644);
617*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
618*8ac5aef8SEnji Cooper   if (fd < 0) return;
619*8ac5aef8SEnji Cooper 
620*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
621*8ac5aef8SEnji Cooper 
622*8ac5aef8SEnji Cooper   // Try a variety of different combinations of rights - a full
623*8ac5aef8SEnji Cooper   // enumeration is too large (2^N with N~30+) to perform.
624*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_READ);
625*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PREAD);
626*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_WRITE);
627*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PWRITE);
628*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_READ, CAP_WRITE);
629*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PREAD, CAP_PWRITE);
630*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_SEEK);
631*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHFLAGS);
632*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_IOCTL);
633*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSTAT);
634*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP);
635*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_R);
636*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_W);
637*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_X);
638*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RW);
639*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RX);
640*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_WX);
641*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RWX);
642*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCNTL);
643*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EVENT);
644*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSYNC);
645*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHOWN);
646*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHMOD);
647*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FTRUNCATE);
648*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FLOCK);
649*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSTATFS);
650*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FPATHCONF);
651*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FUTIMES);
652*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_GET);
653*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_SET);
654*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_DELETE);
655*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_CHECK);
656*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_GET);
657*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_SET);
658*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_DELETE);
659*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_LIST);
660*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MAC_GET);
661*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MAC_SET);
662*8ac5aef8SEnji Cooper 
663*8ac5aef8SEnji Cooper   // Socket-specific.
664*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_GETPEERNAME);
665*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_GETSOCKNAME);
666*8ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACCEPT);
667*8ac5aef8SEnji Cooper 
668*8ac5aef8SEnji Cooper   close(fd);
669*8ac5aef8SEnji Cooper }
670*8ac5aef8SEnji Cooper 
671*8ac5aef8SEnji Cooper #define TRY_DIR_OPS(dfd, ...) do {       \
672*8ac5aef8SEnji Cooper   cap_rights_t rights;                   \
673*8ac5aef8SEnji Cooper   cap_rights_init(&rights, __VA_ARGS__); \
674*8ac5aef8SEnji Cooper   TryDirOps((dfd), rights);              \
675*8ac5aef8SEnji Cooper } while (0)
676*8ac5aef8SEnji Cooper 
677*8ac5aef8SEnji Cooper static void TryDirOps(int dirfd, cap_rights_t rights) {
678*8ac5aef8SEnji Cooper   cap_rights_t erights;
679*8ac5aef8SEnji Cooper   int dfd_cap = dup(dirfd);
680*8ac5aef8SEnji Cooper   EXPECT_OK(dfd_cap);
681*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(dfd_cap, &rights));
682*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(dfd_cap, &erights));
683*8ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
684*8ac5aef8SEnji Cooper 
685*8ac5aef8SEnji Cooper   int rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDONLY, 0600);
686*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_LOOKUP);
687*8ac5aef8SEnji Cooper   if (rc >= 0) {
688*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
689*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
690*8ac5aef8SEnji Cooper   }
691*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY | O_APPEND, 0600);
692*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_WRITE, CAP_LOOKUP);
693*8ac5aef8SEnji Cooper   if (rc >= 0) {
694*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
695*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
696*8ac5aef8SEnji Cooper   }
697*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR | O_APPEND, 0600);
698*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
699*8ac5aef8SEnji Cooper   if (rc >= 0) {
700*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
701*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
702*8ac5aef8SEnji Cooper   }
703*8ac5aef8SEnji Cooper 
704*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_faccess", O_CREAT, 0600);
705*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
706*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
707*8ac5aef8SEnji Cooper   rc = faccessat(dfd_cap, "cap_faccess", F_OK, 0);
708*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSTAT, CAP_LOOKUP);
709*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_faccess", 0));
710*8ac5aef8SEnji Cooper 
711*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fsync", O_CREAT, 0600);
712*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
713*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
714*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDONLY);
715*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
716*8ac5aef8SEnji Cooper   if (rc >= 0) {
717*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
718*8ac5aef8SEnji Cooper   }
719*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY | O_APPEND);
720*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
721*8ac5aef8SEnji Cooper   if (rc >= 0) {
722*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
723*8ac5aef8SEnji Cooper   }
724*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR | O_APPEND);
725*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
726*8ac5aef8SEnji Cooper   if (rc >= 0) {
727*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
728*8ac5aef8SEnji Cooper   }
729*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDONLY);
730*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
731*8ac5aef8SEnji Cooper   if (rc >= 0) {
732*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
733*8ac5aef8SEnji Cooper   }
734*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY | O_APPEND);
735*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
736*8ac5aef8SEnji Cooper   if (rc >= 0) {
737*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
738*8ac5aef8SEnji Cooper   }
739*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR | O_APPEND);
740*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
741*8ac5aef8SEnji Cooper   if (rc >= 0) {
742*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
743*8ac5aef8SEnji Cooper   }
744*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fsync", 0));
745*8ac5aef8SEnji Cooper 
746*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_ftruncate", O_CREAT, 0600);
747*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
748*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
749*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDONLY);
750*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_READ, CAP_LOOKUP);
751*8ac5aef8SEnji Cooper   if (rc >= 0) {
752*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
753*8ac5aef8SEnji Cooper   }
754*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_WRONLY);
755*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_WRITE, CAP_LOOKUP);
756*8ac5aef8SEnji Cooper   if (rc >= 0) {
757*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
758*8ac5aef8SEnji Cooper   }
759*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDWR);
760*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
761*8ac5aef8SEnji Cooper   if (rc >= 0) {
762*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
763*8ac5aef8SEnji Cooper   }
764*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_ftruncate", 0));
765*8ac5aef8SEnji Cooper 
766*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY, 0600);
767*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
768*8ac5aef8SEnji Cooper   if (rc >= 0) {
769*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
770*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
771*8ac5aef8SEnji Cooper   }
772*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR, 0600);
773*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
774*8ac5aef8SEnji Cooper   if (rc >= 0) {
775*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
776*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
777*8ac5aef8SEnji Cooper   }
778*8ac5aef8SEnji Cooper 
779*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fsync", O_CREAT, 0600);
780*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
781*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
782*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY);
783*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
784*8ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
785*8ac5aef8SEnji Cooper   if (rc >= 0) {
786*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
787*8ac5aef8SEnji Cooper   }
788*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR);
789*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
790*8ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
791*8ac5aef8SEnji Cooper   if (rc >= 0) {
792*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
793*8ac5aef8SEnji Cooper   }
794*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY);
795*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
796*8ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
797*8ac5aef8SEnji Cooper   if (rc >= 0) {
798*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
799*8ac5aef8SEnji Cooper   }
800*8ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR);
801*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
802*8ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
803*8ac5aef8SEnji Cooper   if (rc >= 0) {
804*8ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
805*8ac5aef8SEnji Cooper   }
806*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fsync", 0));
807*8ac5aef8SEnji Cooper 
808*8ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGSAT
809*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_chflagsat", O_CREAT, 0600);
810*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
811*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
812*8ac5aef8SEnji Cooper   rc = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0);
813*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CHFLAGSAT, CAP_LOOKUP);
814*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_chflagsat", 0));
815*8ac5aef8SEnji Cooper #endif
816*8ac5aef8SEnji Cooper 
817*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fchownat", O_CREAT, 0600);
818*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
819*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
820*8ac5aef8SEnji Cooper   rc = fchownat(dfd_cap, "cap_fchownat", -1, -1, 0);
821*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCHOWN, CAP_LOOKUP);
822*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fchownat", 0));
823*8ac5aef8SEnji Cooper 
824*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fchmodat", O_CREAT, 0600);
825*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
826*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
827*8ac5aef8SEnji Cooper   rc = fchmodat(dfd_cap, "cap_fchmodat", 0600, 0);
828*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCHMOD, CAP_LOOKUP);
829*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fchmodat", 0));
830*8ac5aef8SEnji Cooper 
831*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fstatat", O_CREAT, 0600);
832*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
833*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
834*8ac5aef8SEnji Cooper   struct stat sb;
835*8ac5aef8SEnji Cooper   rc = fstatat(dfd_cap, "cap_fstatat", &sb, 0);
836*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSTAT, CAP_LOOKUP);
837*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fstatat", 0));
838*8ac5aef8SEnji Cooper 
839*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_futimesat", O_CREAT, 0600);
840*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
841*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
842*8ac5aef8SEnji Cooper   rc = futimesat(dfd_cap, "cap_futimesat", NULL);
843*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FUTIMES, CAP_LOOKUP);
844*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_futimesat", 0));
845*8ac5aef8SEnji Cooper 
846*8ac5aef8SEnji Cooper   // For linkat(2), need:
847*8ac5aef8SEnji Cooper   //  - CAP_LINKAT_SOURCE on source
848*8ac5aef8SEnji Cooper   //  - CAP_LINKAT_TARGET on destination.
849*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_linkat_src", O_CREAT, 0600);
850*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
851*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
852*8ac5aef8SEnji Cooper 
853*8ac5aef8SEnji Cooper   rc = linkat(dirfd, "cap_linkat_src", dfd_cap, "cap_linkat_dst", 0);
854*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_LINKAT_TARGET);
855*8ac5aef8SEnji Cooper   if (rc >= 0) {
856*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_linkat_dst", 0));
857*8ac5aef8SEnji Cooper   }
858*8ac5aef8SEnji Cooper 
859*8ac5aef8SEnji Cooper   rc = linkat(dfd_cap, "cap_linkat_src", dirfd, "cap_linkat_dst", 0);
860*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_LINKAT_SOURCE);
861*8ac5aef8SEnji Cooper   if (rc >= 0) {
862*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_linkat_dst", 0));
863*8ac5aef8SEnji Cooper   }
864*8ac5aef8SEnji Cooper 
865*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_linkat_src", 0));
866*8ac5aef8SEnji Cooper 
867*8ac5aef8SEnji Cooper   rc = mkdirat(dfd_cap, "cap_mkdirat", 0700);
868*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_MKDIRAT, CAP_LOOKUP);
869*8ac5aef8SEnji Cooper   if (rc >= 0) {
870*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR));
871*8ac5aef8SEnji Cooper   }
872*8ac5aef8SEnji Cooper 
873*8ac5aef8SEnji Cooper #ifdef HAVE_MKFIFOAT
874*8ac5aef8SEnji Cooper   rc = mkfifoat(dfd_cap, "cap_mkfifoat", 0600);
875*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_MKFIFOAT, CAP_LOOKUP);
876*8ac5aef8SEnji Cooper   if (rc >= 0) {
877*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_mkfifoat", 0));
878*8ac5aef8SEnji Cooper   }
879*8ac5aef8SEnji Cooper #endif
880*8ac5aef8SEnji Cooper 
881*8ac5aef8SEnji Cooper   if (getuid() == 0) {
882*8ac5aef8SEnji Cooper     rc = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0);
883*8ac5aef8SEnji Cooper     CHECK_RIGHT_RESULT(rc, rights, CAP_MKNODAT, CAP_LOOKUP);
884*8ac5aef8SEnji Cooper     if (rc >= 0) {
885*8ac5aef8SEnji Cooper       EXPECT_OK(unlinkat(dirfd, "cap_mknodat", 0));
886*8ac5aef8SEnji Cooper     }
887*8ac5aef8SEnji Cooper   }
888*8ac5aef8SEnji Cooper 
889*8ac5aef8SEnji Cooper   // For renameat(2), need:
890*8ac5aef8SEnji Cooper   //  - CAP_RENAMEAT_SOURCE on source
891*8ac5aef8SEnji Cooper   //  - CAP_RENAMEAT_TARGET on destination.
892*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_renameat_src", O_CREAT, 0600);
893*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
894*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
895*8ac5aef8SEnji Cooper 
896*8ac5aef8SEnji Cooper   rc = renameat(dirfd, "cap_renameat_src", dfd_cap, "cap_renameat_dst");
897*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_RENAMEAT_TARGET);
898*8ac5aef8SEnji Cooper   if (rc >= 0) {
899*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_dst", 0));
900*8ac5aef8SEnji Cooper   } else {
901*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_src", 0));
902*8ac5aef8SEnji Cooper   }
903*8ac5aef8SEnji Cooper 
904*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_renameat_src", O_CREAT, 0600);
905*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
906*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
907*8ac5aef8SEnji Cooper 
908*8ac5aef8SEnji Cooper   rc = renameat(dfd_cap, "cap_renameat_src", dirfd, "cap_renameat_dst");
909*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_RENAMEAT_SOURCE);
910*8ac5aef8SEnji Cooper 
911*8ac5aef8SEnji Cooper   if (rc >= 0) {
912*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_dst", 0));
913*8ac5aef8SEnji Cooper   } else {
914*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_src", 0));
915*8ac5aef8SEnji Cooper   }
916*8ac5aef8SEnji Cooper 
917*8ac5aef8SEnji Cooper   rc = symlinkat("test", dfd_cap, "cap_symlinkat");
918*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_SYMLINKAT, CAP_LOOKUP);
919*8ac5aef8SEnji Cooper   if (rc >= 0) {
920*8ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_symlinkat", 0));
921*8ac5aef8SEnji Cooper   }
922*8ac5aef8SEnji Cooper 
923*8ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_unlinkat", O_CREAT, 0600);
924*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
925*8ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
926*8ac5aef8SEnji Cooper   rc = unlinkat(dfd_cap, "cap_unlinkat", 0);
927*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_UNLINKAT, CAP_LOOKUP);
928*8ac5aef8SEnji Cooper   unlinkat(dirfd, "cap_unlinkat", 0);
929*8ac5aef8SEnji Cooper   EXPECT_OK(mkdirat(dirfd, "cap_unlinkat", 0700));
930*8ac5aef8SEnji Cooper   rc = unlinkat(dfd_cap, "cap_unlinkat", AT_REMOVEDIR);
931*8ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_UNLINKAT, CAP_LOOKUP);
932*8ac5aef8SEnji Cooper   unlinkat(dirfd, "cap_unlinkat", AT_REMOVEDIR);
933*8ac5aef8SEnji Cooper 
934*8ac5aef8SEnji Cooper   EXPECT_OK(close(dfd_cap));
935*8ac5aef8SEnji Cooper }
936*8ac5aef8SEnji Cooper 
937*8ac5aef8SEnji Cooper void DirOperationsTest(int extra) {
938*8ac5aef8SEnji Cooper   int rc = mkdir(TmpFile("cap_dirops"), 0755);
939*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
940*8ac5aef8SEnji Cooper   if (rc < 0 && errno != EEXIST) return;
941*8ac5aef8SEnji Cooper   int dfd = open(TmpFile("cap_dirops"), O_RDONLY | O_DIRECTORY | extra);
942*8ac5aef8SEnji Cooper   EXPECT_OK(dfd);
943*8ac5aef8SEnji Cooper   int tmpfd = open(tmpdir.c_str(), O_RDONLY | O_DIRECTORY);
944*8ac5aef8SEnji Cooper   EXPECT_OK(tmpfd);
945*8ac5aef8SEnji Cooper 
946*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
947*8ac5aef8SEnji Cooper 
948*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_LINKAT_SOURCE);
949*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_LINKAT_TARGET);
950*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_READ, CAP_LOOKUP);
951*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_WRITE, CAP_LOOKUP);
952*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
953*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
954*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
955*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
956*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_READ, CAP_LOOKUP);
957*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_WRITE, CAP_LOOKUP);
958*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
959*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FCHOWN, CAP_LOOKUP);
960*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FCHMOD, CAP_LOOKUP);
961*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSTAT, CAP_LOOKUP);
962*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FUTIMES, CAP_LOOKUP);
963*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKDIRAT, CAP_LOOKUP);
964*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKFIFOAT, CAP_LOOKUP);
965*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKNODAT, CAP_LOOKUP);
966*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_SYMLINKAT, CAP_LOOKUP);
967*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_UNLINKAT, CAP_LOOKUP);
968*8ac5aef8SEnji Cooper   // Rename needs CAP_RENAMEAT_SOURCE on source directory and
969*8ac5aef8SEnji Cooper   // CAP_RENAMEAT_TARGET on destination directory.
970*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_RENAMEAT_SOURCE, CAP_UNLINKAT, CAP_LOOKUP);
971*8ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_RENAMEAT_TARGET, CAP_UNLINKAT, CAP_LOOKUP);
972*8ac5aef8SEnji Cooper 
973*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(tmpfd, "cap_dirops", AT_REMOVEDIR));
974*8ac5aef8SEnji Cooper   EXPECT_OK(close(tmpfd));
975*8ac5aef8SEnji Cooper   EXPECT_OK(close(dfd));
976*8ac5aef8SEnji Cooper }
977*8ac5aef8SEnji Cooper 
978*8ac5aef8SEnji Cooper FORK_TEST(Capability, DirOperations) {
979*8ac5aef8SEnji Cooper   DirOperationsTest(0);
980*8ac5aef8SEnji Cooper }
981*8ac5aef8SEnji Cooper 
982*8ac5aef8SEnji Cooper #ifdef O_PATH
983*8ac5aef8SEnji Cooper FORK_TEST(Capability, PathDirOperations) {
984*8ac5aef8SEnji Cooper   // Make the dfd in the test a path-only file descriptor.
985*8ac5aef8SEnji Cooper   DirOperationsTest(O_PATH);
986*8ac5aef8SEnji Cooper }
987*8ac5aef8SEnji Cooper #endif
988*8ac5aef8SEnji Cooper 
989*8ac5aef8SEnji Cooper static void TryReadWrite(int cap_fd) {
990*8ac5aef8SEnji Cooper   char buffer[64];
991*8ac5aef8SEnji Cooper   EXPECT_OK(read(cap_fd, buffer, sizeof(buffer)));
992*8ac5aef8SEnji Cooper   int rc = write(cap_fd, "", 0);
993*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, rc);
994*8ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);
995*8ac5aef8SEnji Cooper }
996*8ac5aef8SEnji Cooper 
997*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
998*8ac5aef8SEnji Cooper   int sock_fds[2];
999*8ac5aef8SEnji Cooper   EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds));
1000*8ac5aef8SEnji Cooper 
1001*8ac5aef8SEnji Cooper   struct msghdr mh;
1002*8ac5aef8SEnji Cooper   mh.msg_name = NULL;  // No address needed
1003*8ac5aef8SEnji Cooper   mh.msg_namelen = 0;
1004*8ac5aef8SEnji Cooper   char buffer1[1024];
1005*8ac5aef8SEnji Cooper   struct iovec iov[1];
1006*8ac5aef8SEnji Cooper   iov[0].iov_base = buffer1;
1007*8ac5aef8SEnji Cooper   iov[0].iov_len = sizeof(buffer1);
1008*8ac5aef8SEnji Cooper   mh.msg_iov = iov;
1009*8ac5aef8SEnji Cooper   mh.msg_iovlen = 1;
1010*8ac5aef8SEnji Cooper   char buffer2[1024];
1011*8ac5aef8SEnji Cooper   mh.msg_control = buffer2;
1012*8ac5aef8SEnji Cooper   mh.msg_controllen = sizeof(buffer2);
1013*8ac5aef8SEnji Cooper   struct cmsghdr *cmptr;
1014*8ac5aef8SEnji Cooper 
1015*8ac5aef8SEnji Cooper   cap_rights_t r_rs;
1016*8ac5aef8SEnji Cooper   cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
1017*8ac5aef8SEnji Cooper 
1018*8ac5aef8SEnji Cooper   pid_t child = fork();
1019*8ac5aef8SEnji Cooper   if (child == 0) {
1020*8ac5aef8SEnji Cooper     // Child: enter cap mode
1021*8ac5aef8SEnji Cooper     EXPECT_OK(cap_enter());
1022*8ac5aef8SEnji Cooper 
1023*8ac5aef8SEnji Cooper     // Child: wait to receive FD over socket
1024*8ac5aef8SEnji Cooper     int rc = recvmsg(sock_fds[0], &mh, 0);
1025*8ac5aef8SEnji Cooper     EXPECT_OK(rc);
1026*8ac5aef8SEnji Cooper     EXPECT_LE(CMSG_LEN(sizeof(int)), mh.msg_controllen);
1027*8ac5aef8SEnji Cooper     cmptr = CMSG_FIRSTHDR(&mh);
1028*8ac5aef8SEnji Cooper     int cap_fd = *(int*)CMSG_DATA(cmptr);
1029*8ac5aef8SEnji Cooper     EXPECT_EQ(CMSG_LEN(sizeof(int)), cmptr->cmsg_len);
1030*8ac5aef8SEnji Cooper     cmptr = CMSG_NXTHDR(&mh, cmptr);
1031*8ac5aef8SEnji Cooper     EXPECT_TRUE(cmptr == NULL);
1032*8ac5aef8SEnji Cooper 
1033*8ac5aef8SEnji Cooper     // Child: confirm we can do the right operations on the capability
1034*8ac5aef8SEnji Cooper     cap_rights_t rights;
1035*8ac5aef8SEnji Cooper     EXPECT_OK(cap_rights_get(cap_fd, &rights));
1036*8ac5aef8SEnji Cooper     EXPECT_RIGHTS_EQ(&r_rs, &rights);
1037*8ac5aef8SEnji Cooper     TryReadWrite(cap_fd);
1038*8ac5aef8SEnji Cooper 
1039*8ac5aef8SEnji Cooper     // Child: wait for a normal read
1040*8ac5aef8SEnji Cooper     int val;
1041*8ac5aef8SEnji Cooper     read(sock_fds[0], &val, sizeof(val));
1042*8ac5aef8SEnji Cooper     exit(0);
1043*8ac5aef8SEnji Cooper   }
1044*8ac5aef8SEnji Cooper 
1045*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_fd_transfer"), O_RDWR | O_CREAT, 0644);
1046*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
1047*8ac5aef8SEnji Cooper   if (fd < 0) return;
1048*8ac5aef8SEnji Cooper   int cap_fd = dup(fd);
1049*8ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
1050*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rs));
1051*8ac5aef8SEnji Cooper 
1052*8ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
1053*8ac5aef8SEnji Cooper 
1054*8ac5aef8SEnji Cooper   // Confirm we can do the right operations on the capability
1055*8ac5aef8SEnji Cooper   TryReadWrite(cap_fd);
1056*8ac5aef8SEnji Cooper 
1057*8ac5aef8SEnji Cooper   // Send the file descriptor over the pipe to the sub-process
1058*8ac5aef8SEnji Cooper   mh.msg_controllen = CMSG_LEN(sizeof(int));
1059*8ac5aef8SEnji Cooper   cmptr = CMSG_FIRSTHDR(&mh);
1060*8ac5aef8SEnji Cooper   cmptr->cmsg_level = SOL_SOCKET;
1061*8ac5aef8SEnji Cooper   cmptr->cmsg_type = SCM_RIGHTS;
1062*8ac5aef8SEnji Cooper   cmptr->cmsg_len = CMSG_LEN(sizeof(int));
1063*8ac5aef8SEnji Cooper   *(int *)CMSG_DATA(cmptr) = cap_fd;
1064*8ac5aef8SEnji Cooper   buffer1[0] = 0;
1065*8ac5aef8SEnji Cooper   iov[0].iov_len = 1;
1066*8ac5aef8SEnji Cooper   sleep(3);
1067*8ac5aef8SEnji Cooper   int rc = sendmsg(sock_fds[1], &mh, 0);
1068*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
1069*8ac5aef8SEnji Cooper 
1070*8ac5aef8SEnji Cooper   sleep(1);  // Ensure subprocess runs
1071*8ac5aef8SEnji Cooper   int zero = 0;
1072*8ac5aef8SEnji Cooper   write(sock_fds[1], &zero, sizeof(zero));
1073*8ac5aef8SEnji Cooper }
1074*8ac5aef8SEnji Cooper 
1075*8ac5aef8SEnji Cooper TEST(Capability, SyscallAt) {
1076*8ac5aef8SEnji Cooper   int rc = mkdir(TmpFile("cap_at_topdir"), 0755);
1077*8ac5aef8SEnji Cooper   EXPECT_OK(rc);
1078*8ac5aef8SEnji Cooper   if (rc < 0 && errno != EEXIST) return;
1079*8ac5aef8SEnji Cooper 
1080*8ac5aef8SEnji Cooper   cap_rights_t r_all;
1081*8ac5aef8SEnji Cooper   cap_rights_init(&r_all, CAP_READ, CAP_LOOKUP, CAP_MKNODAT, CAP_UNLINKAT, CAP_MKDIRAT, CAP_MKFIFOAT);
1082*8ac5aef8SEnji Cooper   cap_rights_t r_no_unlink;
1083*8ac5aef8SEnji Cooper   cap_rights_init(&r_no_unlink, CAP_READ, CAP_LOOKUP, CAP_MKDIRAT, CAP_MKFIFOAT);
1084*8ac5aef8SEnji Cooper   cap_rights_t r_no_mkdir;
1085*8ac5aef8SEnji Cooper   cap_rights_init(&r_no_mkdir, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKFIFOAT);
1086*8ac5aef8SEnji Cooper   cap_rights_t r_no_mkfifo;
1087*8ac5aef8SEnji Cooper   cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
1088*8ac5aef8SEnji Cooper   cap_rights_t r_no_mknod;
1089*8ac5aef8SEnji Cooper   cap_rights_init(&r_no_mknod, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
1090*8ac5aef8SEnji Cooper   cap_rights_t r_create;
1091*8ac5aef8SEnji Cooper   cap_rights_init(&r_create, CAP_READ, CAP_LOOKUP, CAP_CREATE);
1092*8ac5aef8SEnji Cooper   cap_rights_t r_bind;
1093*8ac5aef8SEnji Cooper   cap_rights_init(&r_bind, CAP_READ, CAP_LOOKUP, CAP_BIND);
1094*8ac5aef8SEnji Cooper 
1095*8ac5aef8SEnji Cooper   int dfd = open(TmpFile("cap_at_topdir"), O_RDONLY);
1096*8ac5aef8SEnji Cooper   EXPECT_OK(dfd);
1097*8ac5aef8SEnji Cooper   int cap_dfd_all = dup(dfd);
1098*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_all);
1099*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_all, &r_all));
1100*8ac5aef8SEnji Cooper   int cap_dfd_no_unlink = dup(dfd);
1101*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_unlink);
1102*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_unlink, &r_no_unlink));
1103*8ac5aef8SEnji Cooper   int cap_dfd_no_mkdir = dup(dfd);
1104*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_mkdir);
1105*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_mkdir, &r_no_mkdir));
1106*8ac5aef8SEnji Cooper   int cap_dfd_no_mkfifo = dup(dfd);
1107*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_mkfifo);
1108*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_no_mkfifo));
1109*8ac5aef8SEnji Cooper   int cap_dfd_no_mknod = dup(dfd);
1110*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_mknod);
1111*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_mknod, &r_no_mknod));
1112*8ac5aef8SEnji Cooper   int cap_dfd_create = dup(dfd);
1113*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_create);
1114*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_create, &r_create));
1115*8ac5aef8SEnji Cooper   int cap_dfd_bind = dup(dfd);
1116*8ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_bind);
1117*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_bind, &r_bind));
1118*8ac5aef8SEnji Cooper 
1119*8ac5aef8SEnji Cooper   // Need CAP_MKDIRAT to mkdirat(2).
1120*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mkdirat(cap_dfd_no_mkdir, "cap_subdir", 0755));
1121*8ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir/cap_subdir"));
1122*8ac5aef8SEnji Cooper   EXPECT_OK(mkdirat(cap_dfd_all, "cap_subdir", 0755));
1123*8ac5aef8SEnji Cooper 
1124*8ac5aef8SEnji Cooper   // Need CAP_UNLINKAT to unlinkat(dfd, name, AT_REMOVEDIR).
1125*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(unlinkat(cap_dfd_no_unlink, "cap_subdir", AT_REMOVEDIR));
1126*8ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(cap_dfd_all, "cap_subdir", AT_REMOVEDIR));
1127*8ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir/cap_subdir"));
1128*8ac5aef8SEnji Cooper 
1129*8ac5aef8SEnji Cooper   // Need CAP_MKFIFOAT to mkfifoat(2).
1130*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mkfifoat(cap_dfd_no_mkfifo, "cap_fifo", 0755));
1131*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_fifo"));
1132*8ac5aef8SEnji Cooper   EXPECT_OK(mkfifoat(cap_dfd_all, "cap_fifo", 0755));
1133*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_fifo"));
1134*8ac5aef8SEnji Cooper 
1135*8ac5aef8SEnji Cooper #ifdef HAVE_MKNOD_REG
1136*8ac5aef8SEnji Cooper   // Need CAP_CREATE to create a regular file with mknodat(2).
1137*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_regular", S_IFREG|0755, 0));
1138*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_regular"));
1139*8ac5aef8SEnji Cooper   EXPECT_OK(mknodat(cap_dfd_create, "cap_regular", S_IFREG|0755, 0));
1140*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_regular"));
1141*8ac5aef8SEnji Cooper #endif
1142*8ac5aef8SEnji Cooper 
1143*8ac5aef8SEnji Cooper #ifdef HAVE_MKNOD_SOCKET
1144*8ac5aef8SEnji Cooper   // Need CAP_BIND to create a UNIX domain socket with mknodat(2).
1145*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_socket", S_IFSOCK|0755, 0));
1146*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_socket"));
1147*8ac5aef8SEnji Cooper   EXPECT_OK(mknodat(cap_dfd_bind, "cap_socket", S_IFSOCK|0755, 0));
1148*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_socket"));
1149*8ac5aef8SEnji Cooper #endif
1150*8ac5aef8SEnji Cooper 
1151*8ac5aef8SEnji Cooper   if (getuid() == 0) {
1152*8ac5aef8SEnji Cooper     // Need CAP_MKNODAT to mknodat(2) a device
1153*8ac5aef8SEnji Cooper     EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mknod, "cap_device", S_IFCHR|0755, makedev(99, 123)));
1154*8ac5aef8SEnji Cooper     unlink(TmpFile("cap_at_topdir/cap_device"));
1155*8ac5aef8SEnji Cooper     EXPECT_OK(mknodat(cap_dfd_all, "cap_device", S_IFCHR|0755, makedev(99, 123)));
1156*8ac5aef8SEnji Cooper     unlink(TmpFile("cap_at_topdir/cap_device"));
1157*8ac5aef8SEnji Cooper 
1158*8ac5aef8SEnji Cooper     // Need CAP_MKFIFOAT to mknodat(2) for a FIFO.
1159*8ac5aef8SEnji Cooper     EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mkfifo, "cap_fifo", S_IFIFO|0755, 0));
1160*8ac5aef8SEnji Cooper     unlink(TmpFile("cap_at_topdir/cap_fifo"));
1161*8ac5aef8SEnji Cooper     EXPECT_OK(mknodat(cap_dfd_all, "cap_fifo", S_IFIFO|0755, 0));
1162*8ac5aef8SEnji Cooper     unlink(TmpFile("cap_at_topdir/cap_fifo"));
1163*8ac5aef8SEnji Cooper   } else {
1164*8ac5aef8SEnji Cooper     TEST_SKIPPED("requires root (partial)");
1165*8ac5aef8SEnji Cooper   }
1166*8ac5aef8SEnji Cooper 
1167*8ac5aef8SEnji Cooper   close(cap_dfd_all);
1168*8ac5aef8SEnji Cooper   close(cap_dfd_no_mknod);
1169*8ac5aef8SEnji Cooper   close(cap_dfd_no_mkfifo);
1170*8ac5aef8SEnji Cooper   close(cap_dfd_no_mkdir);
1171*8ac5aef8SEnji Cooper   close(cap_dfd_no_unlink);
1172*8ac5aef8SEnji Cooper   close(cap_dfd_create);
1173*8ac5aef8SEnji Cooper   close(cap_dfd_bind);
1174*8ac5aef8SEnji Cooper   close(dfd);
1175*8ac5aef8SEnji Cooper 
1176*8ac5aef8SEnji Cooper   // Tidy up.
1177*8ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir"));
1178*8ac5aef8SEnji Cooper }
1179*8ac5aef8SEnji Cooper 
1180*8ac5aef8SEnji Cooper FORK_TEST_ON(Capability, ExtendedAttributes, TmpFile("cap_extattr")) {
1181*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_extattr"), O_RDONLY|O_CREAT, 0644);
1182*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
1183*8ac5aef8SEnji Cooper 
1184*8ac5aef8SEnji Cooper   char buffer[1024];
1185*8ac5aef8SEnji Cooper   int rc = fgetxattr_(fd, "user.capsicumtest", buffer, sizeof(buffer));
1186*8ac5aef8SEnji Cooper   if (rc < 0 && errno == ENOTSUP) {
1187*8ac5aef8SEnji Cooper     // Need user_xattr mount option for non-root users on Linux
1188*8ac5aef8SEnji Cooper     TEST_SKIPPED("/tmp doesn't support extended attributes");
1189*8ac5aef8SEnji Cooper     close(fd);
1190*8ac5aef8SEnji Cooper     return;
1191*8ac5aef8SEnji Cooper   }
1192*8ac5aef8SEnji Cooper 
1193*8ac5aef8SEnji Cooper   cap_rights_t r_rws;
1194*8ac5aef8SEnji Cooper   cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
1195*8ac5aef8SEnji Cooper   cap_rights_t r_xlist;
1196*8ac5aef8SEnji Cooper   cap_rights_init(&r_xlist, CAP_EXTATTR_LIST);
1197*8ac5aef8SEnji Cooper   cap_rights_t r_xget;
1198*8ac5aef8SEnji Cooper   cap_rights_init(&r_xget, CAP_EXTATTR_GET);
1199*8ac5aef8SEnji Cooper   cap_rights_t r_xset;
1200*8ac5aef8SEnji Cooper   cap_rights_init(&r_xset, CAP_EXTATTR_SET);
1201*8ac5aef8SEnji Cooper   cap_rights_t r_xdel;
1202*8ac5aef8SEnji Cooper   cap_rights_init(&r_xdel, CAP_EXTATTR_DELETE);
1203*8ac5aef8SEnji Cooper 
1204*8ac5aef8SEnji Cooper   int cap = dup(fd);
1205*8ac5aef8SEnji Cooper   EXPECT_OK(cap);
1206*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap, &r_rws));
1207*8ac5aef8SEnji Cooper   int cap_xlist = dup(fd);
1208*8ac5aef8SEnji Cooper   EXPECT_OK(cap_xlist);
1209*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xlist, &r_xlist));
1210*8ac5aef8SEnji Cooper   int cap_xget = dup(fd);
1211*8ac5aef8SEnji Cooper   EXPECT_OK(cap_xget);
1212*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xget, &r_xget));
1213*8ac5aef8SEnji Cooper   int cap_xset = dup(fd);
1214*8ac5aef8SEnji Cooper   EXPECT_OK(cap_xset);
1215*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xset, &r_xset));
1216*8ac5aef8SEnji Cooper   int cap_xdel = dup(fd);
1217*8ac5aef8SEnji Cooper   EXPECT_OK(cap_xdel);
1218*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xdel, &r_xdel));
1219*8ac5aef8SEnji Cooper 
1220*8ac5aef8SEnji Cooper   const char* value = "capsicum";
1221*8ac5aef8SEnji Cooper   int len = strlen(value) + 1;
1222*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap, "user.capsicumtest", value, len, 0));
1223*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xlist, "user.capsicumtest", value, len, 0));
1224*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xget, "user.capsicumtest", value, len, 0));
1225*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xdel, "user.capsicumtest", value, len, 0));
1226*8ac5aef8SEnji Cooper   EXPECT_OK(fsetxattr_(cap_xset, "user.capsicumtest", value, len, 0));
1227*8ac5aef8SEnji Cooper 
1228*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap, buffer, sizeof(buffer)));
1229*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xget, buffer, sizeof(buffer)));
1230*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xset, buffer, sizeof(buffer)));
1231*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xdel, buffer, sizeof(buffer)));
1232*8ac5aef8SEnji Cooper   EXPECT_OK(flistxattr_(cap_xlist, buffer, sizeof(buffer)));
1233*8ac5aef8SEnji Cooper 
1234*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap, "user.capsicumtest", buffer, sizeof(buffer)));
1235*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xlist, "user.capsicumtest", buffer, sizeof(buffer)));
1236*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xset, "user.capsicumtest", buffer, sizeof(buffer)));
1237*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xdel, "user.capsicumtest", buffer, sizeof(buffer)));
1238*8ac5aef8SEnji Cooper   EXPECT_OK(fgetxattr_(cap_xget, "user.capsicumtest", buffer, sizeof(buffer)));
1239*8ac5aef8SEnji Cooper 
1240*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap, "user.capsicumtest"));
1241*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xlist, "user.capsicumtest"));
1242*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xget, "user.capsicumtest"));
1243*8ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xset, "user.capsicumtest"));
1244*8ac5aef8SEnji Cooper   EXPECT_OK(fremovexattr_(cap_xdel, "user.capsicumtest"));
1245*8ac5aef8SEnji Cooper 
1246*8ac5aef8SEnji Cooper   close(cap_xdel);
1247*8ac5aef8SEnji Cooper   close(cap_xset);
1248*8ac5aef8SEnji Cooper   close(cap_xget);
1249*8ac5aef8SEnji Cooper   close(cap_xlist);
1250*8ac5aef8SEnji Cooper   close(cap);
1251*8ac5aef8SEnji Cooper   close(fd);
1252*8ac5aef8SEnji Cooper }
1253*8ac5aef8SEnji Cooper 
1254*8ac5aef8SEnji Cooper TEST(Capability, PipeUnseekable) {
1255*8ac5aef8SEnji Cooper   int fds[2];
1256*8ac5aef8SEnji Cooper   EXPECT_OK(pipe(fds));
1257*8ac5aef8SEnji Cooper 
1258*8ac5aef8SEnji Cooper   // Some programs detect pipes by calling seek() and getting ESPIPE.
1259*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
1260*8ac5aef8SEnji Cooper   EXPECT_EQ(ESPIPE, errno);
1261*8ac5aef8SEnji Cooper 
1262*8ac5aef8SEnji Cooper   cap_rights_t rights;
1263*8ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK);
1264*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fds[0], &rights));
1265*8ac5aef8SEnji Cooper 
1266*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
1267*8ac5aef8SEnji Cooper   EXPECT_EQ(ESPIPE, errno);
1268*8ac5aef8SEnji Cooper 
1269*8ac5aef8SEnji Cooper   // Remove CAP_SEEK and see if ENOTCAPABLE trumps ESPIPE.
1270*8ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE);
1271*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fds[0], &rights));
1272*8ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
1273*8ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);
1274*8ac5aef8SEnji Cooper   // TODO(drysdale): in practical terms it might be nice if ESPIPE trumped ENOTCAPABLE.
1275*8ac5aef8SEnji Cooper   // EXPECT_EQ(ESPIPE, errno);
1276*8ac5aef8SEnji Cooper 
1277*8ac5aef8SEnji Cooper   close(fds[0]);
1278*8ac5aef8SEnji Cooper   close(fds[1]);
1279*8ac5aef8SEnji Cooper }
1280*8ac5aef8SEnji Cooper 
1281*8ac5aef8SEnji Cooper TEST(Capability, NoBypassDAC) {
1282*8ac5aef8SEnji Cooper   REQUIRE_ROOT();
1283*8ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_root_owned"), O_RDONLY|O_CREAT, 0644);
1284*8ac5aef8SEnji Cooper   EXPECT_OK(fd);
1285*8ac5aef8SEnji Cooper   cap_rights_t rights;
1286*8ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FCHMOD, CAP_FSTAT);
1287*8ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fd, &rights));
1288*8ac5aef8SEnji Cooper 
1289*8ac5aef8SEnji Cooper   pid_t child = fork();
1290*8ac5aef8SEnji Cooper   if (child == 0) {
1291*8ac5aef8SEnji Cooper     // Child: change uid to a lesser being
1292*8ac5aef8SEnji Cooper     setuid(other_uid);
1293*8ac5aef8SEnji Cooper     // Attempt to fchmod the file, and fail.
1294*8ac5aef8SEnji Cooper     // Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy.
1295*8ac5aef8SEnji Cooper     int rc = fchmod(fd, 0666);
1296*8ac5aef8SEnji Cooper     EXPECT_EQ(-1, rc);
1297*8ac5aef8SEnji Cooper     EXPECT_EQ(EPERM, errno);
1298*8ac5aef8SEnji Cooper     exit(HasFailure());
1299*8ac5aef8SEnji Cooper   }
1300*8ac5aef8SEnji Cooper   int status;
1301*8ac5aef8SEnji Cooper   EXPECT_EQ(child, waitpid(child, &status, 0));
1302*8ac5aef8SEnji Cooper   EXPECT_TRUE(WIFEXITED(status)) << "0x" << std::hex << status;
1303*8ac5aef8SEnji Cooper   EXPECT_EQ(0, WEXITSTATUS(status));
1304*8ac5aef8SEnji Cooper   struct stat info;
1305*8ac5aef8SEnji Cooper   EXPECT_OK(fstat(fd, &info));
1306*8ac5aef8SEnji Cooper   EXPECT_EQ((mode_t)(S_IFREG|0644), info.st_mode);
1307*8ac5aef8SEnji Cooper   close(fd);
1308*8ac5aef8SEnji Cooper   unlink(TmpFile("cap_root_owned"));
1309*8ac5aef8SEnji Cooper }
1310