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