xref: /freebsd/contrib/capsicum-test/capability-fd.cc (revision a7100ae23aca07976926bd8d50223c45149f65d6)
18ac5aef8SEnji Cooper #include <stdio.h>
28ac5aef8SEnji Cooper #include <unistd.h>
38ac5aef8SEnji Cooper #include <sys/file.h>
48ac5aef8SEnji Cooper #include <sys/types.h>
58ac5aef8SEnji Cooper #include <sys/wait.h>
68ac5aef8SEnji Cooper #include <sys/stat.h>
78ac5aef8SEnji Cooper #include <sys/mman.h>
88ac5aef8SEnji Cooper #include <sys/select.h>
98ac5aef8SEnji Cooper #include <sys/socket.h>
108ac5aef8SEnji Cooper #include <sys/time.h>
118ac5aef8SEnji Cooper #include <errno.h>
128ac5aef8SEnji Cooper #include <fcntl.h>
138ac5aef8SEnji Cooper #include <poll.h>
148ac5aef8SEnji Cooper #include <stdint.h>
158ac5aef8SEnji Cooper 
168ac5aef8SEnji Cooper #include "capsicum.h"
178ac5aef8SEnji Cooper #include "syscalls.h"
188ac5aef8SEnji Cooper #include "capsicum-test.h"
198ac5aef8SEnji Cooper 
208ac5aef8SEnji Cooper /* Utilities for printing rights information */
218ac5aef8SEnji Cooper /* Written in C style to allow for: */
228ac5aef8SEnji Cooper /* TODO(drysdale): migrate these to somewhere in libcaprights/ */
238ac5aef8SEnji Cooper #define RIGHTS_INFO(RR) { (RR), #RR}
248ac5aef8SEnji Cooper typedef struct {
258ac5aef8SEnji Cooper   uint64_t right;
268ac5aef8SEnji Cooper   const char* name;
278ac5aef8SEnji Cooper } right_info;
288ac5aef8SEnji Cooper static right_info known_rights[] = {
298ac5aef8SEnji Cooper   /* Rights that are common to all versions of Capsicum */
308ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_READ),
318ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_WRITE),
328ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEEK_TELL),
338ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEEK),
348ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PREAD),
358ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PWRITE),
368ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP),
378ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_R),
388ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_W),
398ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_X),
408ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RW),
418ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RX),
428ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_WX),
438ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MMAP_RWX),
448ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CREATE),
458ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FEXECVE),
468ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSYNC),
478ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FTRUNCATE),
488ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LOOKUP),
498ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHDIR),
508ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHFLAGS),
518ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CHFLAGSAT),
528ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHMOD),
538ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHMODAT),
548ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHOWN),
558ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCHOWNAT),
568ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FCNTL),
578ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FLOCK),
588ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FPATHCONF),
598ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSCK),
608ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTAT),
618ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTATAT),
628ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSTATFS),
638ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FUTIMES),
648ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FUTIMESAT),
658ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKDIRAT),
668ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKFIFOAT),
678ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MKNODAT),
688ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RENAMEAT_SOURCE),
698ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SYMLINKAT),
708ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_UNLINKAT),
718ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACCEPT),
728ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BIND),
738ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CONNECT),
748ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETPEERNAME),
758ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETSOCKNAME),
768ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_GETSOCKOPT),
778ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LISTEN),
788ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PEELOFF),
798ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RECV),
808ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEND),
818ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SETSOCKOPT),
828ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SHUTDOWN),
838ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BINDAT),
848ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_CONNECTAT),
858ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_SOURCE),
868ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_RENAMEAT_TARGET),
878ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SOCK_CLIENT),
888ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SOCK_SERVER),
898ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MAC_GET),
908ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_MAC_SET),
918ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_GETVALUE),
928ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_POST),
938ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SEM_WAIT),
948ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EVENT),
958ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE_EVENT),
968ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_IOCTL),
978ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_TTYHOOK),
988ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDWAIT),
998ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDGETPID),
1008ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDKILL),
1018ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_DELETE),
1028ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_GET),
1038ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_LIST),
1048ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EXTATTR_SET),
1058ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_CHECK),
1068ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_DELETE),
1078ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_GET),
1088ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_ACL_SET),
1098ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE_CHANGE),
1108ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_KQUEUE),
1118ac5aef8SEnji Cooper   /* Rights that are only present in some version or some OS, and so are #ifdef'ed */
1128ac5aef8SEnji Cooper   /* LINKAT got split */
1138ac5aef8SEnji Cooper #ifdef CAP_LINKAT
1148ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT),
1158ac5aef8SEnji Cooper #endif
1168ac5aef8SEnji Cooper #ifdef CAP_LINKAT_SOURCE
1178ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_SOURCE),
1188ac5aef8SEnji Cooper #endif
1198ac5aef8SEnji Cooper #ifdef CAP_LINKAT_TARGET
1208ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_LINKAT_TARGET),
1218ac5aef8SEnji Cooper #endif
1228ac5aef8SEnji Cooper   /* Linux aliased some FD operations for pdgetpid/pdkill */
1238ac5aef8SEnji Cooper #ifdef CAP_PDGETPID_FREEBSD
1248ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDGETPID_FREEBSD),
1258ac5aef8SEnji Cooper #endif
1268ac5aef8SEnji Cooper #ifdef CAP_PDKILL_FREEBSD
1278ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PDKILL_FREEBSD),
1288ac5aef8SEnji Cooper #endif
1298ac5aef8SEnji Cooper   /* Linux-specific rights */
1308ac5aef8SEnji Cooper #ifdef CAP_FSIGNAL
1318ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_FSIGNAL),
1328ac5aef8SEnji Cooper #endif
1338ac5aef8SEnji Cooper #ifdef CAP_EPOLL_CTL
1348ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_EPOLL_CTL),
1358ac5aef8SEnji Cooper #endif
1368ac5aef8SEnji Cooper #ifdef CAP_NOTIFY
1378ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_NOTIFY),
1388ac5aef8SEnji Cooper #endif
1398ac5aef8SEnji Cooper #ifdef CAP_SETNS
1408ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_SETNS),
1418ac5aef8SEnji Cooper #endif
1428ac5aef8SEnji Cooper #ifdef CAP_PERFMON
1438ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_PERFMON),
1448ac5aef8SEnji Cooper #endif
1458ac5aef8SEnji Cooper #ifdef CAP_BPF
1468ac5aef8SEnji Cooper   RIGHTS_INFO(CAP_BPF),
1478ac5aef8SEnji Cooper #endif
1488ac5aef8SEnji Cooper   /* Rights in later versions of FreeBSD (>10.0) */
1498ac5aef8SEnji Cooper };
1508ac5aef8SEnji Cooper 
ShowCapRights(FILE * out,int fd)1518ac5aef8SEnji Cooper void ShowCapRights(FILE *out, int fd) {
1528ac5aef8SEnji Cooper   size_t ii;
1538ac5aef8SEnji Cooper   bool first = true;
1548ac5aef8SEnji Cooper   cap_rights_t rights;
1558ac5aef8SEnji Cooper   CAP_SET_NONE(&rights);
1568ac5aef8SEnji Cooper   if (cap_rights_get(fd, &rights) < 0) {
1578ac5aef8SEnji Cooper     fprintf(out, "Failed to get rights for fd %d: errno %d\n", fd, errno);
1588ac5aef8SEnji Cooper     return;
1598ac5aef8SEnji Cooper   }
1608ac5aef8SEnji Cooper 
1618ac5aef8SEnji Cooper   /* First print out all known rights */
1628ac5aef8SEnji Cooper   size_t num_known = (sizeof(known_rights)/sizeof(known_rights[0]));
1638ac5aef8SEnji Cooper   for (ii = 0; ii < num_known; ii++) {
1648ac5aef8SEnji Cooper     if (cap_rights_is_set(&rights, known_rights[ii].right)) {
1658ac5aef8SEnji Cooper       if (!first) fprintf(out, ",");
1668ac5aef8SEnji Cooper       first = false;
1678ac5aef8SEnji Cooper       fprintf(out, "%s", known_rights[ii].name);
1688ac5aef8SEnji Cooper     }
1698ac5aef8SEnji Cooper   }
1708ac5aef8SEnji Cooper   /* Now repeat the loop, clearing rights we know of; this needs to be
1718ac5aef8SEnji Cooper    * a separate loop because some named rights overlap.
1728ac5aef8SEnji Cooper    */
1738ac5aef8SEnji Cooper   for (ii = 0; ii < num_known; ii++) {
1748ac5aef8SEnji Cooper     cap_rights_clear(&rights, known_rights[ii].right);
1758ac5aef8SEnji Cooper   }
1768ac5aef8SEnji Cooper   /* The following relies on the internal structure of cap_rights_t to
1778ac5aef8SEnji Cooper    * try to show rights we don't know about. */
1788ac5aef8SEnji Cooper   for (ii = 0; ii < (size_t)CAPARSIZE(&rights); ii++) {
1798ac5aef8SEnji Cooper     uint64_t bits = (rights.cr_rights[0] & 0x01ffffffffffffffULL);
1808ac5aef8SEnji Cooper     if (bits != 0) {
1818ac5aef8SEnji Cooper       uint64_t which = 1;
1828ac5aef8SEnji Cooper       for (which = 1; which < 0x0200000000000000 ; which <<= 1) {
1838ac5aef8SEnji Cooper         if (bits & which) {
1848ac5aef8SEnji Cooper           if (!first) fprintf(out, ",");
1858ac5aef8SEnji Cooper           fprintf(out, "CAP_RIGHT(%d, 0x%016llxULL)", (int)ii, (long long unsigned)which);
1868ac5aef8SEnji Cooper         }
1878ac5aef8SEnji Cooper       }
1888ac5aef8SEnji Cooper     }
1898ac5aef8SEnji Cooper   }
1908ac5aef8SEnji Cooper   fprintf(out, "\n");
1918ac5aef8SEnji Cooper }
1928ac5aef8SEnji Cooper 
ShowAllCapRights(FILE * out)1938ac5aef8SEnji Cooper void ShowAllCapRights(FILE *out) {
1948ac5aef8SEnji Cooper   int fd;
1958ac5aef8SEnji Cooper   struct rlimit limits;
1968ac5aef8SEnji Cooper   if (getrlimit(RLIMIT_NOFILE, &limits) != 0) {
1978ac5aef8SEnji Cooper     fprintf(out, "Failed to getrlimit for max FDs: errno %d\n", errno);
1988ac5aef8SEnji Cooper     return;
1998ac5aef8SEnji Cooper   }
2008ac5aef8SEnji Cooper   for (fd = 0; fd < (int)limits.rlim_cur; fd++) {
2018ac5aef8SEnji Cooper     if (fcntl(fd, F_GETFD, 0) != 0) {
2028ac5aef8SEnji Cooper       continue;
2038ac5aef8SEnji Cooper     }
2048ac5aef8SEnji Cooper     fprintf(out, "fd %d: ", fd);
2058ac5aef8SEnji Cooper     ShowCapRights(out, fd);
2068ac5aef8SEnji Cooper   }
2078ac5aef8SEnji Cooper }
2088ac5aef8SEnji Cooper 
FORK_TEST(Capability,CapNew)2098ac5aef8SEnji Cooper FORK_TEST(Capability, CapNew) {
2108ac5aef8SEnji Cooper   cap_rights_t r_rws;
2118ac5aef8SEnji Cooper   cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
2128ac5aef8SEnji Cooper   cap_rights_t r_all;
2138ac5aef8SEnji Cooper   CAP_SET_ALL(&r_all);
2148ac5aef8SEnji Cooper 
2158ac5aef8SEnji Cooper   int cap_fd = dup(STDOUT_FILENO);
2168ac5aef8SEnji Cooper   cap_rights_t rights;
2178ac5aef8SEnji Cooper   CAP_SET_NONE(&rights);
2188ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &rights));
2198ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_all, &rights);
2208ac5aef8SEnji Cooper 
2218ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
2228ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rws));
2238ac5aef8SEnji Cooper   if (cap_fd < 0) return;
2248ac5aef8SEnji Cooper   int rc = write(cap_fd, "OK!\n", 4);
2258ac5aef8SEnji Cooper   EXPECT_OK(rc);
2268ac5aef8SEnji Cooper   EXPECT_EQ(4, rc);
2278ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &rights));
2288ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
2298ac5aef8SEnji Cooper 
2308ac5aef8SEnji Cooper   // dup/dup2 should preserve rights.
2318ac5aef8SEnji Cooper   int cap_dup = dup(cap_fd);
2328ac5aef8SEnji Cooper   EXPECT_OK(cap_dup);
2338ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
2348ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
2358ac5aef8SEnji Cooper   close(cap_dup);
2368ac5aef8SEnji Cooper   EXPECT_OK(dup2(cap_fd, cap_dup));
2378ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
2388ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
2398ac5aef8SEnji Cooper   close(cap_dup);
2408ac5aef8SEnji Cooper #ifdef HAVE_DUP3
2418ac5aef8SEnji Cooper   EXPECT_OK(dup3(cap_fd, cap_dup, 0));
2428ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_dup, &rights));
2438ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rws, &rights);
2448ac5aef8SEnji Cooper   close(cap_dup);
2458ac5aef8SEnji Cooper #endif
2468ac5aef8SEnji Cooper 
2478ac5aef8SEnji Cooper   // Try to get a disjoint set of rights in a sub-capability.
2488ac5aef8SEnji Cooper   cap_rights_t r_rs;
2498ac5aef8SEnji Cooper   cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
2508ac5aef8SEnji Cooper   cap_rights_t r_rsmapchmod;
2518ac5aef8SEnji Cooper   cap_rights_init(&r_rsmapchmod, CAP_READ, CAP_SEEK, CAP_MMAP, CAP_FCHMOD);
2528ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
2538ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
2548ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(cap_rights_limit(cap_cap_fd, &r_rsmapchmod));
2558ac5aef8SEnji Cooper 
2568ac5aef8SEnji Cooper   // Dump rights info to stderr (mostly to ensure that Show[All]CapRights()
2578ac5aef8SEnji Cooper   // is working.
2588ac5aef8SEnji Cooper   ShowAllCapRights(stderr);
2598ac5aef8SEnji Cooper 
2608ac5aef8SEnji Cooper   EXPECT_OK(close(cap_fd));
2618ac5aef8SEnji Cooper }
2628ac5aef8SEnji Cooper 
FORK_TEST(Capability,CapEnter)2638ac5aef8SEnji Cooper FORK_TEST(Capability, CapEnter) {
2648ac5aef8SEnji Cooper   EXPECT_EQ(0, cap_enter());
2658ac5aef8SEnji Cooper }
2668ac5aef8SEnji Cooper 
FORK_TEST(Capability,BasicInterception)2678ac5aef8SEnji Cooper FORK_TEST(Capability, BasicInterception) {
2688ac5aef8SEnji Cooper   cap_rights_t r_0;
2698ac5aef8SEnji Cooper   cap_rights_init(&r_0, 0);
2708ac5aef8SEnji Cooper   int cap_fd = dup(1);
2718ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
2728ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_0));
2738ac5aef8SEnji Cooper 
2748ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
2758ac5aef8SEnji Cooper 
2768ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode
2778ac5aef8SEnji Cooper 
2788ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
2798ac5aef8SEnji Cooper 
2808ac5aef8SEnji Cooper   // Create a new capability which does have write permission
2818ac5aef8SEnji Cooper   cap_rights_t r_ws;
2828ac5aef8SEnji Cooper   cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
2838ac5aef8SEnji Cooper   int cap_fd2 = dup(1);
2848ac5aef8SEnji Cooper   EXPECT_OK(cap_fd2);
2858ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd2, &r_ws));
2868ac5aef8SEnji Cooper   EXPECT_OK(write(cap_fd2, "", 0));
2878ac5aef8SEnji Cooper 
2888ac5aef8SEnji Cooper   // Tidy up.
2898ac5aef8SEnji Cooper   if (cap_fd >= 0) close(cap_fd);
2908ac5aef8SEnji Cooper   if (cap_fd2 >= 0) close(cap_fd2);
2918ac5aef8SEnji Cooper }
2928ac5aef8SEnji Cooper 
2938ac5aef8SEnji Cooper FORK_TEST_ON(Capability, OpenAtDirectoryTraversal, TmpFile("cap_openat_testfile")) {
2948ac5aef8SEnji Cooper   int dir = open(tmpdir.c_str(), O_RDONLY);
2958ac5aef8SEnji Cooper   EXPECT_OK(dir);
2968ac5aef8SEnji Cooper 
2978ac5aef8SEnji Cooper   cap_enter();
2988ac5aef8SEnji Cooper 
2998ac5aef8SEnji Cooper   int file = openat(dir, "cap_openat_testfile", O_RDONLY|O_CREAT, 0644);
3008ac5aef8SEnji Cooper   EXPECT_OK(file);
3018ac5aef8SEnji Cooper 
3028ac5aef8SEnji Cooper   // Test that we are confined to /tmp, and cannot
3038ac5aef8SEnji Cooper   // escape using absolute paths or ../.
3048ac5aef8SEnji Cooper   int new_file = openat(dir, "../dev/null", O_RDONLY);
3058ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
3068ac5aef8SEnji Cooper 
3078ac5aef8SEnji Cooper   new_file = openat(dir, "..", O_RDONLY);
3088ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
3098ac5aef8SEnji Cooper 
3108ac5aef8SEnji Cooper   new_file = openat(dir, "/dev/null", O_RDONLY);
3118ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
3128ac5aef8SEnji Cooper 
3138ac5aef8SEnji Cooper   new_file = openat(dir, "/", O_RDONLY);
3148ac5aef8SEnji Cooper   EXPECT_EQ(-1, new_file);
3158ac5aef8SEnji Cooper 
3168ac5aef8SEnji Cooper   // Tidy up.
3178ac5aef8SEnji Cooper   close(file);
3188ac5aef8SEnji Cooper   close(dir);
3198ac5aef8SEnji Cooper }
3208ac5aef8SEnji Cooper 
3218ac5aef8SEnji Cooper FORK_TEST_ON(Capability, FileInSync, TmpFile("cap_file_sync")) {
3228ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_file_sync"), O_RDWR|O_CREAT, 0644);
3238ac5aef8SEnji Cooper   EXPECT_OK(fd);
3248ac5aef8SEnji Cooper   const char* message = "Hello capability world";
3258ac5aef8SEnji Cooper   EXPECT_OK(write(fd, message, strlen(message)));
3268ac5aef8SEnji Cooper 
3278ac5aef8SEnji Cooper   cap_rights_t r_rsstat;
3288ac5aef8SEnji Cooper   cap_rights_init(&r_rsstat, CAP_READ, CAP_SEEK, CAP_FSTAT);
3298ac5aef8SEnji Cooper 
3308ac5aef8SEnji Cooper   int cap_fd = dup(fd);
3318ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
3328ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rsstat));
3338ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
3348ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
3358ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_cap_fd, &r_rsstat));
3368ac5aef8SEnji Cooper 
3378ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
3388ac5aef8SEnji Cooper 
3398ac5aef8SEnji Cooper   // Changes to one file descriptor affect the others.
3408ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(fd, 1, SEEK_SET));
3418ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(fd, 0, SEEK_CUR));
3428ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(cap_fd, 0, SEEK_CUR));
3438ac5aef8SEnji Cooper   EXPECT_EQ(1, lseek(cap_cap_fd, 0, SEEK_CUR));
3448ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_fd, 3, SEEK_SET));
3458ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(fd, 0, SEEK_CUR));
3468ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_fd, 0, SEEK_CUR));
3478ac5aef8SEnji Cooper   EXPECT_EQ(3, lseek(cap_cap_fd, 0, SEEK_CUR));
3488ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_cap_fd, 5, SEEK_SET));
3498ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(fd, 0, SEEK_CUR));
3508ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_fd, 0, SEEK_CUR));
3518ac5aef8SEnji Cooper   EXPECT_EQ(5, lseek(cap_cap_fd, 0, SEEK_CUR));
3528ac5aef8SEnji Cooper 
3538ac5aef8SEnji Cooper   close(cap_cap_fd);
3548ac5aef8SEnji Cooper   close(cap_fd);
3558ac5aef8SEnji Cooper   close(fd);
3568ac5aef8SEnji Cooper }
3578ac5aef8SEnji Cooper 
3588ac5aef8SEnji Cooper // Create a capability on /tmp that does not allow CAP_WRITE,
3598ac5aef8SEnji Cooper // and check that this restriction is inherited through openat().
3608ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Inheritance, TmpFile("cap_openat_write_testfile")) {
3618ac5aef8SEnji Cooper   int dir = open(tmpdir.c_str(), O_RDONLY);
3628ac5aef8SEnji Cooper   EXPECT_OK(dir);
3638ac5aef8SEnji Cooper 
3648ac5aef8SEnji Cooper   cap_rights_t r_rl;
3658ac5aef8SEnji Cooper   cap_rights_init(&r_rl, CAP_READ, CAP_LOOKUP);
3668ac5aef8SEnji Cooper 
3678ac5aef8SEnji Cooper   int cap_dir = dup(dir);
3688ac5aef8SEnji Cooper   EXPECT_OK(cap_dir);
3698ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dir, &r_rl));
3708ac5aef8SEnji Cooper 
3718ac5aef8SEnji Cooper   const char *filename = "cap_openat_write_testfile";
3728ac5aef8SEnji Cooper   int file = openat(dir, filename, O_WRONLY|O_CREAT, 0644);
3738ac5aef8SEnji Cooper   EXPECT_OK(file);
3748ac5aef8SEnji Cooper   EXPECT_EQ(5, write(file, "TEST\n", 5));
3758ac5aef8SEnji Cooper   if (file >= 0) close(file);
3768ac5aef8SEnji Cooper 
3778ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());
3788ac5aef8SEnji Cooper   file = openat(cap_dir, filename, O_RDONLY);
3798ac5aef8SEnji Cooper   EXPECT_OK(file);
3808ac5aef8SEnji Cooper 
3818ac5aef8SEnji Cooper   cap_rights_t rights;
3828ac5aef8SEnji Cooper   cap_rights_init(&rights, 0);
3838ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(file, &rights));
3848ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&r_rl, &rights);
3858ac5aef8SEnji Cooper   if (file >= 0) close(file);
3868ac5aef8SEnji Cooper 
3878ac5aef8SEnji Cooper   file = openat(cap_dir, filename, O_WRONLY|O_APPEND);
3888ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(file);
3898ac5aef8SEnji Cooper   if (file > 0) close(file);
3908ac5aef8SEnji Cooper 
3918ac5aef8SEnji Cooper   if (dir > 0) close(dir);
3928ac5aef8SEnji Cooper   if (cap_dir > 0) close(cap_dir);
3938ac5aef8SEnji Cooper }
3948ac5aef8SEnji Cooper 
3958ac5aef8SEnji Cooper 
3968ac5aef8SEnji Cooper // Ensure that, if the capability had enough rights for the system call to
3978ac5aef8SEnji Cooper // pass, then it did. Otherwise, ensure that the errno is ENOTCAPABLE;
3988ac5aef8SEnji Cooper // capability restrictions should kick in before any other error logic.
3998ac5aef8SEnji Cooper #define CHECK_RIGHT_RESULT(result, rights, ...) do {    \
4008ac5aef8SEnji Cooper   cap_rights_t rights_needed;                           \
4018ac5aef8SEnji Cooper   cap_rights_init(&rights_needed, __VA_ARGS__);         \
4028ac5aef8SEnji Cooper   if (cap_rights_contains(&rights, &rights_needed)) {   \
4038ac5aef8SEnji Cooper     EXPECT_OK(result) << std::endl                      \
4048ac5aef8SEnji Cooper                       << " need: " << rights_needed     \
4058ac5aef8SEnji Cooper                       << std::endl                      \
4068ac5aef8SEnji Cooper                       << " got:  " << rights;           \
4078ac5aef8SEnji Cooper   } else {                                              \
4088ac5aef8SEnji Cooper     EXPECT_EQ(-1, result) << " need: " << rights_needed \
4098ac5aef8SEnji Cooper                           << std::endl                  \
4108ac5aef8SEnji Cooper                           << " got:  "<< rights;        \
4118ac5aef8SEnji Cooper     EXPECT_EQ(ENOTCAPABLE, errno);                      \
4128ac5aef8SEnji Cooper   }                                                     \
4138ac5aef8SEnji Cooper } while (0)
4148ac5aef8SEnji Cooper 
4158ac5aef8SEnji Cooper #define EXPECT_MMAP_NOTCAPABLE(result) do {         \
4168ac5aef8SEnji Cooper   void *rv = result;                                \
4178ac5aef8SEnji Cooper   EXPECT_EQ(MAP_FAILED, rv);                        \
4188ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);                    \
4198ac5aef8SEnji Cooper   if (rv != MAP_FAILED) munmap(rv, getpagesize());  \
4208ac5aef8SEnji Cooper } while (0)
4218ac5aef8SEnji Cooper 
4228ac5aef8SEnji Cooper #define EXPECT_MMAP_OK(result) do {                     \
4238ac5aef8SEnji Cooper   void *rv = result;                                    \
4248ac5aef8SEnji Cooper   EXPECT_NE(MAP_FAILED, rv) << " with errno " << errno; \
4258ac5aef8SEnji Cooper   if (rv != MAP_FAILED) munmap(rv, getpagesize());      \
4268ac5aef8SEnji Cooper } while (0)
4278ac5aef8SEnji Cooper 
4288ac5aef8SEnji Cooper 
4298ac5aef8SEnji Cooper // As above, but for the special mmap() case: unmap after successful mmap().
4308ac5aef8SEnji Cooper #define CHECK_RIGHT_MMAP_RESULT(result, rights, ...) do { \
4318ac5aef8SEnji Cooper   cap_rights_t rights_needed;                             \
4328ac5aef8SEnji Cooper   cap_rights_init(&rights_needed, __VA_ARGS__);           \
4338ac5aef8SEnji Cooper   if (cap_rights_contains(&rights, &rights_needed)) {     \
4348ac5aef8SEnji Cooper     EXPECT_MMAP_OK(result);                               \
4358ac5aef8SEnji Cooper   } else {                                                \
4368ac5aef8SEnji Cooper     EXPECT_MMAP_NOTCAPABLE(result);                       \
4378ac5aef8SEnji Cooper   }                                                       \
4388ac5aef8SEnji Cooper } while (0)
4398ac5aef8SEnji Cooper 
4408ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Mmap, TmpFile("cap_mmap_operations")) {
4418ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_mmap_operations"), O_RDWR | O_CREAT, 0644);
4428ac5aef8SEnji Cooper   EXPECT_OK(fd);
4438ac5aef8SEnji Cooper   if (fd < 0) return;
4448ac5aef8SEnji Cooper 
4458ac5aef8SEnji Cooper   cap_rights_t r_0;
4468ac5aef8SEnji Cooper   cap_rights_init(&r_0, 0);
4478ac5aef8SEnji Cooper   cap_rights_t r_mmap;
4488ac5aef8SEnji Cooper   cap_rights_init(&r_mmap, CAP_MMAP);
4498ac5aef8SEnji Cooper   cap_rights_t r_r;
4508ac5aef8SEnji Cooper   cap_rights_init(&r_r, CAP_PREAD);
4518ac5aef8SEnji Cooper   cap_rights_t r_rmmap;
4528ac5aef8SEnji Cooper   cap_rights_init(&r_rmmap, CAP_PREAD, CAP_MMAP);
4538ac5aef8SEnji Cooper 
4548ac5aef8SEnji Cooper   // If we're missing a capability, it will fail.
4558ac5aef8SEnji Cooper   int cap_none = dup(fd);
4568ac5aef8SEnji Cooper   EXPECT_OK(cap_none);
4578ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_none, &r_0));
4588ac5aef8SEnji Cooper   int cap_mmap = dup(fd);
4598ac5aef8SEnji Cooper   EXPECT_OK(cap_mmap);
4608ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_mmap, &r_mmap));
4618ac5aef8SEnji Cooper   int cap_read = dup(fd);
4628ac5aef8SEnji Cooper   EXPECT_OK(cap_read);
4638ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_read, &r_r));
4648ac5aef8SEnji Cooper   int cap_both = dup(fd);
4658ac5aef8SEnji Cooper   EXPECT_OK(cap_both);
4668ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_both, &r_rmmap));
4678ac5aef8SEnji Cooper 
4688ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
4698ac5aef8SEnji Cooper 
4708ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_none, 0));
4718ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_mmap, 0));
4728ac5aef8SEnji Cooper   EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_read, 0));
4738ac5aef8SEnji Cooper 
4748ac5aef8SEnji Cooper   EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_both, 0));
4758ac5aef8SEnji Cooper 
4768ac5aef8SEnji Cooper   // A call with MAP_ANONYMOUS should succeed without any capability requirements.
4778ac5aef8SEnji Cooper   EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
4788ac5aef8SEnji Cooper 
4798ac5aef8SEnji Cooper   EXPECT_OK(close(cap_both));
4808ac5aef8SEnji Cooper   EXPECT_OK(close(cap_read));
4818ac5aef8SEnji Cooper   EXPECT_OK(close(cap_mmap));
4828ac5aef8SEnji Cooper   EXPECT_OK(close(cap_none));
4838ac5aef8SEnji Cooper   EXPECT_OK(close(fd));
4848ac5aef8SEnji Cooper }
4858ac5aef8SEnji Cooper 
4868ac5aef8SEnji Cooper // Given a file descriptor, create a capability with specific rights and
4878ac5aef8SEnji Cooper // make sure only those rights work.
4888ac5aef8SEnji Cooper #define TRY_FILE_OPS(fd, ...) do {       \
489955a3f9aSAlex Richardson   SCOPED_TRACE(#__VA_ARGS__);            \
4908ac5aef8SEnji Cooper   cap_rights_t rights;                   \
4918ac5aef8SEnji Cooper   cap_rights_init(&rights, __VA_ARGS__); \
4928ac5aef8SEnji Cooper   TryFileOps((fd), rights);              \
4938ac5aef8SEnji Cooper } while (0)
4948ac5aef8SEnji Cooper 
TryFileOps(int fd,cap_rights_t rights)4958ac5aef8SEnji Cooper static void TryFileOps(int fd, cap_rights_t rights) {
4968ac5aef8SEnji Cooper   int cap_fd = dup(fd);
4978ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
4988ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &rights));
4998ac5aef8SEnji Cooper   if (cap_fd < 0) return;
5008ac5aef8SEnji Cooper   cap_rights_t erights;
5018ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_fd, &erights));
5028ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
5038ac5aef8SEnji Cooper 
5048ac5aef8SEnji Cooper   // Check creation of a capability from a capability.
5058ac5aef8SEnji Cooper   int cap_cap_fd = dup(cap_fd);
5068ac5aef8SEnji Cooper   EXPECT_OK(cap_cap_fd);
5078ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_cap_fd, &rights));
5088ac5aef8SEnji Cooper   EXPECT_NE(cap_fd, cap_cap_fd);
5098ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(cap_cap_fd, &erights));
5108ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
5118ac5aef8SEnji Cooper   close(cap_cap_fd);
5128ac5aef8SEnji Cooper 
5138ac5aef8SEnji Cooper   char ch;
5148ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(read(cap_fd, &ch, sizeof(ch)), rights, CAP_READ, CAP_SEEK_ASWAS);
5158ac5aef8SEnji Cooper 
5168ac5aef8SEnji Cooper   ssize_t len1 = pread(cap_fd, &ch, sizeof(ch), 0);
5178ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(len1, rights, CAP_PREAD);
5188ac5aef8SEnji Cooper   ssize_t len2 = pread(cap_fd, &ch, sizeof(ch), 0);
5198ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(len2, rights, CAP_PREAD);
5208ac5aef8SEnji Cooper   EXPECT_EQ(len1, len2);
5218ac5aef8SEnji Cooper 
5228ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(write(cap_fd, &ch, sizeof(ch)), rights, CAP_WRITE, CAP_SEEK_ASWAS);
5238ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(pwrite(cap_fd, &ch, sizeof(ch), 0), rights, CAP_PWRITE);
5248ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(lseek(cap_fd, 0, SEEK_SET), rights, CAP_SEEK);
5258ac5aef8SEnji Cooper 
5268ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGS
5278ac5aef8SEnji Cooper   // Note: this is not expected to work over NFS.
5288ac5aef8SEnji Cooper   struct statfs sf;
5298ac5aef8SEnji Cooper   EXPECT_OK(fstatfs(fd, &sf));
5308ac5aef8SEnji Cooper   bool is_nfs = (strncmp("nfs", sf.f_fstypename, sizeof(sf.f_fstypename)) == 0);
5318ac5aef8SEnji Cooper   if (!is_nfs) {
5328ac5aef8SEnji Cooper     CHECK_RIGHT_RESULT(fchflags(cap_fd, UF_NODUMP), rights, CAP_FCHFLAGS);
5338ac5aef8SEnji Cooper   }
5348ac5aef8SEnji Cooper #endif
5358ac5aef8SEnji Cooper 
5368ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, cap_fd, 0),
5378ac5aef8SEnji Cooper                           rights, CAP_MMAP);
5388ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, cap_fd, 0),
5398ac5aef8SEnji Cooper                           rights, CAP_MMAP_R);
5408ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, cap_fd, 0),
5418ac5aef8SEnji Cooper                           rights, CAP_MMAP_W);
5428ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, cap_fd, 0),
5438ac5aef8SEnji Cooper                           rights, CAP_MMAP_X);
5448ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, cap_fd, 0),
5458ac5aef8SEnji Cooper                           rights, CAP_MMAP_RW);
5468ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED, cap_fd, 0),
5478ac5aef8SEnji Cooper                           rights, CAP_MMAP_RX);
5488ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED, cap_fd, 0),
5498ac5aef8SEnji Cooper                           rights, CAP_MMAP_WX);
5508ac5aef8SEnji Cooper   CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, cap_fd, 0),
5518ac5aef8SEnji Cooper                           rights, CAP_MMAP_RWX);
5528ac5aef8SEnji Cooper 
5538ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fsync(cap_fd), rights, CAP_FSYNC);
5548ac5aef8SEnji Cooper #ifdef HAVE_SYNC_FILE_RANGE
5558ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(sync_file_range(cap_fd, 0, 1, 0), rights, CAP_FSYNC, CAP_SEEK);
5568ac5aef8SEnji Cooper #endif
5578ac5aef8SEnji Cooper 
5588ac5aef8SEnji Cooper   int rc = fcntl(cap_fd, F_GETFL);
5598ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
5608ac5aef8SEnji Cooper   rc = fcntl(cap_fd, F_SETFL, rc);
5618ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
5628ac5aef8SEnji Cooper 
5638ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fchown(cap_fd, -1, -1), rights, CAP_FCHOWN);
5648ac5aef8SEnji Cooper 
5658ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fchmod(cap_fd, 0644), rights, CAP_FCHMOD);
5668ac5aef8SEnji Cooper 
5678ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_SH), rights, CAP_FLOCK);
5688ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_UN), rights, CAP_FLOCK);
5698ac5aef8SEnji Cooper 
5708ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(ftruncate(cap_fd, 0), rights, CAP_FTRUNCATE);
5718ac5aef8SEnji Cooper 
5728ac5aef8SEnji Cooper   struct stat sb;
5738ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fstat(cap_fd, &sb), rights, CAP_FSTAT);
5748ac5aef8SEnji Cooper 
5758ac5aef8SEnji Cooper   struct statfs cap_sf;
5768ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fstatfs(cap_fd, &cap_sf), rights, CAP_FSTATFS);
5778ac5aef8SEnji Cooper 
5788ac5aef8SEnji Cooper #ifdef HAVE_FPATHCONF
5798ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(fpathconf(cap_fd, _PC_NAME_MAX), rights, CAP_FPATHCONF);
5808ac5aef8SEnji Cooper #endif
5818ac5aef8SEnji Cooper 
5828ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(futimes(cap_fd, NULL), rights, CAP_FUTIMES);
5838ac5aef8SEnji Cooper 
5848ac5aef8SEnji Cooper   struct pollfd pollfd;
5858ac5aef8SEnji Cooper   pollfd.fd = cap_fd;
5868ac5aef8SEnji Cooper   pollfd.events = POLLIN | POLLERR | POLLHUP;
5878ac5aef8SEnji Cooper   pollfd.revents = 0;
5888ac5aef8SEnji Cooper   int ret = poll(&pollfd, 1, 0);
5898ac5aef8SEnji Cooper   if (cap_rights_is_set(&rights, CAP_EVENT)) {
5908ac5aef8SEnji Cooper     EXPECT_OK(ret);
5918ac5aef8SEnji Cooper   } else {
5928ac5aef8SEnji Cooper     EXPECT_NE(0, (pollfd.revents & POLLNVAL));
5938ac5aef8SEnji Cooper   }
5948ac5aef8SEnji Cooper 
5958ac5aef8SEnji Cooper   struct timeval tv;
5968ac5aef8SEnji Cooper   tv.tv_sec = 0;
5978ac5aef8SEnji Cooper   tv.tv_usec = 100;
5988ac5aef8SEnji Cooper   fd_set rset;
5998ac5aef8SEnji Cooper   FD_ZERO(&rset);
6008ac5aef8SEnji Cooper   FD_SET(cap_fd, &rset);
6018ac5aef8SEnji Cooper   fd_set wset;
6028ac5aef8SEnji Cooper   FD_ZERO(&wset);
6038ac5aef8SEnji Cooper   FD_SET(cap_fd, &wset);
6048ac5aef8SEnji Cooper   ret = select(cap_fd+1, &rset, &wset, NULL, &tv);
6058ac5aef8SEnji Cooper   if (cap_rights_is_set(&rights, CAP_EVENT)) {
6068ac5aef8SEnji Cooper     EXPECT_OK(ret);
6078ac5aef8SEnji Cooper   } else {
6088ac5aef8SEnji Cooper     EXPECT_NOTCAPABLE(ret);
6098ac5aef8SEnji Cooper   }
6108ac5aef8SEnji Cooper 
6118ac5aef8SEnji Cooper   // TODO(FreeBSD): kqueue
6128ac5aef8SEnji Cooper 
6138ac5aef8SEnji Cooper   EXPECT_OK(close(cap_fd));
6148ac5aef8SEnji Cooper }
6158ac5aef8SEnji Cooper 
6168ac5aef8SEnji Cooper FORK_TEST_ON(Capability, Operations, TmpFile("cap_fd_operations")) {
6178ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_fd_operations"), O_RDWR | O_CREAT, 0644);
6188ac5aef8SEnji Cooper   EXPECT_OK(fd);
6198ac5aef8SEnji Cooper   if (fd < 0) return;
6208ac5aef8SEnji Cooper 
6218ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
6228ac5aef8SEnji Cooper 
6238ac5aef8SEnji Cooper   // Try a variety of different combinations of rights - a full
6248ac5aef8SEnji Cooper   // enumeration is too large (2^N with N~30+) to perform.
6258ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_READ);
6268ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PREAD);
6278ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_WRITE);
6288ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PWRITE);
6298ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_READ, CAP_WRITE);
6308ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_PREAD, CAP_PWRITE);
6318ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_SEEK);
6328ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHFLAGS);
6338ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_IOCTL);
6348ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSTAT);
6358ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP);
6368ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_R);
6378ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_W);
6388ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_X);
6398ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RW);
6408ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RX);
6418ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_WX);
6428ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MMAP_RWX);
6438ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCNTL);
6448ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EVENT);
6458ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSYNC);
6468ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHOWN);
6478ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FCHMOD);
6488ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FTRUNCATE);
6498ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FLOCK);
6508ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FSTATFS);
6518ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FPATHCONF);
6528ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_FUTIMES);
6538ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_GET);
6548ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_SET);
6558ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_DELETE);
6568ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACL_CHECK);
6578ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_GET);
6588ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_SET);
6598ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_DELETE);
6608ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_EXTATTR_LIST);
6618ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MAC_GET);
6628ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_MAC_SET);
6638ac5aef8SEnji Cooper 
6648ac5aef8SEnji Cooper   // Socket-specific.
6658ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_GETPEERNAME);
6668ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_GETSOCKNAME);
6678ac5aef8SEnji Cooper   TRY_FILE_OPS(fd, CAP_ACCEPT);
6688ac5aef8SEnji Cooper 
6698ac5aef8SEnji Cooper   close(fd);
6708ac5aef8SEnji Cooper }
6718ac5aef8SEnji Cooper 
6728ac5aef8SEnji Cooper #define TRY_DIR_OPS(dfd, ...) do {       \
6738ac5aef8SEnji Cooper   cap_rights_t rights;                   \
6748ac5aef8SEnji Cooper   cap_rights_init(&rights, __VA_ARGS__); \
6758ac5aef8SEnji Cooper   TryDirOps((dfd), rights);              \
6768ac5aef8SEnji Cooper } while (0)
6778ac5aef8SEnji Cooper 
TryDirOps(int dirfd,cap_rights_t rights)6788ac5aef8SEnji Cooper static void TryDirOps(int dirfd, cap_rights_t rights) {
6798ac5aef8SEnji Cooper   cap_rights_t erights;
6808ac5aef8SEnji Cooper   int dfd_cap = dup(dirfd);
6818ac5aef8SEnji Cooper   EXPECT_OK(dfd_cap);
6828ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(dfd_cap, &rights));
6838ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_get(dfd_cap, &erights));
6848ac5aef8SEnji Cooper   EXPECT_RIGHTS_EQ(&rights, &erights);
6858ac5aef8SEnji Cooper 
6868ac5aef8SEnji Cooper   int rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDONLY, 0600);
6878ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_LOOKUP);
6888ac5aef8SEnji Cooper   if (rc >= 0) {
6898ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
6908ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
6918ac5aef8SEnji Cooper   }
6928ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY | O_APPEND, 0600);
6938ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_WRITE, CAP_LOOKUP);
6948ac5aef8SEnji Cooper   if (rc >= 0) {
6958ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
6968ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
6978ac5aef8SEnji Cooper   }
6988ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR | O_APPEND, 0600);
6998ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
7008ac5aef8SEnji Cooper   if (rc >= 0) {
7018ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7028ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
7038ac5aef8SEnji Cooper   }
7048ac5aef8SEnji Cooper 
7058ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_faccess", O_CREAT, 0600);
7068ac5aef8SEnji Cooper   EXPECT_OK(rc);
7078ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
7088ac5aef8SEnji Cooper   rc = faccessat(dfd_cap, "cap_faccess", F_OK, 0);
7098ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSTAT, CAP_LOOKUP);
7108ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_faccess", 0));
7118ac5aef8SEnji Cooper 
7128ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fsync", O_CREAT, 0600);
7138ac5aef8SEnji Cooper   EXPECT_OK(rc);
7148ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
7158ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDONLY);
7168ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
7178ac5aef8SEnji Cooper   if (rc >= 0) {
7188ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7198ac5aef8SEnji Cooper   }
7208ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY | O_APPEND);
7218ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
7228ac5aef8SEnji Cooper   if (rc >= 0) {
7238ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7248ac5aef8SEnji Cooper   }
7258ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR | O_APPEND);
7268ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
7278ac5aef8SEnji Cooper   if (rc >= 0) {
7288ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7298ac5aef8SEnji Cooper   }
7308ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDONLY);
7318ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
7328ac5aef8SEnji Cooper   if (rc >= 0) {
7338ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7348ac5aef8SEnji Cooper   }
7358ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY | O_APPEND);
7368ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
7378ac5aef8SEnji Cooper   if (rc >= 0) {
7388ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7398ac5aef8SEnji Cooper   }
7408ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR | O_APPEND);
7418ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
7428ac5aef8SEnji Cooper   if (rc >= 0) {
7438ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7448ac5aef8SEnji Cooper   }
7458ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fsync", 0));
7468ac5aef8SEnji Cooper 
7478ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_ftruncate", O_CREAT, 0600);
7488ac5aef8SEnji Cooper   EXPECT_OK(rc);
7498ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
7508ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDONLY);
7518ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_READ, CAP_LOOKUP);
7528ac5aef8SEnji Cooper   if (rc >= 0) {
7538ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7548ac5aef8SEnji Cooper   }
7558ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_WRONLY);
7568ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_WRITE, CAP_LOOKUP);
7578ac5aef8SEnji Cooper   if (rc >= 0) {
7588ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7598ac5aef8SEnji Cooper   }
7608ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDWR);
7618ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FTRUNCATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
7628ac5aef8SEnji Cooper   if (rc >= 0) {
7638ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7648ac5aef8SEnji Cooper   }
7658ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_ftruncate", 0));
7668ac5aef8SEnji Cooper 
7678ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY, 0600);
7688ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
7698ac5aef8SEnji Cooper   if (rc >= 0) {
7708ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7718ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
7728ac5aef8SEnji Cooper   }
7738ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR, 0600);
7748ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
7758ac5aef8SEnji Cooper   if (rc >= 0) {
7768ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7778ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_create", 0));
7788ac5aef8SEnji Cooper   }
7798ac5aef8SEnji Cooper 
7808ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fsync", O_CREAT, 0600);
7818ac5aef8SEnji Cooper   EXPECT_OK(rc);
7828ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
7838ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY);
7848ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
7858ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
7868ac5aef8SEnji Cooper   if (rc >= 0) {
7878ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7888ac5aef8SEnji Cooper   }
7898ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR);
7908ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
7918ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
7928ac5aef8SEnji Cooper   if (rc >= 0) {
7938ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
7948ac5aef8SEnji Cooper   }
7958ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY);
7968ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
7978ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
7988ac5aef8SEnji Cooper   if (rc >= 0) {
7998ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
8008ac5aef8SEnji Cooper   }
8018ac5aef8SEnji Cooper   rc = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR);
8028ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc,
8038ac5aef8SEnji Cooper                rights, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_LOOKUP);
8048ac5aef8SEnji Cooper   if (rc >= 0) {
8058ac5aef8SEnji Cooper     EXPECT_OK(close(rc));
8068ac5aef8SEnji Cooper   }
8078ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fsync", 0));
8088ac5aef8SEnji Cooper 
8098ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGSAT
8108ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_chflagsat", O_CREAT, 0600);
8118ac5aef8SEnji Cooper   EXPECT_OK(rc);
8128ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8138ac5aef8SEnji Cooper   rc = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0);
8148ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_CHFLAGSAT, CAP_LOOKUP);
8158ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_chflagsat", 0));
8168ac5aef8SEnji Cooper #endif
8178ac5aef8SEnji Cooper 
8188ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fchownat", O_CREAT, 0600);
8198ac5aef8SEnji Cooper   EXPECT_OK(rc);
8208ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8218ac5aef8SEnji Cooper   rc = fchownat(dfd_cap, "cap_fchownat", -1, -1, 0);
8228ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCHOWN, CAP_LOOKUP);
8238ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fchownat", 0));
8248ac5aef8SEnji Cooper 
8258ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fchmodat", O_CREAT, 0600);
8268ac5aef8SEnji Cooper   EXPECT_OK(rc);
8278ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8288ac5aef8SEnji Cooper   rc = fchmodat(dfd_cap, "cap_fchmodat", 0600, 0);
8298ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FCHMOD, CAP_LOOKUP);
8308ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fchmodat", 0));
8318ac5aef8SEnji Cooper 
8328ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_fstatat", O_CREAT, 0600);
8338ac5aef8SEnji Cooper   EXPECT_OK(rc);
8348ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8358ac5aef8SEnji Cooper   struct stat sb;
8368ac5aef8SEnji Cooper   rc = fstatat(dfd_cap, "cap_fstatat", &sb, 0);
8378ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FSTAT, CAP_LOOKUP);
8388ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_fstatat", 0));
8398ac5aef8SEnji Cooper 
8408ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_futimesat", O_CREAT, 0600);
8418ac5aef8SEnji Cooper   EXPECT_OK(rc);
8428ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8438ac5aef8SEnji Cooper   rc = futimesat(dfd_cap, "cap_futimesat", NULL);
8448ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_FUTIMES, CAP_LOOKUP);
8458ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_futimesat", 0));
8468ac5aef8SEnji Cooper 
8478ac5aef8SEnji Cooper   // For linkat(2), need:
8488ac5aef8SEnji Cooper   //  - CAP_LINKAT_SOURCE on source
8498ac5aef8SEnji Cooper   //  - CAP_LINKAT_TARGET on destination.
8508ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_linkat_src", O_CREAT, 0600);
8518ac5aef8SEnji Cooper   EXPECT_OK(rc);
8528ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8538ac5aef8SEnji Cooper 
8548ac5aef8SEnji Cooper   rc = linkat(dirfd, "cap_linkat_src", dfd_cap, "cap_linkat_dst", 0);
8558ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_LINKAT_TARGET);
8568ac5aef8SEnji Cooper   if (rc >= 0) {
8578ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_linkat_dst", 0));
8588ac5aef8SEnji Cooper   }
8598ac5aef8SEnji Cooper 
8608ac5aef8SEnji Cooper   rc = linkat(dfd_cap, "cap_linkat_src", dirfd, "cap_linkat_dst", 0);
8618ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_LINKAT_SOURCE);
8628ac5aef8SEnji Cooper   if (rc >= 0) {
8638ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_linkat_dst", 0));
8648ac5aef8SEnji Cooper   }
8658ac5aef8SEnji Cooper 
8668ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(dirfd, "cap_linkat_src", 0));
8678ac5aef8SEnji Cooper 
8688ac5aef8SEnji Cooper   rc = mkdirat(dfd_cap, "cap_mkdirat", 0700);
8698ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_MKDIRAT, CAP_LOOKUP);
8708ac5aef8SEnji Cooper   if (rc >= 0) {
8718ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR));
8728ac5aef8SEnji Cooper   }
8738ac5aef8SEnji Cooper 
8748ac5aef8SEnji Cooper #ifdef HAVE_MKFIFOAT
8758ac5aef8SEnji Cooper   rc = mkfifoat(dfd_cap, "cap_mkfifoat", 0600);
8768ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_MKFIFOAT, CAP_LOOKUP);
8778ac5aef8SEnji Cooper   if (rc >= 0) {
8788ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_mkfifoat", 0));
8798ac5aef8SEnji Cooper   }
8808ac5aef8SEnji Cooper #endif
8818ac5aef8SEnji Cooper 
8828ac5aef8SEnji Cooper   if (getuid() == 0) {
8838ac5aef8SEnji Cooper     rc = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0);
8848ac5aef8SEnji Cooper     CHECK_RIGHT_RESULT(rc, rights, CAP_MKNODAT, CAP_LOOKUP);
8858ac5aef8SEnji Cooper     if (rc >= 0) {
8868ac5aef8SEnji Cooper       EXPECT_OK(unlinkat(dirfd, "cap_mknodat", 0));
8878ac5aef8SEnji Cooper     }
8888ac5aef8SEnji Cooper   }
8898ac5aef8SEnji Cooper 
8908ac5aef8SEnji Cooper   // For renameat(2), need:
8918ac5aef8SEnji Cooper   //  - CAP_RENAMEAT_SOURCE on source
8928ac5aef8SEnji Cooper   //  - CAP_RENAMEAT_TARGET on destination.
8938ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_renameat_src", O_CREAT, 0600);
8948ac5aef8SEnji Cooper   EXPECT_OK(rc);
8958ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
8968ac5aef8SEnji Cooper 
8978ac5aef8SEnji Cooper   rc = renameat(dirfd, "cap_renameat_src", dfd_cap, "cap_renameat_dst");
8988ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_RENAMEAT_TARGET);
8998ac5aef8SEnji Cooper   if (rc >= 0) {
9008ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_dst", 0));
9018ac5aef8SEnji Cooper   } else {
9028ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_src", 0));
9038ac5aef8SEnji Cooper   }
9048ac5aef8SEnji Cooper 
9058ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_renameat_src", O_CREAT, 0600);
9068ac5aef8SEnji Cooper   EXPECT_OK(rc);
9078ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
9088ac5aef8SEnji Cooper 
9098ac5aef8SEnji Cooper   rc = renameat(dfd_cap, "cap_renameat_src", dirfd, "cap_renameat_dst");
9108ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_RENAMEAT_SOURCE);
9118ac5aef8SEnji Cooper 
9128ac5aef8SEnji Cooper   if (rc >= 0) {
9138ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_dst", 0));
9148ac5aef8SEnji Cooper   } else {
9158ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_renameat_src", 0));
9168ac5aef8SEnji Cooper   }
9178ac5aef8SEnji Cooper 
9188ac5aef8SEnji Cooper   rc = symlinkat("test", dfd_cap, "cap_symlinkat");
9198ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_SYMLINKAT, CAP_LOOKUP);
9208ac5aef8SEnji Cooper   if (rc >= 0) {
9218ac5aef8SEnji Cooper     EXPECT_OK(unlinkat(dirfd, "cap_symlinkat", 0));
9228ac5aef8SEnji Cooper   }
9238ac5aef8SEnji Cooper 
9248ac5aef8SEnji Cooper   rc = openat(dirfd, "cap_unlinkat", O_CREAT, 0600);
9258ac5aef8SEnji Cooper   EXPECT_OK(rc);
9268ac5aef8SEnji Cooper   EXPECT_OK(close(rc));
9278ac5aef8SEnji Cooper   rc = unlinkat(dfd_cap, "cap_unlinkat", 0);
9288ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_UNLINKAT, CAP_LOOKUP);
9298ac5aef8SEnji Cooper   unlinkat(dirfd, "cap_unlinkat", 0);
9308ac5aef8SEnji Cooper   EXPECT_OK(mkdirat(dirfd, "cap_unlinkat", 0700));
9318ac5aef8SEnji Cooper   rc = unlinkat(dfd_cap, "cap_unlinkat", AT_REMOVEDIR);
9328ac5aef8SEnji Cooper   CHECK_RIGHT_RESULT(rc, rights, CAP_UNLINKAT, CAP_LOOKUP);
9338ac5aef8SEnji Cooper   unlinkat(dirfd, "cap_unlinkat", AT_REMOVEDIR);
9348ac5aef8SEnji Cooper 
9358ac5aef8SEnji Cooper   EXPECT_OK(close(dfd_cap));
9368ac5aef8SEnji Cooper }
9378ac5aef8SEnji Cooper 
DirOperationsTest(int extra)9388ac5aef8SEnji Cooper void DirOperationsTest(int extra) {
9398ac5aef8SEnji Cooper   int rc = mkdir(TmpFile("cap_dirops"), 0755);
9408ac5aef8SEnji Cooper   EXPECT_OK(rc);
9418ac5aef8SEnji Cooper   if (rc < 0 && errno != EEXIST) return;
9428ac5aef8SEnji Cooper   int dfd = open(TmpFile("cap_dirops"), O_RDONLY | O_DIRECTORY | extra);
9438ac5aef8SEnji Cooper   EXPECT_OK(dfd);
9448ac5aef8SEnji Cooper   int tmpfd = open(tmpdir.c_str(), O_RDONLY | O_DIRECTORY);
9458ac5aef8SEnji Cooper   EXPECT_OK(tmpfd);
9468ac5aef8SEnji Cooper 
9478ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
9488ac5aef8SEnji Cooper 
9498ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_LINKAT_SOURCE);
9508ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_LINKAT_TARGET);
9518ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_READ, CAP_LOOKUP);
9528ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_WRITE, CAP_LOOKUP);
9538ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_CREATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
9548ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_READ, CAP_LOOKUP);
9558ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_WRITE, CAP_LOOKUP);
9568ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSYNC, CAP_READ, CAP_WRITE, CAP_LOOKUP);
9578ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_READ, CAP_LOOKUP);
9588ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_WRITE, CAP_LOOKUP);
9598ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FTRUNCATE, CAP_READ, CAP_WRITE, CAP_LOOKUP);
9608ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FCHOWN, CAP_LOOKUP);
9618ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FCHMOD, CAP_LOOKUP);
9628ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FSTAT, CAP_LOOKUP);
9638ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_FUTIMES, CAP_LOOKUP);
9648ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKDIRAT, CAP_LOOKUP);
9658ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKFIFOAT, CAP_LOOKUP);
9668ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_MKNODAT, CAP_LOOKUP);
9678ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_SYMLINKAT, CAP_LOOKUP);
9688ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_UNLINKAT, CAP_LOOKUP);
9698ac5aef8SEnji Cooper   // Rename needs CAP_RENAMEAT_SOURCE on source directory and
9708ac5aef8SEnji Cooper   // CAP_RENAMEAT_TARGET on destination directory.
9718ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_RENAMEAT_SOURCE, CAP_UNLINKAT, CAP_LOOKUP);
9728ac5aef8SEnji Cooper   TRY_DIR_OPS(dfd, CAP_RENAMEAT_TARGET, CAP_UNLINKAT, CAP_LOOKUP);
9738ac5aef8SEnji Cooper 
9748ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(tmpfd, "cap_dirops", AT_REMOVEDIR));
9758ac5aef8SEnji Cooper   EXPECT_OK(close(tmpfd));
9768ac5aef8SEnji Cooper   EXPECT_OK(close(dfd));
9778ac5aef8SEnji Cooper }
9788ac5aef8SEnji Cooper 
FORK_TEST(Capability,DirOperations)9798ac5aef8SEnji Cooper FORK_TEST(Capability, DirOperations) {
9808ac5aef8SEnji Cooper   DirOperationsTest(0);
9818ac5aef8SEnji Cooper }
9828ac5aef8SEnji Cooper 
9838ac5aef8SEnji Cooper #ifdef O_PATH
FORK_TEST(Capability,PathDirOperations)9848ac5aef8SEnji Cooper FORK_TEST(Capability, PathDirOperations) {
9858ac5aef8SEnji Cooper   // Make the dfd in the test a path-only file descriptor.
9868ac5aef8SEnji Cooper   DirOperationsTest(O_PATH);
9878ac5aef8SEnji Cooper }
9888ac5aef8SEnji Cooper #endif
9898ac5aef8SEnji Cooper 
TryReadWrite(int cap_fd)9908ac5aef8SEnji Cooper static void TryReadWrite(int cap_fd) {
9918ac5aef8SEnji Cooper   char buffer[64];
9928ac5aef8SEnji Cooper   EXPECT_OK(read(cap_fd, buffer, sizeof(buffer)));
9938ac5aef8SEnji Cooper   int rc = write(cap_fd, "", 0);
9948ac5aef8SEnji Cooper   EXPECT_EQ(-1, rc);
9958ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);
9968ac5aef8SEnji Cooper }
9978ac5aef8SEnji Cooper 
9988ac5aef8SEnji Cooper FORK_TEST_ON(Capability, SocketTransfer, TmpFile("cap_fd_transfer")) {
9998ac5aef8SEnji Cooper   int sock_fds[2];
10008ac5aef8SEnji Cooper   EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds));
10018ac5aef8SEnji Cooper 
10028ac5aef8SEnji Cooper   struct msghdr mh;
10038ac5aef8SEnji Cooper   mh.msg_name = NULL;  // No address needed
10048ac5aef8SEnji Cooper   mh.msg_namelen = 0;
10058ac5aef8SEnji Cooper   char buffer1[1024];
10068ac5aef8SEnji Cooper   struct iovec iov[1];
10078ac5aef8SEnji Cooper   iov[0].iov_base = buffer1;
10088ac5aef8SEnji Cooper   iov[0].iov_len = sizeof(buffer1);
10098ac5aef8SEnji Cooper   mh.msg_iov = iov;
10108ac5aef8SEnji Cooper   mh.msg_iovlen = 1;
10118ac5aef8SEnji Cooper   char buffer2[1024];
10128ac5aef8SEnji Cooper   mh.msg_control = buffer2;
10138ac5aef8SEnji Cooper   mh.msg_controllen = sizeof(buffer2);
10148ac5aef8SEnji Cooper   struct cmsghdr *cmptr;
10158ac5aef8SEnji Cooper 
10168ac5aef8SEnji Cooper   cap_rights_t r_rs;
10178ac5aef8SEnji Cooper   cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
10188ac5aef8SEnji Cooper 
10198ac5aef8SEnji Cooper   pid_t child = fork();
10208ac5aef8SEnji Cooper   if (child == 0) {
10218ac5aef8SEnji Cooper     // Child: enter cap mode
10228ac5aef8SEnji Cooper     EXPECT_OK(cap_enter());
1023955a3f9aSAlex Richardson     // Child: send startup notification
1024955a3f9aSAlex Richardson     SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_STARTED);
10258ac5aef8SEnji Cooper 
10268ac5aef8SEnji Cooper     // Child: wait to receive FD over socket
10278ac5aef8SEnji Cooper     int rc = recvmsg(sock_fds[0], &mh, 0);
10288ac5aef8SEnji Cooper     EXPECT_OK(rc);
10298ac5aef8SEnji Cooper     EXPECT_LE(CMSG_LEN(sizeof(int)), mh.msg_controllen);
10308ac5aef8SEnji Cooper     cmptr = CMSG_FIRSTHDR(&mh);
10318ac5aef8SEnji Cooper     int cap_fd = *(int*)CMSG_DATA(cmptr);
10328ac5aef8SEnji Cooper     EXPECT_EQ(CMSG_LEN(sizeof(int)), cmptr->cmsg_len);
10338ac5aef8SEnji Cooper     cmptr = CMSG_NXTHDR(&mh, cmptr);
10348ac5aef8SEnji Cooper     EXPECT_TRUE(cmptr == NULL);
10358ac5aef8SEnji Cooper 
10368ac5aef8SEnji Cooper     // Child: confirm we can do the right operations on the capability
10378ac5aef8SEnji Cooper     cap_rights_t rights;
10388ac5aef8SEnji Cooper     EXPECT_OK(cap_rights_get(cap_fd, &rights));
10398ac5aef8SEnji Cooper     EXPECT_RIGHTS_EQ(&r_rs, &rights);
10408ac5aef8SEnji Cooper     TryReadWrite(cap_fd);
10418ac5aef8SEnji Cooper 
1042955a3f9aSAlex Richardson     // Child: acknowledge that we have received and tested the file descriptor
1043955a3f9aSAlex Richardson     SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_FD_RECEIVED);
1044955a3f9aSAlex Richardson 
10458ac5aef8SEnji Cooper     // Child: wait for a normal read
1046955a3f9aSAlex Richardson     AWAIT_INT_MESSAGE(sock_fds[0], MSG_PARENT_REQUEST_CHILD_EXIT);
1047955a3f9aSAlex Richardson     exit(testing::Test::HasFailure());
10488ac5aef8SEnji Cooper   }
10498ac5aef8SEnji Cooper 
10508ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_fd_transfer"), O_RDWR | O_CREAT, 0644);
10518ac5aef8SEnji Cooper   EXPECT_OK(fd);
10528ac5aef8SEnji Cooper   if (fd < 0) return;
10538ac5aef8SEnji Cooper   int cap_fd = dup(fd);
10548ac5aef8SEnji Cooper   EXPECT_OK(cap_fd);
10558ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_fd, &r_rs));
10568ac5aef8SEnji Cooper 
10578ac5aef8SEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode.
10588ac5aef8SEnji Cooper 
10598ac5aef8SEnji Cooper   // Confirm we can do the right operations on the capability
10608ac5aef8SEnji Cooper   TryReadWrite(cap_fd);
10618ac5aef8SEnji Cooper 
1062955a3f9aSAlex Richardson   // Wait for child to start up:
1063955a3f9aSAlex Richardson   AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_STARTED);
1064955a3f9aSAlex Richardson 
10658ac5aef8SEnji Cooper   // Send the file descriptor over the pipe to the sub-process
10668ac5aef8SEnji Cooper   mh.msg_controllen = CMSG_LEN(sizeof(int));
10678ac5aef8SEnji Cooper   cmptr = CMSG_FIRSTHDR(&mh);
10688ac5aef8SEnji Cooper   cmptr->cmsg_level = SOL_SOCKET;
10698ac5aef8SEnji Cooper   cmptr->cmsg_type = SCM_RIGHTS;
10708ac5aef8SEnji Cooper   cmptr->cmsg_len = CMSG_LEN(sizeof(int));
10718ac5aef8SEnji Cooper   *(int *)CMSG_DATA(cmptr) = cap_fd;
10728ac5aef8SEnji Cooper   buffer1[0] = 0;
10738ac5aef8SEnji Cooper   iov[0].iov_len = 1;
10748ac5aef8SEnji Cooper   int rc = sendmsg(sock_fds[1], &mh, 0);
10758ac5aef8SEnji Cooper   EXPECT_OK(rc);
10768ac5aef8SEnji Cooper 
1077955a3f9aSAlex Richardson   // Check that the child received the message
1078955a3f9aSAlex Richardson   AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_FD_RECEIVED);
1079955a3f9aSAlex Richardson 
1080955a3f9aSAlex Richardson   // Tell the child to exit
1081955a3f9aSAlex Richardson   SEND_INT_MESSAGE(sock_fds[1], MSG_PARENT_REQUEST_CHILD_EXIT);
10828ac5aef8SEnji Cooper }
10838ac5aef8SEnji Cooper 
TEST(Capability,SyscallAt)10848ac5aef8SEnji Cooper TEST(Capability, SyscallAt) {
10858ac5aef8SEnji Cooper   int rc = mkdir(TmpFile("cap_at_topdir"), 0755);
10868ac5aef8SEnji Cooper   EXPECT_OK(rc);
10878ac5aef8SEnji Cooper   if (rc < 0 && errno != EEXIST) return;
10888ac5aef8SEnji Cooper 
10898ac5aef8SEnji Cooper   cap_rights_t r_all;
10908ac5aef8SEnji Cooper   cap_rights_init(&r_all, CAP_READ, CAP_LOOKUP, CAP_MKNODAT, CAP_UNLINKAT, CAP_MKDIRAT, CAP_MKFIFOAT);
10918ac5aef8SEnji Cooper   cap_rights_t r_no_unlink;
10928ac5aef8SEnji Cooper   cap_rights_init(&r_no_unlink, CAP_READ, CAP_LOOKUP, CAP_MKDIRAT, CAP_MKFIFOAT);
10938ac5aef8SEnji Cooper   cap_rights_t r_no_mkdir;
10948ac5aef8SEnji Cooper   cap_rights_init(&r_no_mkdir, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKFIFOAT);
10958ac5aef8SEnji Cooper   cap_rights_t r_no_mkfifo;
10968ac5aef8SEnji Cooper   cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
10978ac5aef8SEnji Cooper   cap_rights_t r_create;
10988ac5aef8SEnji Cooper   cap_rights_init(&r_create, CAP_READ, CAP_LOOKUP, CAP_CREATE);
10998ac5aef8SEnji Cooper   cap_rights_t r_bind;
11008ac5aef8SEnji Cooper   cap_rights_init(&r_bind, CAP_READ, CAP_LOOKUP, CAP_BIND);
11018ac5aef8SEnji Cooper 
11028ac5aef8SEnji Cooper   int dfd = open(TmpFile("cap_at_topdir"), O_RDONLY);
11038ac5aef8SEnji Cooper   EXPECT_OK(dfd);
11048ac5aef8SEnji Cooper   int cap_dfd_all = dup(dfd);
11058ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_all);
11068ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_all, &r_all));
11078ac5aef8SEnji Cooper   int cap_dfd_no_unlink = dup(dfd);
11088ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_unlink);
11098ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_unlink, &r_no_unlink));
11108ac5aef8SEnji Cooper   int cap_dfd_no_mkdir = dup(dfd);
11118ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_mkdir);
11128ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_mkdir, &r_no_mkdir));
11138ac5aef8SEnji Cooper   int cap_dfd_no_mkfifo = dup(dfd);
11148ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_no_mkfifo);
11158ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_no_mkfifo));
11168ac5aef8SEnji Cooper   int cap_dfd_create = dup(dfd);
11178ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_create);
11188ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_create, &r_create));
11198ac5aef8SEnji Cooper   int cap_dfd_bind = dup(dfd);
11208ac5aef8SEnji Cooper   EXPECT_OK(cap_dfd_bind);
11218ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_dfd_bind, &r_bind));
11228ac5aef8SEnji Cooper 
11238ac5aef8SEnji Cooper   // Need CAP_MKDIRAT to mkdirat(2).
11248ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mkdirat(cap_dfd_no_mkdir, "cap_subdir", 0755));
11258ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir/cap_subdir"));
11268ac5aef8SEnji Cooper   EXPECT_OK(mkdirat(cap_dfd_all, "cap_subdir", 0755));
11278ac5aef8SEnji Cooper 
11288ac5aef8SEnji Cooper   // Need CAP_UNLINKAT to unlinkat(dfd, name, AT_REMOVEDIR).
11298ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(unlinkat(cap_dfd_no_unlink, "cap_subdir", AT_REMOVEDIR));
11308ac5aef8SEnji Cooper   EXPECT_OK(unlinkat(cap_dfd_all, "cap_subdir", AT_REMOVEDIR));
11318ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir/cap_subdir"));
11328ac5aef8SEnji Cooper 
11338ac5aef8SEnji Cooper   // Need CAP_MKFIFOAT to mkfifoat(2).
11348ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mkfifoat(cap_dfd_no_mkfifo, "cap_fifo", 0755));
11358ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_fifo"));
11368ac5aef8SEnji Cooper   EXPECT_OK(mkfifoat(cap_dfd_all, "cap_fifo", 0755));
11378ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_fifo"));
11388ac5aef8SEnji Cooper 
11398ac5aef8SEnji Cooper #ifdef HAVE_MKNOD_REG
11408ac5aef8SEnji Cooper   // Need CAP_CREATE to create a regular file with mknodat(2).
11418ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_regular", S_IFREG|0755, 0));
11428ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_regular"));
11438ac5aef8SEnji Cooper   EXPECT_OK(mknodat(cap_dfd_create, "cap_regular", S_IFREG|0755, 0));
11448ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_regular"));
11458ac5aef8SEnji Cooper #endif
11468ac5aef8SEnji Cooper 
11478ac5aef8SEnji Cooper #ifdef HAVE_MKNOD_SOCKET
11488ac5aef8SEnji Cooper   // Need CAP_BIND to create a UNIX domain socket with mknodat(2).
11498ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(mknodat(cap_dfd_all, "cap_socket", S_IFSOCK|0755, 0));
11508ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_socket"));
11518ac5aef8SEnji Cooper   EXPECT_OK(mknodat(cap_dfd_bind, "cap_socket", S_IFSOCK|0755, 0));
11528ac5aef8SEnji Cooper   unlink(TmpFile("cap_at_topdir/cap_socket"));
11538ac5aef8SEnji Cooper #endif
11548ac5aef8SEnji Cooper 
11558ac5aef8SEnji Cooper   close(cap_dfd_all);
11568ac5aef8SEnji Cooper   close(cap_dfd_no_mkfifo);
11578ac5aef8SEnji Cooper   close(cap_dfd_no_mkdir);
11588ac5aef8SEnji Cooper   close(cap_dfd_no_unlink);
11598ac5aef8SEnji Cooper   close(cap_dfd_create);
11608ac5aef8SEnji Cooper   close(cap_dfd_bind);
11618ac5aef8SEnji Cooper   close(dfd);
11628ac5aef8SEnji Cooper 
11638ac5aef8SEnji Cooper   // Tidy up.
11648ac5aef8SEnji Cooper   rmdir(TmpFile("cap_at_topdir"));
11658ac5aef8SEnji Cooper }
11668ac5aef8SEnji Cooper 
TEST(Capability,SyscallAtIfRoot)11672d936e6cSAlex Richardson TEST(Capability, SyscallAtIfRoot) {
11682d936e6cSAlex Richardson   GTEST_SKIP_IF_NOT_ROOT();
11692d936e6cSAlex Richardson   int rc = mkdir(TmpFile("cap_at_topdir"), 0755);
11702d936e6cSAlex Richardson   EXPECT_OK(rc);
11712d936e6cSAlex Richardson   if (rc < 0 && errno != EEXIST) return;
11722d936e6cSAlex Richardson 
11732d936e6cSAlex Richardson   cap_rights_t r_all;
11742d936e6cSAlex Richardson   cap_rights_init(&r_all, CAP_READ, CAP_LOOKUP, CAP_MKNODAT, CAP_UNLINKAT, CAP_MKDIRAT, CAP_MKFIFOAT);
11752d936e6cSAlex Richardson   cap_rights_t r_no_mkfifo;
11762d936e6cSAlex Richardson   cap_rights_init(&r_no_mkfifo, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
11772d936e6cSAlex Richardson   cap_rights_t r_no_mknod;
11782d936e6cSAlex Richardson   cap_rights_init(&r_no_mknod, CAP_READ, CAP_LOOKUP, CAP_UNLINKAT, CAP_MKDIRAT);
11792d936e6cSAlex Richardson 
11802d936e6cSAlex Richardson   int dfd = open(TmpFile("cap_at_topdir"), O_RDONLY);
11812d936e6cSAlex Richardson   EXPECT_OK(dfd);
11822d936e6cSAlex Richardson   int cap_dfd_all = dup(dfd);
11832d936e6cSAlex Richardson   EXPECT_OK(cap_dfd_all);
11842d936e6cSAlex Richardson   EXPECT_OK(cap_rights_limit(cap_dfd_all, &r_all));
11852d936e6cSAlex Richardson   int cap_dfd_no_mkfifo = dup(dfd);
11862d936e6cSAlex Richardson   EXPECT_OK(cap_dfd_no_mkfifo);
11872d936e6cSAlex Richardson   EXPECT_OK(cap_rights_limit(cap_dfd_no_mkfifo, &r_no_mkfifo));
11882d936e6cSAlex Richardson   int cap_dfd_no_mknod = dup(dfd);
11892d936e6cSAlex Richardson   EXPECT_OK(cap_dfd_no_mknod);
11902d936e6cSAlex Richardson   EXPECT_OK(cap_rights_limit(cap_dfd_no_mknod, &r_no_mknod));
11912d936e6cSAlex Richardson 
11922d936e6cSAlex Richardson   // Need CAP_MKNODAT to mknodat(2) a device
11932d936e6cSAlex Richardson   EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mknod, "cap_device", S_IFCHR|0755, makedev(99, 123)));
11942d936e6cSAlex Richardson   unlink(TmpFile("cap_at_topdir/cap_device"));
11952d936e6cSAlex Richardson   EXPECT_OK(mknodat(cap_dfd_all, "cap_device", S_IFCHR|0755, makedev(99, 123)));
11962d936e6cSAlex Richardson   unlink(TmpFile("cap_at_topdir/cap_device"));
11972d936e6cSAlex Richardson 
11982d936e6cSAlex Richardson   // Need CAP_MKFIFOAT to mknodat(2) for a FIFO.
11992d936e6cSAlex Richardson   EXPECT_NOTCAPABLE(mknodat(cap_dfd_no_mkfifo, "cap_fifo", S_IFIFO|0755, 0));
12002d936e6cSAlex Richardson   unlink(TmpFile("cap_at_topdir/cap_fifo"));
12012d936e6cSAlex Richardson   EXPECT_OK(mknodat(cap_dfd_all, "cap_fifo", S_IFIFO|0755, 0));
12022d936e6cSAlex Richardson   unlink(TmpFile("cap_at_topdir/cap_fifo"));
12032d936e6cSAlex Richardson 
12042d936e6cSAlex Richardson   close(cap_dfd_all);
12052d936e6cSAlex Richardson   close(cap_dfd_no_mknod);
12062d936e6cSAlex Richardson   close(cap_dfd_no_mkfifo);
12072d936e6cSAlex Richardson   close(dfd);
12082d936e6cSAlex Richardson 
12092d936e6cSAlex Richardson   // Tidy up.
12102d936e6cSAlex Richardson   rmdir(TmpFile("cap_at_topdir"));
12112d936e6cSAlex Richardson }
12122d936e6cSAlex Richardson 
12132d936e6cSAlex Richardson FORK_TEST_ON(Capability, ExtendedAttributesIfAvailable, TmpFile("cap_extattr")) {
12148ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_extattr"), O_RDONLY|O_CREAT, 0644);
12158ac5aef8SEnji Cooper   EXPECT_OK(fd);
12168ac5aef8SEnji Cooper 
12178ac5aef8SEnji Cooper   char buffer[1024];
12188ac5aef8SEnji Cooper   int rc = fgetxattr_(fd, "user.capsicumtest", buffer, sizeof(buffer));
12198ac5aef8SEnji Cooper   if (rc < 0 && errno == ENOTSUP) {
12208ac5aef8SEnji Cooper     // Need user_xattr mount option for non-root users on Linux
12218ac5aef8SEnji Cooper     close(fd);
12222d936e6cSAlex Richardson     GTEST_SKIP() << "/tmp doesn't support extended attributes";
12238ac5aef8SEnji Cooper   }
12248ac5aef8SEnji Cooper 
12258ac5aef8SEnji Cooper   cap_rights_t r_rws;
12268ac5aef8SEnji Cooper   cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
12278ac5aef8SEnji Cooper   cap_rights_t r_xlist;
12288ac5aef8SEnji Cooper   cap_rights_init(&r_xlist, CAP_EXTATTR_LIST);
12298ac5aef8SEnji Cooper   cap_rights_t r_xget;
12308ac5aef8SEnji Cooper   cap_rights_init(&r_xget, CAP_EXTATTR_GET);
12318ac5aef8SEnji Cooper   cap_rights_t r_xset;
12328ac5aef8SEnji Cooper   cap_rights_init(&r_xset, CAP_EXTATTR_SET);
12338ac5aef8SEnji Cooper   cap_rights_t r_xdel;
12348ac5aef8SEnji Cooper   cap_rights_init(&r_xdel, CAP_EXTATTR_DELETE);
12358ac5aef8SEnji Cooper 
12368ac5aef8SEnji Cooper   int cap = dup(fd);
12378ac5aef8SEnji Cooper   EXPECT_OK(cap);
12388ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap, &r_rws));
12398ac5aef8SEnji Cooper   int cap_xlist = dup(fd);
12408ac5aef8SEnji Cooper   EXPECT_OK(cap_xlist);
12418ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xlist, &r_xlist));
12428ac5aef8SEnji Cooper   int cap_xget = dup(fd);
12438ac5aef8SEnji Cooper   EXPECT_OK(cap_xget);
12448ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xget, &r_xget));
12458ac5aef8SEnji Cooper   int cap_xset = dup(fd);
12468ac5aef8SEnji Cooper   EXPECT_OK(cap_xset);
12478ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xset, &r_xset));
12488ac5aef8SEnji Cooper   int cap_xdel = dup(fd);
12498ac5aef8SEnji Cooper   EXPECT_OK(cap_xdel);
12508ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(cap_xdel, &r_xdel));
12518ac5aef8SEnji Cooper 
12528ac5aef8SEnji Cooper   const char* value = "capsicum";
12538ac5aef8SEnji Cooper   int len = strlen(value) + 1;
12548ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap, "user.capsicumtest", value, len, 0));
12558ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xlist, "user.capsicumtest", value, len, 0));
12568ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xget, "user.capsicumtest", value, len, 0));
12578ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fsetxattr_(cap_xdel, "user.capsicumtest", value, len, 0));
12588ac5aef8SEnji Cooper   EXPECT_OK(fsetxattr_(cap_xset, "user.capsicumtest", value, len, 0));
12598ac5aef8SEnji Cooper 
12608ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap, buffer, sizeof(buffer)));
12618ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xget, buffer, sizeof(buffer)));
12628ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xset, buffer, sizeof(buffer)));
12638ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(flistxattr_(cap_xdel, buffer, sizeof(buffer)));
12648ac5aef8SEnji Cooper   EXPECT_OK(flistxattr_(cap_xlist, buffer, sizeof(buffer)));
12658ac5aef8SEnji Cooper 
12668ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap, "user.capsicumtest", buffer, sizeof(buffer)));
12678ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xlist, "user.capsicumtest", buffer, sizeof(buffer)));
12688ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xset, "user.capsicumtest", buffer, sizeof(buffer)));
12698ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fgetxattr_(cap_xdel, "user.capsicumtest", buffer, sizeof(buffer)));
12708ac5aef8SEnji Cooper   EXPECT_OK(fgetxattr_(cap_xget, "user.capsicumtest", buffer, sizeof(buffer)));
12718ac5aef8SEnji Cooper 
12728ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap, "user.capsicumtest"));
12738ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xlist, "user.capsicumtest"));
12748ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xget, "user.capsicumtest"));
12758ac5aef8SEnji Cooper   EXPECT_NOTCAPABLE(fremovexattr_(cap_xset, "user.capsicumtest"));
12768ac5aef8SEnji Cooper   EXPECT_OK(fremovexattr_(cap_xdel, "user.capsicumtest"));
12778ac5aef8SEnji Cooper 
12788ac5aef8SEnji Cooper   close(cap_xdel);
12798ac5aef8SEnji Cooper   close(cap_xset);
12808ac5aef8SEnji Cooper   close(cap_xget);
12818ac5aef8SEnji Cooper   close(cap_xlist);
12828ac5aef8SEnji Cooper   close(cap);
12838ac5aef8SEnji Cooper   close(fd);
12848ac5aef8SEnji Cooper }
12858ac5aef8SEnji Cooper 
TEST(Capability,PipeUnseekable)12868ac5aef8SEnji Cooper TEST(Capability, PipeUnseekable) {
12878ac5aef8SEnji Cooper   int fds[2];
12888ac5aef8SEnji Cooper   EXPECT_OK(pipe(fds));
12898ac5aef8SEnji Cooper 
12908ac5aef8SEnji Cooper   // Some programs detect pipes by calling seek() and getting ESPIPE.
12918ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
12928ac5aef8SEnji Cooper   EXPECT_EQ(ESPIPE, errno);
12938ac5aef8SEnji Cooper 
12948ac5aef8SEnji Cooper   cap_rights_t rights;
12958ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK);
12968ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fds[0], &rights));
12978ac5aef8SEnji Cooper 
12988ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
12998ac5aef8SEnji Cooper   EXPECT_EQ(ESPIPE, errno);
13008ac5aef8SEnji Cooper 
13018ac5aef8SEnji Cooper   // Remove CAP_SEEK and see if ENOTCAPABLE trumps ESPIPE.
13028ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE);
13038ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fds[0], &rights));
13048ac5aef8SEnji Cooper   EXPECT_EQ(-1, lseek(fds[0], 0, SEEK_SET));
13058ac5aef8SEnji Cooper   EXPECT_EQ(ENOTCAPABLE, errno);
13068ac5aef8SEnji Cooper   // TODO(drysdale): in practical terms it might be nice if ESPIPE trumped ENOTCAPABLE.
13078ac5aef8SEnji Cooper   // EXPECT_EQ(ESPIPE, errno);
13088ac5aef8SEnji Cooper 
13098ac5aef8SEnji Cooper   close(fds[0]);
13108ac5aef8SEnji Cooper   close(fds[1]);
13118ac5aef8SEnji Cooper }
13128ac5aef8SEnji Cooper 
TEST(Capability,NoBypassDACIfRoot)13132d936e6cSAlex Richardson TEST(Capability, NoBypassDACIfRoot) {
13142d936e6cSAlex Richardson   GTEST_SKIP_IF_NOT_ROOT();
13158ac5aef8SEnji Cooper   int fd = open(TmpFile("cap_root_owned"), O_RDONLY|O_CREAT, 0644);
13168ac5aef8SEnji Cooper   EXPECT_OK(fd);
13178ac5aef8SEnji Cooper   cap_rights_t rights;
13188ac5aef8SEnji Cooper   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FCHMOD, CAP_FSTAT);
13198ac5aef8SEnji Cooper   EXPECT_OK(cap_rights_limit(fd, &rights));
13208ac5aef8SEnji Cooper 
13218ac5aef8SEnji Cooper   pid_t child = fork();
13228ac5aef8SEnji Cooper   if (child == 0) {
13238ac5aef8SEnji Cooper     // Child: change uid to a lesser being
13242d936e6cSAlex Richardson     ASSERT_NE(0u, other_uid) << "other_uid not initialized correctly, "
13252d936e6cSAlex Richardson                                 "please pass the -u <uid> flag.";
13262d936e6cSAlex Richardson     EXPECT_EQ(0, setuid(other_uid));
13272d936e6cSAlex Richardson     EXPECT_EQ(other_uid, getuid());
13288ac5aef8SEnji Cooper     // Attempt to fchmod the file, and fail.
13298ac5aef8SEnji Cooper     // Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy.
13308ac5aef8SEnji Cooper     int rc = fchmod(fd, 0666);
13318ac5aef8SEnji Cooper     EXPECT_EQ(-1, rc);
13328ac5aef8SEnji Cooper     EXPECT_EQ(EPERM, errno);
13338ac5aef8SEnji Cooper     exit(HasFailure());
13348ac5aef8SEnji Cooper   }
13358ac5aef8SEnji Cooper   int status;
13368ac5aef8SEnji Cooper   EXPECT_EQ(child, waitpid(child, &status, 0));
13378ac5aef8SEnji Cooper   EXPECT_TRUE(WIFEXITED(status)) << "0x" << std::hex << status;
13388ac5aef8SEnji Cooper   EXPECT_EQ(0, WEXITSTATUS(status));
13398ac5aef8SEnji Cooper   struct stat info;
13408ac5aef8SEnji Cooper   EXPECT_OK(fstat(fd, &info));
13418ac5aef8SEnji Cooper   EXPECT_EQ((mode_t)(S_IFREG|0644), info.st_mode);
13428ac5aef8SEnji Cooper   close(fd);
13438ac5aef8SEnji Cooper   unlink(TmpFile("cap_root_owned"));
13448ac5aef8SEnji Cooper }
1345*a7100ae2SMariusz Zaborski 
TEST(Capability,CheckIsEmpty)1346*a7100ae2SMariusz Zaborski TEST(Capability, CheckIsEmpty) {
1347*a7100ae2SMariusz Zaborski   cap_rights_t rights;
1348*a7100ae2SMariusz Zaborski 
1349*a7100ae2SMariusz Zaborski   cap_rights_init(&rights);
1350*a7100ae2SMariusz Zaborski   EXPECT_TRUE(cap_rights_is_empty(&rights));
1351*a7100ae2SMariusz Zaborski 
1352*a7100ae2SMariusz Zaborski   size_t num_known = (sizeof(known_rights)/sizeof(known_rights[0]));
1353*a7100ae2SMariusz Zaborski   for (size_t ii = 0; ii < num_known; ii++) {
1354*a7100ae2SMariusz Zaborski     cap_rights_init(&rights, known_rights[ii].right);
1355*a7100ae2SMariusz Zaborski     EXPECT_FALSE(cap_rights_is_empty(&rights));
1356*a7100ae2SMariusz Zaborski     cap_rights_clear(&rights, known_rights[ii].right);
1357*a7100ae2SMariusz Zaborski     EXPECT_TRUE(cap_rights_is_empty(&rights));
1358*a7100ae2SMariusz Zaborski   }
1359*a7100ae2SMariusz Zaborski }
1360