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 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 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 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 2638ac5aef8SEnji Cooper FORK_TEST(Capability, CapEnter) { 2648ac5aef8SEnji Cooper EXPECT_EQ(0, cap_enter()); 2658ac5aef8SEnji Cooper } 2668ac5aef8SEnji Cooper 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 { \ 489*955a3f9aSAlex 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 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 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 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 9798ac5aef8SEnji Cooper FORK_TEST(Capability, DirOperations) { 9808ac5aef8SEnji Cooper DirOperationsTest(0); 9818ac5aef8SEnji Cooper } 9828ac5aef8SEnji Cooper 9838ac5aef8SEnji Cooper #ifdef O_PATH 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 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()); 1023*955a3f9aSAlex Richardson // Child: send startup notification 1024*955a3f9aSAlex 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 1042*955a3f9aSAlex Richardson // Child: acknowledge that we have received and tested the file descriptor 1043*955a3f9aSAlex Richardson SEND_INT_MESSAGE(sock_fds[0], MSG_CHILD_FD_RECEIVED); 1044*955a3f9aSAlex Richardson 10458ac5aef8SEnji Cooper // Child: wait for a normal read 1046*955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(sock_fds[0], MSG_PARENT_REQUEST_CHILD_EXIT); 1047*955a3f9aSAlex 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 1062*955a3f9aSAlex Richardson // Wait for child to start up: 1063*955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_STARTED); 1064*955a3f9aSAlex 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 1077*955a3f9aSAlex Richardson // Check that the child received the message 1078*955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(sock_fds[1], MSG_CHILD_FD_RECEIVED); 1079*955a3f9aSAlex Richardson 1080*955a3f9aSAlex Richardson // Tell the child to exit 1081*955a3f9aSAlex Richardson SEND_INT_MESSAGE(sock_fds[1], MSG_PARENT_REQUEST_CHILD_EXIT); 10828ac5aef8SEnji Cooper } 10838ac5aef8SEnji Cooper 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 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 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 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