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