18ac5aef8SEnji Cooper // Test routines to make sure a variety of system calls are or are not 28ac5aef8SEnji Cooper // available in capability mode. The goal is not to see if they work, just 38ac5aef8SEnji Cooper // whether or not they return the expected ECAPMODE. 48ac5aef8SEnji Cooper #include <sys/types.h> 58ac5aef8SEnji Cooper #include <sys/socket.h> 6b856b51dSMark Johnston #ifdef __FreeBSD__ 7b856b51dSMark Johnston #include <sys/sockio.h> 8b856b51dSMark Johnston #endif 98ac5aef8SEnji Cooper #include <sys/stat.h> 108ac5aef8SEnji Cooper #include <sys/mount.h> 118ac5aef8SEnji Cooper #include <sys/mman.h> 128ac5aef8SEnji Cooper #include <sys/wait.h> 138ac5aef8SEnji Cooper #include <sys/time.h> 148ac5aef8SEnji Cooper #include <sys/resource.h> 158ac5aef8SEnji Cooper #include <sys/ptrace.h> 168ac5aef8SEnji Cooper #include <dirent.h> 17b856b51dSMark Johnston #include <net/if.h> 188ac5aef8SEnji Cooper #include <netinet/in.h> 198ac5aef8SEnji Cooper #include <fcntl.h> 208ac5aef8SEnji Cooper #include <sched.h> 218ac5aef8SEnji Cooper #include <time.h> 228ac5aef8SEnji Cooper #include <unistd.h> 238ac5aef8SEnji Cooper #include <pthread.h> 248ac5aef8SEnji Cooper 258ac5aef8SEnji Cooper #include "capsicum.h" 268ac5aef8SEnji Cooper #include "syscalls.h" 278ac5aef8SEnji Cooper #include "capsicum-test.h" 288ac5aef8SEnji Cooper 298ac5aef8SEnji Cooper // Test fixture that opens (and closes) a bunch of files. 308ac5aef8SEnji Cooper class WithFiles : public ::testing::Test { 318ac5aef8SEnji Cooper public: 328ac5aef8SEnji Cooper WithFiles() : 338ac5aef8SEnji Cooper fd_file_(open(TmpFile("cap_capmode"), O_RDWR|O_CREAT, 0644)), 348ac5aef8SEnji Cooper fd_close_(open("/dev/null", O_RDWR)), 358ac5aef8SEnji Cooper fd_dir_(open(tmpdir.c_str(), O_RDONLY)), 368ac5aef8SEnji Cooper fd_socket_(socket(PF_INET, SOCK_DGRAM, 0)), 378ac5aef8SEnji Cooper fd_tcp_socket_(socket(PF_INET, SOCK_STREAM, 0)) { 388ac5aef8SEnji Cooper EXPECT_OK(fd_file_); 398ac5aef8SEnji Cooper EXPECT_OK(fd_close_); 408ac5aef8SEnji Cooper EXPECT_OK(fd_dir_); 418ac5aef8SEnji Cooper EXPECT_OK(fd_socket_); 428ac5aef8SEnji Cooper EXPECT_OK(fd_tcp_socket_); 438ac5aef8SEnji Cooper } 448ac5aef8SEnji Cooper ~WithFiles() { 458ac5aef8SEnji Cooper if (fd_tcp_socket_ >= 0) close(fd_tcp_socket_); 468ac5aef8SEnji Cooper if (fd_socket_ >= 0) close(fd_socket_); 478ac5aef8SEnji Cooper if (fd_dir_ >= 0) close(fd_dir_); 488ac5aef8SEnji Cooper if (fd_close_ >= 0) close(fd_close_); 498ac5aef8SEnji Cooper if (fd_file_ >= 0) close(fd_file_); 508ac5aef8SEnji Cooper unlink(TmpFile("cap_capmode")); 518ac5aef8SEnji Cooper } 528ac5aef8SEnji Cooper protected: 538ac5aef8SEnji Cooper int fd_file_; 548ac5aef8SEnji Cooper int fd_close_; 558ac5aef8SEnji Cooper int fd_dir_; 568ac5aef8SEnji Cooper int fd_socket_; 578ac5aef8SEnji Cooper int fd_tcp_socket_; 588ac5aef8SEnji Cooper }; 598ac5aef8SEnji Cooper 608ac5aef8SEnji Cooper FORK_TEST_F(WithFiles, DisallowedFileSyscalls) { 618ac5aef8SEnji Cooper unsigned int mode = -1; 628ac5aef8SEnji Cooper EXPECT_OK(cap_getmode(&mode)); 638ac5aef8SEnji Cooper EXPECT_EQ(0, (int)mode); 648ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 658ac5aef8SEnji Cooper EXPECT_OK(cap_getmode(&mode)); 668ac5aef8SEnji Cooper EXPECT_EQ(1, (int)mode); 678ac5aef8SEnji Cooper 688ac5aef8SEnji Cooper // System calls that are not permitted in capability mode. 698ac5aef8SEnji Cooper EXPECT_CAPMODE(access(TmpFile("cap_capmode_access"), F_OK)); 708ac5aef8SEnji Cooper EXPECT_CAPMODE(acct(TmpFile("cap_capmode_acct"))); 718ac5aef8SEnji Cooper EXPECT_CAPMODE(chdir(TmpFile("cap_capmode_chdir"))); 728ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGS 738ac5aef8SEnji Cooper EXPECT_CAPMODE(chflags(TmpFile("cap_capmode_chflags"), UF_NODUMP)); 748ac5aef8SEnji Cooper #endif 758ac5aef8SEnji Cooper EXPECT_CAPMODE(chmod(TmpFile("cap_capmode_chmod"), 0644)); 768ac5aef8SEnji Cooper EXPECT_CAPMODE(chown(TmpFile("cap_capmode_chown"), -1, -1)); 778ac5aef8SEnji Cooper EXPECT_CAPMODE(chroot(TmpFile("cap_capmode_chroot"))); 788ac5aef8SEnji Cooper EXPECT_CAPMODE(creat(TmpFile("cap_capmode_creat"), 0644)); 798ac5aef8SEnji Cooper EXPECT_CAPMODE(fchdir(fd_dir_)); 808ac5aef8SEnji Cooper #ifdef HAVE_GETFSSTAT 818ac5aef8SEnji Cooper struct statfs statfs; 828ac5aef8SEnji Cooper EXPECT_CAPMODE(getfsstat(&statfs, sizeof(statfs), MNT_NOWAIT)); 838ac5aef8SEnji Cooper #endif 848ac5aef8SEnji Cooper EXPECT_CAPMODE(link(TmpFile("foo"), TmpFile("bar"))); 858ac5aef8SEnji Cooper struct stat sb; 868ac5aef8SEnji Cooper EXPECT_CAPMODE(lstat(TmpFile("cap_capmode_lstat"), &sb)); 878ac5aef8SEnji Cooper EXPECT_CAPMODE(mknod(TmpFile("capmode_mknod"), 0644 | S_IFIFO, 0)); 888ac5aef8SEnji Cooper EXPECT_CAPMODE(bogus_mount_()); 898ac5aef8SEnji Cooper EXPECT_CAPMODE(open("/dev/null", O_RDWR)); 908ac5aef8SEnji Cooper char buf[64]; 918ac5aef8SEnji Cooper EXPECT_CAPMODE(readlink(TmpFile("cap_capmode_readlink"), buf, sizeof(buf))); 928ac5aef8SEnji Cooper #ifdef HAVE_REVOKE 938ac5aef8SEnji Cooper EXPECT_CAPMODE(revoke(TmpFile("cap_capmode_revoke"))); 948ac5aef8SEnji Cooper #endif 958ac5aef8SEnji Cooper EXPECT_CAPMODE(stat(TmpFile("cap_capmode_stat"), &sb)); 968ac5aef8SEnji Cooper EXPECT_CAPMODE(symlink(TmpFile("cap_capmode_symlink_from"), TmpFile("cap_capmode_symlink_to"))); 978ac5aef8SEnji Cooper EXPECT_CAPMODE(unlink(TmpFile("cap_capmode_unlink"))); 988ac5aef8SEnji Cooper EXPECT_CAPMODE(umount2("/not_mounted", 0)); 998ac5aef8SEnji Cooper } 1008ac5aef8SEnji Cooper 1018ac5aef8SEnji Cooper FORK_TEST_F(WithFiles, DisallowedSocketSyscalls) { 1028ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 1038ac5aef8SEnji Cooper 1048ac5aef8SEnji Cooper // System calls that are not permitted in capability mode. 1058ac5aef8SEnji Cooper struct sockaddr_in addr; 1068ac5aef8SEnji Cooper addr.sin_family = AF_INET; 1078ac5aef8SEnji Cooper addr.sin_port = 0; 1088ac5aef8SEnji Cooper addr.sin_addr.s_addr = htonl(INADDR_ANY); 1098ac5aef8SEnji Cooper EXPECT_CAPMODE(bind_(fd_socket_, (sockaddr*)&addr, sizeof(addr))); 1108ac5aef8SEnji Cooper addr.sin_family = AF_INET; 1118ac5aef8SEnji Cooper addr.sin_port = 53; 1128ac5aef8SEnji Cooper addr.sin_addr.s_addr = htonl(0x08080808); 1138ac5aef8SEnji Cooper EXPECT_CAPMODE(connect_(fd_tcp_socket_, (sockaddr*)&addr, sizeof(addr))); 1148ac5aef8SEnji Cooper } 1158ac5aef8SEnji Cooper 1168ac5aef8SEnji Cooper FORK_TEST_F(WithFiles, AllowedFileSyscalls) { 1178ac5aef8SEnji Cooper int rc; 1188ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 1198ac5aef8SEnji Cooper 1208ac5aef8SEnji Cooper EXPECT_OK(close(fd_close_)); 1218ac5aef8SEnji Cooper fd_close_ = -1; 1228ac5aef8SEnji Cooper int fd_dup = dup(fd_file_); 1238ac5aef8SEnji Cooper EXPECT_OK(fd_dup); 1248ac5aef8SEnji Cooper EXPECT_OK(dup2(fd_file_, fd_dup)); 1258ac5aef8SEnji Cooper #ifdef HAVE_DUP3 1268ac5aef8SEnji Cooper EXPECT_OK(dup3(fd_file_, fd_dup, 0)); 1278ac5aef8SEnji Cooper #endif 1288ac5aef8SEnji Cooper if (fd_dup >= 0) close(fd_dup); 1298ac5aef8SEnji Cooper 1308ac5aef8SEnji Cooper struct stat sb; 1318ac5aef8SEnji Cooper EXPECT_OK(fstat(fd_file_, &sb)); 1328ac5aef8SEnji Cooper EXPECT_OK(lseek(fd_file_, 0, SEEK_SET)); 1338ac5aef8SEnji Cooper char ch; 1348ac5aef8SEnji Cooper EXPECT_OK(read(fd_file_, &ch, sizeof(ch))); 1358ac5aef8SEnji Cooper EXPECT_OK(write(fd_file_, &ch, sizeof(ch))); 1368ac5aef8SEnji Cooper 1378ac5aef8SEnji Cooper #ifdef HAVE_CHFLAGS 1388ac5aef8SEnji Cooper rc = fchflags(fd_file_, UF_NODUMP); 1398ac5aef8SEnji Cooper if (rc < 0) { 1408ac5aef8SEnji Cooper EXPECT_NE(ECAPMODE, errno); 1418ac5aef8SEnji Cooper } 1428ac5aef8SEnji Cooper #endif 1438ac5aef8SEnji Cooper 1448ac5aef8SEnji Cooper char buf[1024]; 1458ac5aef8SEnji Cooper rc = getdents_(fd_dir_, (void*)buf, sizeof(buf)); 1468ac5aef8SEnji Cooper EXPECT_OK(rc); 1478ac5aef8SEnji Cooper 1488ac5aef8SEnji Cooper char data[] = "123"; 1498ac5aef8SEnji Cooper EXPECT_OK(pwrite(fd_file_, data, 1, 0)); 1508ac5aef8SEnji Cooper EXPECT_OK(pread(fd_file_, data, 1, 0)); 1518ac5aef8SEnji Cooper 1528ac5aef8SEnji Cooper struct iovec io; 1538ac5aef8SEnji Cooper io.iov_base = data; 1548ac5aef8SEnji Cooper io.iov_len = 2; 1558ac5aef8SEnji Cooper #if !defined(__i386__) && !defined(__linux__) 1568ac5aef8SEnji Cooper // TODO(drysdale): reinstate these tests for 32-bit runs when possible 1578ac5aef8SEnji Cooper // libc bug is fixed. 1588ac5aef8SEnji Cooper EXPECT_OK(pwritev(fd_file_, &io, 1, 0)); 1598ac5aef8SEnji Cooper EXPECT_OK(preadv(fd_file_, &io, 1, 0)); 1608ac5aef8SEnji Cooper #endif 1618ac5aef8SEnji Cooper EXPECT_OK(writev(fd_file_, &io, 1)); 1628ac5aef8SEnji Cooper EXPECT_OK(readv(fd_file_, &io, 1)); 1638ac5aef8SEnji Cooper 1648ac5aef8SEnji Cooper #ifdef HAVE_SYNCFS 1658ac5aef8SEnji Cooper EXPECT_OK(syncfs(fd_file_)); 1668ac5aef8SEnji Cooper #endif 1678ac5aef8SEnji Cooper #ifdef HAVE_SYNC_FILE_RANGE 1688ac5aef8SEnji Cooper EXPECT_OK(sync_file_range(fd_file_, 0, 1, 0)); 1698ac5aef8SEnji Cooper #endif 1708ac5aef8SEnji Cooper #ifdef HAVE_READAHEAD 1718ac5aef8SEnji Cooper if (!tmpdir_on_tmpfs) { // tmpfs doesn't support readahead(2) 1728ac5aef8SEnji Cooper EXPECT_OK(readahead(fd_file_, 0, 1)); 1738ac5aef8SEnji Cooper } 1748ac5aef8SEnji Cooper #endif 1758ac5aef8SEnji Cooper } 1768ac5aef8SEnji Cooper 1778ac5aef8SEnji Cooper FORK_TEST_F(WithFiles, AllowedSocketSyscalls) { 1788ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 1798ac5aef8SEnji Cooper 1808ac5aef8SEnji Cooper // recvfrom() either returns -1 with EAGAIN, or 0. 1818ac5aef8SEnji Cooper int rc = recvfrom(fd_socket_, NULL, 0, MSG_DONTWAIT, NULL, NULL); 1828ac5aef8SEnji Cooper if (rc < 0) { 1838ac5aef8SEnji Cooper EXPECT_EQ(EAGAIN, errno); 1848ac5aef8SEnji Cooper } 1858ac5aef8SEnji Cooper char ch; 1868ac5aef8SEnji Cooper EXPECT_OK(write(fd_file_, &ch, sizeof(ch))); 1878ac5aef8SEnji Cooper 1888ac5aef8SEnji Cooper // These calls will fail for lack of e.g. a proper name to send to, 1898ac5aef8SEnji Cooper // but they are allowed in capability mode, so errno != ECAPMODE. 1908ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(accept(fd_socket_, NULL, NULL)); 1918ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(getpeername(fd_socket_, NULL, NULL)); 1928ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(getsockname(fd_socket_, NULL, NULL)); 1938ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(recvmsg(fd_socket_, NULL, 0)); 1948ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(sendmsg(fd_socket_, NULL, 0)); 1958ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(sendto(fd_socket_, NULL, 0, 0, NULL, 0)); 1968ac5aef8SEnji Cooper off_t offset = 0; 1978ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(sendfile_(fd_socket_, fd_file_, &offset, 1)); 1988ac5aef8SEnji Cooper 1998ac5aef8SEnji Cooper // The socket/socketpair syscalls are allowed, but they don't give 2008ac5aef8SEnji Cooper // anything externally useful (can't call bind/connect on them). 2018ac5aef8SEnji Cooper int fd_socket2 = socket(PF_INET, SOCK_DGRAM, 0); 2028ac5aef8SEnji Cooper EXPECT_OK(fd_socket2); 2038ac5aef8SEnji Cooper if (fd_socket2 >= 0) close(fd_socket2); 2048ac5aef8SEnji Cooper int fd_pair[2] = {-1, -1}; 2058ac5aef8SEnji Cooper EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, fd_pair)); 2068ac5aef8SEnji Cooper if (fd_pair[0] >= 0) close(fd_pair[0]); 2078ac5aef8SEnji Cooper if (fd_pair[1] >= 0) close(fd_pair[1]); 2088ac5aef8SEnji Cooper } 2098ac5aef8SEnji Cooper 210b856b51dSMark Johnston FORK_TEST_F(WithFiles, AllowedSocketSyscallsIfRoot) { 211b856b51dSMark Johnston GTEST_SKIP_IF_NOT_ROOT(); 212b856b51dSMark Johnston 213b856b51dSMark Johnston EXPECT_OK(cap_enter()); // Enter capability mode. 214b856b51dSMark Johnston 215b856b51dSMark Johnston // Creation of raw sockets is not permitted in capability mode. 216b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET, SOCK_RAW, 0)); 217b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)); 218b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET, SOCK_RAW, IPPROTO_TCP)); 219b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET, SOCK_RAW, IPPROTO_UDP)); 220b856b51dSMark Johnston 221b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET6, SOCK_RAW, IPPROTO_ICMP)); 222b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)); 223b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET6, SOCK_RAW, IPPROTO_TCP)); 224b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)); 225b856b51dSMark Johnston 226b856b51dSMark Johnston EXPECT_CAPMODE(socket(AF_ROUTE, SOCK_RAW, 0)); 227b856b51dSMark Johnston 228b856b51dSMark Johnston // Interface configuration ioctls are not permitted in capability 229b856b51dSMark Johnston // mode. 230*8e8f1cc9SMark Johnston // 231*8e8f1cc9SMark Johnston // This test is disabled for now as the corresponding kernel change was 232*8e8f1cc9SMark Johnston // disabled. 233*8e8f1cc9SMark Johnston #if 0 234b856b51dSMark Johnston #ifdef __FreeBSD__ 235b856b51dSMark Johnston struct if_clonereq req; 236b856b51dSMark Johnston 237b856b51dSMark Johnston req.ifcr_total = 0; 238b856b51dSMark Johnston req.ifcr_count = 1; 239b856b51dSMark Johnston req.ifcr_buffer = static_cast<char *>(malloc(IFNAMSIZ)); 240b856b51dSMark Johnston 241b856b51dSMark Johnston EXPECT_CAPMODE(ioctl(fd_socket_, SIOCIFGCLONERS, &req)); 242b856b51dSMark Johnston 243b856b51dSMark Johnston free(req.ifcr_buffer); 244b856b51dSMark Johnston #endif 245*8e8f1cc9SMark Johnston #endif 246b856b51dSMark Johnston } 247b856b51dSMark Johnston 2488ac5aef8SEnji Cooper #ifdef HAVE_SEND_RECV_MMSG 2498ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedMmsgSendRecv) { 2508ac5aef8SEnji Cooper int fd_socket = socket(PF_INET, SOCK_DGRAM, 0); 2518ac5aef8SEnji Cooper 2528ac5aef8SEnji Cooper struct sockaddr_in addr; 2538ac5aef8SEnji Cooper addr.sin_family = AF_INET; 2548ac5aef8SEnji Cooper addr.sin_port = htons(0); 2558ac5aef8SEnji Cooper addr.sin_addr.s_addr = htonl(INADDR_ANY); 2568ac5aef8SEnji Cooper EXPECT_OK(bind(fd_socket, (sockaddr*)&addr, sizeof(addr))); 2578ac5aef8SEnji Cooper 2588ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 2598ac5aef8SEnji Cooper 2608ac5aef8SEnji Cooper char buffer[256] = {0}; 2618ac5aef8SEnji Cooper struct iovec iov; 2628ac5aef8SEnji Cooper iov.iov_base = buffer; 2638ac5aef8SEnji Cooper iov.iov_len = sizeof(buffer); 2648ac5aef8SEnji Cooper struct mmsghdr mm; 2658ac5aef8SEnji Cooper memset(&mm, 0, sizeof(mm)); 2668ac5aef8SEnji Cooper mm.msg_hdr.msg_iov = &iov; 2678ac5aef8SEnji Cooper mm.msg_hdr.msg_iovlen = 1; 2688ac5aef8SEnji Cooper struct timespec ts; 2698ac5aef8SEnji Cooper ts.tv_sec = 1; 2708ac5aef8SEnji Cooper ts.tv_nsec = 100; 2718ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(recvmmsg(fd_socket, &mm, 1, MSG_DONTWAIT, &ts)); 2728ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(sendmmsg(fd_socket, &mm, 1, 0)); 2738ac5aef8SEnji Cooper close(fd_socket); 2748ac5aef8SEnji Cooper } 2758ac5aef8SEnji Cooper #endif 2768ac5aef8SEnji Cooper 2778ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedIdentifierSyscalls) { 2788ac5aef8SEnji Cooper // Record some identifiers 2798ac5aef8SEnji Cooper gid_t my_gid = getgid(); 2808ac5aef8SEnji Cooper pid_t my_pid = getpid(); 2818ac5aef8SEnji Cooper pid_t my_ppid = getppid(); 2828ac5aef8SEnji Cooper uid_t my_uid = getuid(); 2838ac5aef8SEnji Cooper pid_t my_sid = getsid(my_pid); 2848ac5aef8SEnji Cooper 2858ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 2868ac5aef8SEnji Cooper 2878ac5aef8SEnji Cooper EXPECT_EQ(my_gid, getegid_()); 2888ac5aef8SEnji Cooper EXPECT_EQ(my_uid, geteuid_()); 2898ac5aef8SEnji Cooper EXPECT_EQ(my_gid, getgid_()); 2908ac5aef8SEnji Cooper EXPECT_EQ(my_pid, getpid()); 2918ac5aef8SEnji Cooper EXPECT_EQ(my_ppid, getppid()); 2928ac5aef8SEnji Cooper EXPECT_EQ(my_uid, getuid_()); 2938ac5aef8SEnji Cooper EXPECT_EQ(my_sid, getsid(my_pid)); 2948ac5aef8SEnji Cooper gid_t grps[128]; 2958ac5aef8SEnji Cooper EXPECT_OK(getgroups_(128, grps)); 2968ac5aef8SEnji Cooper uid_t ruid; 2978ac5aef8SEnji Cooper uid_t euid; 2988ac5aef8SEnji Cooper uid_t suid; 2998ac5aef8SEnji Cooper EXPECT_OK(getresuid(&ruid, &euid, &suid)); 3008ac5aef8SEnji Cooper gid_t rgid; 3018ac5aef8SEnji Cooper gid_t egid; 3028ac5aef8SEnji Cooper gid_t sgid; 3038ac5aef8SEnji Cooper EXPECT_OK(getresgid(&rgid, &egid, &sgid)); 3048ac5aef8SEnji Cooper #ifdef HAVE_GETLOGIN 3058ac5aef8SEnji Cooper EXPECT_TRUE(getlogin() != NULL); 3068ac5aef8SEnji Cooper #endif 3078ac5aef8SEnji Cooper 3088ac5aef8SEnji Cooper // Set various identifiers (to their existing values). 3098ac5aef8SEnji Cooper EXPECT_OK(setgid(my_gid)); 3108ac5aef8SEnji Cooper #ifdef HAVE_SETFSGID 3118ac5aef8SEnji Cooper EXPECT_OK(setfsgid(my_gid)); 3128ac5aef8SEnji Cooper #endif 3138ac5aef8SEnji Cooper EXPECT_OK(setuid(my_uid)); 3148ac5aef8SEnji Cooper #ifdef HAVE_SETFSUID 3158ac5aef8SEnji Cooper EXPECT_OK(setfsuid(my_uid)); 3168ac5aef8SEnji Cooper #endif 3178ac5aef8SEnji Cooper EXPECT_OK(setregid(my_gid, my_gid)); 3188ac5aef8SEnji Cooper EXPECT_OK(setresgid(my_gid, my_gid, my_gid)); 3198ac5aef8SEnji Cooper EXPECT_OK(setreuid(my_uid, my_uid)); 3208ac5aef8SEnji Cooper EXPECT_OK(setresuid(my_uid, my_uid, my_uid)); 3218ac5aef8SEnji Cooper EXPECT_OK(setsid()); 3228ac5aef8SEnji Cooper } 3238ac5aef8SEnji Cooper 3248ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedSchedSyscalls) { 3258ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 3268ac5aef8SEnji Cooper int policy = sched_getscheduler(0); 3278ac5aef8SEnji Cooper EXPECT_OK(policy); 3288ac5aef8SEnji Cooper struct sched_param sp; 3298ac5aef8SEnji Cooper EXPECT_OK(sched_getparam(0, &sp)); 3308ac5aef8SEnji Cooper if (policy >= 0 && (!SCHED_SETSCHEDULER_REQUIRES_ROOT || getuid() == 0)) { 3318ac5aef8SEnji Cooper EXPECT_OK(sched_setscheduler(0, policy, &sp)); 3328ac5aef8SEnji Cooper } 3338ac5aef8SEnji Cooper EXPECT_OK(sched_setparam(0, &sp)); 3348ac5aef8SEnji Cooper EXPECT_OK(sched_get_priority_max(policy)); 3358ac5aef8SEnji Cooper EXPECT_OK(sched_get_priority_min(policy)); 3368ac5aef8SEnji Cooper struct timespec ts; 3378ac5aef8SEnji Cooper EXPECT_OK(sched_rr_get_interval(0, &ts)); 3388ac5aef8SEnji Cooper EXPECT_OK(sched_yield()); 3398ac5aef8SEnji Cooper } 3408ac5aef8SEnji Cooper 3418ac5aef8SEnji Cooper 3428ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedTimerSyscalls) { 3438ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 3448ac5aef8SEnji Cooper struct timespec ts; 3458ac5aef8SEnji Cooper EXPECT_OK(clock_getres(CLOCK_REALTIME, &ts)); 3468ac5aef8SEnji Cooper EXPECT_OK(clock_gettime(CLOCK_REALTIME, &ts)); 3478ac5aef8SEnji Cooper struct itimerval itv; 3488ac5aef8SEnji Cooper EXPECT_OK(getitimer(ITIMER_REAL, &itv)); 3498ac5aef8SEnji Cooper EXPECT_OK(setitimer(ITIMER_REAL, &itv, NULL)); 3508ac5aef8SEnji Cooper struct timeval tv; 3518ac5aef8SEnji Cooper struct timezone tz; 3528ac5aef8SEnji Cooper EXPECT_OK(gettimeofday(&tv, &tz)); 3538ac5aef8SEnji Cooper ts.tv_sec = 0; 3548ac5aef8SEnji Cooper ts.tv_nsec = 1; 3558ac5aef8SEnji Cooper EXPECT_OK(nanosleep(&ts, NULL)); 3568ac5aef8SEnji Cooper } 3578ac5aef8SEnji Cooper 3588ac5aef8SEnji Cooper 3598ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedProfilSyscall) { 3608ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 3618ac5aef8SEnji Cooper char sbuf[32]; 3628ac5aef8SEnji Cooper EXPECT_OK(profil((profil_arg1_t*)sbuf, sizeof(sbuf), 0, 1)); 3638ac5aef8SEnji Cooper } 3648ac5aef8SEnji Cooper 3658ac5aef8SEnji Cooper 3668ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedResourceSyscalls) { 3678ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 3688ac5aef8SEnji Cooper errno = 0; 3698ac5aef8SEnji Cooper int rc = getpriority(PRIO_PROCESS, 0); 3708ac5aef8SEnji Cooper EXPECT_EQ(0, errno); 3718ac5aef8SEnji Cooper EXPECT_OK(setpriority(PRIO_PROCESS, 0, rc)); 3728ac5aef8SEnji Cooper struct rlimit rlim; 3738ac5aef8SEnji Cooper EXPECT_OK(getrlimit_(RLIMIT_CORE, &rlim)); 3748ac5aef8SEnji Cooper EXPECT_OK(setrlimit(RLIMIT_CORE, &rlim)); 3758ac5aef8SEnji Cooper struct rusage ruse; 3768ac5aef8SEnji Cooper EXPECT_OK(getrusage(RUSAGE_SELF, &ruse)); 3778ac5aef8SEnji Cooper } 3788ac5aef8SEnji Cooper 3798ac5aef8SEnji Cooper FORK_TEST(CapMode, AllowedMmapSyscalls) { 3808ac5aef8SEnji Cooper // mmap() some memory. 3818ac5aef8SEnji Cooper size_t mem_size = getpagesize(); 3828ac5aef8SEnji Cooper void *mem = mmap(NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 3838ac5aef8SEnji Cooper EXPECT_TRUE(mem != NULL); 3848ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 3858ac5aef8SEnji Cooper 3868ac5aef8SEnji Cooper EXPECT_OK(msync(mem, mem_size, MS_ASYNC)); 3878ac5aef8SEnji Cooper EXPECT_OK(madvise(mem, mem_size, MADV_NORMAL)); 3888ac5aef8SEnji Cooper unsigned char vec[2]; 3898ac5aef8SEnji Cooper EXPECT_OK(mincore_(mem, mem_size, vec)); 3908ac5aef8SEnji Cooper EXPECT_OK(mprotect(mem, mem_size, PROT_READ|PROT_WRITE)); 3918ac5aef8SEnji Cooper 3928ac5aef8SEnji Cooper if (!MLOCK_REQUIRES_ROOT || getuid() == 0) { 3938ac5aef8SEnji Cooper EXPECT_OK(mlock(mem, mem_size)); 3948ac5aef8SEnji Cooper EXPECT_OK(munlock(mem, mem_size)); 3958ac5aef8SEnji Cooper int rc = mlockall(MCL_CURRENT); 3968ac5aef8SEnji Cooper if (rc != 0) { 3978ac5aef8SEnji Cooper // mlockall may well fail with ENOMEM for non-root users, as the 3988ac5aef8SEnji Cooper // default RLIMIT_MEMLOCK value isn't that big. 3998ac5aef8SEnji Cooper EXPECT_NE(ECAPMODE, errno); 4008ac5aef8SEnji Cooper } 4018ac5aef8SEnji Cooper EXPECT_OK(munlockall()); 4028ac5aef8SEnji Cooper } 4038ac5aef8SEnji Cooper // Unmap the memory. 4048ac5aef8SEnji Cooper EXPECT_OK(munmap(mem, mem_size)); 4058ac5aef8SEnji Cooper } 4068ac5aef8SEnji Cooper 4078ac5aef8SEnji Cooper FORK_TEST(Capmode, AllowedPipeSyscalls) { 4088ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode 4098ac5aef8SEnji Cooper int fd2[2]; 4108ac5aef8SEnji Cooper int rc = pipe(fd2); 4118ac5aef8SEnji Cooper EXPECT_EQ(0, rc); 4128ac5aef8SEnji Cooper 4138ac5aef8SEnji Cooper #ifdef HAVE_VMSPLICE 4148ac5aef8SEnji Cooper char buf[11] = "0123456789"; 4158ac5aef8SEnji Cooper struct iovec iov; 4168ac5aef8SEnji Cooper iov.iov_base = buf; 4178ac5aef8SEnji Cooper iov.iov_len = sizeof(buf); 4188ac5aef8SEnji Cooper EXPECT_FAIL_NOT_CAPMODE(vmsplice(fd2[0], &iov, 1, SPLICE_F_NONBLOCK)); 4198ac5aef8SEnji Cooper #endif 4208ac5aef8SEnji Cooper 4218ac5aef8SEnji Cooper if (rc == 0) { 4228ac5aef8SEnji Cooper close(fd2[0]); 4238ac5aef8SEnji Cooper close(fd2[1]); 4248ac5aef8SEnji Cooper }; 4258ac5aef8SEnji Cooper #ifdef HAVE_PIPE2 4268ac5aef8SEnji Cooper rc = pipe2(fd2, 0); 4278ac5aef8SEnji Cooper EXPECT_EQ(0, rc); 4288ac5aef8SEnji Cooper if (rc == 0) { 4298ac5aef8SEnji Cooper close(fd2[0]); 4308ac5aef8SEnji Cooper close(fd2[1]); 4318ac5aef8SEnji Cooper }; 4328ac5aef8SEnji Cooper #endif 4338ac5aef8SEnji Cooper } 4348ac5aef8SEnji Cooper 4358ac5aef8SEnji Cooper TEST(Capmode, AllowedAtSyscalls) { 4368ac5aef8SEnji Cooper int rc = mkdir(TmpFile("cap_at_syscalls"), 0755); 4378ac5aef8SEnji Cooper EXPECT_OK(rc); 4388ac5aef8SEnji Cooper if (rc < 0 && errno != EEXIST) return; 4398ac5aef8SEnji Cooper int dfd = open(TmpFile("cap_at_syscalls"), O_RDONLY); 4408ac5aef8SEnji Cooper EXPECT_OK(dfd); 4418ac5aef8SEnji Cooper 4428ac5aef8SEnji Cooper int file = openat(dfd, "testfile", O_RDONLY|O_CREAT, 0644); 4438ac5aef8SEnji Cooper EXPECT_OK(file); 4448ac5aef8SEnji Cooper EXPECT_OK(close(file)); 4458ac5aef8SEnji Cooper 4468ac5aef8SEnji Cooper 4478ac5aef8SEnji Cooper pid_t child = fork(); 4488ac5aef8SEnji Cooper if (child == 0) { 4498ac5aef8SEnji Cooper // Child: enter cap mode and run tests 4508ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode 4518ac5aef8SEnji Cooper 4528ac5aef8SEnji Cooper struct stat fs; 4538ac5aef8SEnji Cooper EXPECT_OK(fstatat(dfd, "testfile", &fs, 0)); 4548ac5aef8SEnji Cooper EXPECT_OK(mkdirat(dfd, "subdir", 0600)); 4558ac5aef8SEnji Cooper EXPECT_OK(fchmodat(dfd, "subdir", 0644, 0)); 4568ac5aef8SEnji Cooper EXPECT_OK(faccessat(dfd, "subdir", F_OK, 0)); 4578ac5aef8SEnji Cooper EXPECT_OK(renameat(dfd, "subdir", dfd, "subdir2")); 4588ac5aef8SEnji Cooper EXPECT_OK(renameat(dfd, "subdir2", dfd, "subdir")); 4598ac5aef8SEnji Cooper struct timeval tv[2]; 4608ac5aef8SEnji Cooper struct timezone tz; 4618ac5aef8SEnji Cooper EXPECT_OK(gettimeofday(&tv[0], &tz)); 4628ac5aef8SEnji Cooper EXPECT_OK(gettimeofday(&tv[1], &tz)); 4638ac5aef8SEnji Cooper EXPECT_OK(futimesat(dfd, "testfile", tv)); 4648ac5aef8SEnji Cooper 4658ac5aef8SEnji Cooper EXPECT_OK(fchownat(dfd, "testfile", fs.st_uid, fs.st_gid, 0)); 4668ac5aef8SEnji Cooper EXPECT_OK(linkat(dfd, "testfile", dfd, "linky", 0)); 4678ac5aef8SEnji Cooper EXPECT_OK(symlinkat("testfile", dfd, "symlink")); 4688ac5aef8SEnji Cooper char buffer[256]; 4698ac5aef8SEnji Cooper EXPECT_OK(readlinkat(dfd, "symlink", buffer, sizeof(buffer))); 4708ac5aef8SEnji Cooper EXPECT_OK(unlinkat(dfd, "linky", 0)); 4718ac5aef8SEnji Cooper EXPECT_OK(unlinkat(dfd, "subdir", AT_REMOVEDIR)); 4728ac5aef8SEnji Cooper 4738ac5aef8SEnji Cooper // Check that invalid requests get a non-Capsicum errno. 4748ac5aef8SEnji Cooper errno = 0; 4758ac5aef8SEnji Cooper rc = readlinkat(-1, "symlink", buffer, sizeof(buffer)); 4768ac5aef8SEnji Cooper EXPECT_GE(0, rc); 4778ac5aef8SEnji Cooper EXPECT_NE(ECAPMODE, errno); 4788ac5aef8SEnji Cooper 4798ac5aef8SEnji Cooper exit(HasFailure()); 4808ac5aef8SEnji Cooper } 4818ac5aef8SEnji Cooper 4828ac5aef8SEnji Cooper // Wait for the child. 4838ac5aef8SEnji Cooper int status; 4848ac5aef8SEnji Cooper EXPECT_EQ(child, waitpid(child, &status, 0)); 4858ac5aef8SEnji Cooper rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1; 4868ac5aef8SEnji Cooper EXPECT_EQ(0, rc); 4878ac5aef8SEnji Cooper 4888ac5aef8SEnji Cooper // Tidy up. 4898ac5aef8SEnji Cooper close(dfd); 4908ac5aef8SEnji Cooper rmdir(TmpFile("cap_at_syscalls/subdir")); 4918ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls/symlink")); 4928ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls/linky")); 4938ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls/testfile")); 4948ac5aef8SEnji Cooper rmdir(TmpFile("cap_at_syscalls")); 4958ac5aef8SEnji Cooper } 4968ac5aef8SEnji Cooper 4978ac5aef8SEnji Cooper TEST(Capmode, AllowedAtSyscallsCwd) { 4988ac5aef8SEnji Cooper int rc = mkdir(TmpFile("cap_at_syscalls_cwd"), 0755); 4998ac5aef8SEnji Cooper EXPECT_OK(rc); 5008ac5aef8SEnji Cooper if (rc < 0 && errno != EEXIST) return; 5018ac5aef8SEnji Cooper int dfd = open(TmpFile("cap_at_syscalls_cwd"), O_RDONLY); 5028ac5aef8SEnji Cooper EXPECT_OK(dfd); 5038ac5aef8SEnji Cooper 5048ac5aef8SEnji Cooper int file = openat(dfd, "testfile", O_RDONLY|O_CREAT, 0644); 5058ac5aef8SEnji Cooper EXPECT_OK(file); 5068ac5aef8SEnji Cooper EXPECT_OK(close(file)); 5078ac5aef8SEnji Cooper 5088ac5aef8SEnji Cooper pid_t child = fork(); 5098ac5aef8SEnji Cooper if (child == 0) { 5108ac5aef8SEnji Cooper // Child: move into temp dir, enter cap mode and run tests 5118ac5aef8SEnji Cooper EXPECT_OK(fchdir(dfd)); 5128ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode 5138ac5aef8SEnji Cooper 5148ac5aef8SEnji Cooper // Test that *at(AT_FDCWD, path,...) is policed with ECAPMODE. 5158ac5aef8SEnji Cooper EXPECT_CAPMODE(openat(AT_FDCWD, "testfile", O_RDONLY)); 5168ac5aef8SEnji Cooper struct stat fs; 5178ac5aef8SEnji Cooper EXPECT_CAPMODE(fstatat(AT_FDCWD, "testfile", &fs, 0)); 5188ac5aef8SEnji Cooper EXPECT_CAPMODE(mkdirat(AT_FDCWD, "subdir", 0600)); 5198ac5aef8SEnji Cooper EXPECT_CAPMODE(fchmodat(AT_FDCWD, "subdir", 0644, 0)); 5208ac5aef8SEnji Cooper EXPECT_CAPMODE(faccessat(AT_FDCWD, "subdir", F_OK, 0)); 5218ac5aef8SEnji Cooper EXPECT_CAPMODE(renameat(AT_FDCWD, "subdir", AT_FDCWD, "subdir2")); 5228ac5aef8SEnji Cooper EXPECT_CAPMODE(renameat(AT_FDCWD, "subdir2", AT_FDCWD, "subdir")); 5238ac5aef8SEnji Cooper struct timeval tv[2]; 5248ac5aef8SEnji Cooper struct timezone tz; 5258ac5aef8SEnji Cooper EXPECT_OK(gettimeofday(&tv[0], &tz)); 5268ac5aef8SEnji Cooper EXPECT_OK(gettimeofday(&tv[1], &tz)); 5278ac5aef8SEnji Cooper EXPECT_CAPMODE(futimesat(AT_FDCWD, "testfile", tv)); 5288ac5aef8SEnji Cooper 5298ac5aef8SEnji Cooper EXPECT_CAPMODE(fchownat(AT_FDCWD, "testfile", fs.st_uid, fs.st_gid, 0)); 5308ac5aef8SEnji Cooper EXPECT_CAPMODE(linkat(AT_FDCWD, "testfile", AT_FDCWD, "linky", 0)); 5318ac5aef8SEnji Cooper EXPECT_CAPMODE(symlinkat("testfile", AT_FDCWD, "symlink")); 5328ac5aef8SEnji Cooper char buffer[256]; 5338ac5aef8SEnji Cooper EXPECT_CAPMODE(readlinkat(AT_FDCWD, "symlink", buffer, sizeof(buffer))); 5348ac5aef8SEnji Cooper EXPECT_CAPMODE(unlinkat(AT_FDCWD, "linky", 0)); 5358ac5aef8SEnji Cooper 5368ac5aef8SEnji Cooper exit(HasFailure()); 5378ac5aef8SEnji Cooper } 5388ac5aef8SEnji Cooper 5398ac5aef8SEnji Cooper // Wait for the child. 5408ac5aef8SEnji Cooper int status; 5418ac5aef8SEnji Cooper EXPECT_EQ(child, waitpid(child, &status, 0)); 5428ac5aef8SEnji Cooper rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1; 5438ac5aef8SEnji Cooper EXPECT_EQ(0, rc); 5448ac5aef8SEnji Cooper 5458ac5aef8SEnji Cooper // Tidy up. 5468ac5aef8SEnji Cooper close(dfd); 5478ac5aef8SEnji Cooper rmdir(TmpFile("cap_at_syscalls_cwd/subdir")); 5488ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls_cwd/symlink")); 5498ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls_cwd/linky")); 5508ac5aef8SEnji Cooper unlink(TmpFile("cap_at_syscalls_cwd/testfile")); 5518ac5aef8SEnji Cooper rmdir(TmpFile("cap_at_syscalls_cwd")); 5528ac5aef8SEnji Cooper } 5538ac5aef8SEnji Cooper 5548ac5aef8SEnji Cooper TEST(Capmode, Abort) { 5558ac5aef8SEnji Cooper // Check that abort(3) works even in capability mode. 5568ac5aef8SEnji Cooper pid_t child = fork(); 5578ac5aef8SEnji Cooper if (child == 0) { 5588ac5aef8SEnji Cooper // Child: enter capability mode and call abort(3). 5598ac5aef8SEnji Cooper // Triggers something like kill(getpid(), SIGABRT). 5608ac5aef8SEnji Cooper cap_enter(); // Enter capability mode. 5618ac5aef8SEnji Cooper abort(); 5628ac5aef8SEnji Cooper exit(99); 5638ac5aef8SEnji Cooper } 5648ac5aef8SEnji Cooper int status; 5658ac5aef8SEnji Cooper EXPECT_EQ(child, waitpid(child, &status, 0)); 5668ac5aef8SEnji Cooper EXPECT_TRUE(WIFSIGNALED(status)) << " status = " << std::hex << status; 5678ac5aef8SEnji Cooper EXPECT_EQ(SIGABRT, WTERMSIG(status)) << " status = " << std::hex << status; 5688ac5aef8SEnji Cooper } 5698ac5aef8SEnji Cooper 5708ac5aef8SEnji Cooper FORK_TEST_F(WithFiles, AllowedMiscSyscalls) { 5718ac5aef8SEnji Cooper umask(022); 5728ac5aef8SEnji Cooper mode_t um_before = umask(022); 573955a3f9aSAlex Richardson int pipefds[2]; 574955a3f9aSAlex Richardson EXPECT_OK(pipe(pipefds)); 5758ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 5768ac5aef8SEnji Cooper 5778ac5aef8SEnji Cooper mode_t um = umask(022); 5788ac5aef8SEnji Cooper EXPECT_NE(-ECAPMODE, (int)um); 5798ac5aef8SEnji Cooper EXPECT_EQ(um_before, um); 5808ac5aef8SEnji Cooper stack_t ss; 5818ac5aef8SEnji Cooper EXPECT_OK(sigaltstack(NULL, &ss)); 5828ac5aef8SEnji Cooper 5838ac5aef8SEnji Cooper // Finally, tests for system calls that don't fit the pattern very well. 5848ac5aef8SEnji Cooper pid_t pid = fork(); 5858ac5aef8SEnji Cooper EXPECT_OK(pid); 5868ac5aef8SEnji Cooper if (pid == 0) { 587955a3f9aSAlex Richardson // Child: wait for an exit message from parent (so we can test waitpid). 588955a3f9aSAlex Richardson EXPECT_OK(close(pipefds[0])); 589955a3f9aSAlex Richardson SEND_INT_MESSAGE(pipefds[1], MSG_CHILD_STARTED); 590955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(pipefds[1], MSG_PARENT_REQUEST_CHILD_EXIT); 5918ac5aef8SEnji Cooper exit(0); 5928ac5aef8SEnji Cooper } else if (pid > 0) { 593955a3f9aSAlex Richardson EXPECT_OK(close(pipefds[1])); 594955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(pipefds[0], MSG_CHILD_STARTED); 5958ac5aef8SEnji Cooper errno = 0; 5968ac5aef8SEnji Cooper EXPECT_CAPMODE(ptrace_(PTRACE_PEEKDATA_, pid, &pid, NULL)); 597955a3f9aSAlex Richardson SEND_INT_MESSAGE(pipefds[0], MSG_PARENT_REQUEST_CHILD_EXIT); 598955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " child finished\n"); 5998ac5aef8SEnji Cooper } 6008ac5aef8SEnji Cooper 6018ac5aef8SEnji Cooper // No error return from sync(2) to test, but check errno remains unset. 6028ac5aef8SEnji Cooper errno = 0; 6038ac5aef8SEnji Cooper sync(); 6048ac5aef8SEnji Cooper EXPECT_EQ(0, errno); 6058ac5aef8SEnji Cooper 6068ac5aef8SEnji Cooper // TODO(FreeBSD): ktrace 6078ac5aef8SEnji Cooper 6088ac5aef8SEnji Cooper #ifdef HAVE_SYSARCH 6098ac5aef8SEnji Cooper // sysarch() is, by definition, architecture-dependent 6108ac5aef8SEnji Cooper #if defined (__amd64__) || defined (__i386__) 6118ac5aef8SEnji Cooper long sysarch_arg = 0; 6128ac5aef8SEnji Cooper EXPECT_CAPMODE(sysarch(I386_SET_IOPERM, &sysarch_arg)); 6138ac5aef8SEnji Cooper #else 6148ac5aef8SEnji Cooper // TOOD(jra): write a test for other architectures, like arm 6158ac5aef8SEnji Cooper #endif 6168ac5aef8SEnji Cooper #endif 6178ac5aef8SEnji Cooper } 6188ac5aef8SEnji Cooper 6198ac5aef8SEnji Cooper void *thread_fn(void *p) { 620955a3f9aSAlex Richardson int fd = (int)(intptr_t)p; 621955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " thread waiting to run\n"); 622955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(fd, MSG_PARENT_CHILD_SHOULD_RUN); 6238ac5aef8SEnji Cooper EXPECT_OK(getpid_()); 6248ac5aef8SEnji Cooper EXPECT_CAPMODE(open("/dev/null", O_RDWR)); 625955a3f9aSAlex Richardson // Return whether there have been any failures to the main thread. 626955a3f9aSAlex Richardson void *rval = (void *)(intptr_t)testing::Test::HasFailure(); 627955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " thread finished: %p\n", rval); 628955a3f9aSAlex Richardson return rval; 6298ac5aef8SEnji Cooper } 6308ac5aef8SEnji Cooper 6318ac5aef8SEnji Cooper // Check that restrictions are the same in subprocesses and threads 6328ac5aef8SEnji Cooper FORK_TEST(Capmode, NewThread) { 6338ac5aef8SEnji Cooper // Fire off a new thread before entering capability mode 6348ac5aef8SEnji Cooper pthread_t early_thread; 635955a3f9aSAlex Richardson void *thread_rval; 636955a3f9aSAlex Richardson // Create two pipes, one for synchronization with the threads, the other to 637955a3f9aSAlex Richardson // synchronize with the children (since we can't use waitpid after cap_enter). 638955a3f9aSAlex Richardson // Note: Could use pdfork+pdwait instead, but that is tested in procdesc.cc. 639955a3f9aSAlex Richardson int thread_pipe[2]; 640955a3f9aSAlex Richardson EXPECT_OK(pipe(thread_pipe)); 641955a3f9aSAlex Richardson int proc_pipe[2]; 642955a3f9aSAlex Richardson EXPECT_OK(pipe(proc_pipe)); 643955a3f9aSAlex Richardson EXPECT_OK(pthread_create(&early_thread, NULL, thread_fn, 644955a3f9aSAlex Richardson (void *)(intptr_t)thread_pipe[1])); 6458ac5aef8SEnji Cooper 6468ac5aef8SEnji Cooper // Fire off a new process before entering capability mode. 647955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " starting second child (non-capability mode)\n"); 6488ac5aef8SEnji Cooper int early_child = fork(); 6498ac5aef8SEnji Cooper EXPECT_OK(early_child); 6508ac5aef8SEnji Cooper if (early_child == 0) { 651955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " first child started\n"); 652955a3f9aSAlex Richardson EXPECT_OK(close(proc_pipe[0])); 653955a3f9aSAlex Richardson // Child: wait and then confirm this process is unaffected by capability mode in the parent. 654955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(proc_pipe[1], MSG_PARENT_CHILD_SHOULD_RUN); 6558ac5aef8SEnji Cooper int fd = open("/dev/null", O_RDWR); 6568ac5aef8SEnji Cooper EXPECT_OK(fd); 6578ac5aef8SEnji Cooper close(fd); 658955a3f9aSAlex Richardson // Notify the parent of success/failure. 659955a3f9aSAlex Richardson int rval = (int)testing::Test::HasFailure(); 660955a3f9aSAlex Richardson SEND_INT_MESSAGE(proc_pipe[1], rval); 661955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " first child finished: %d\n", rval); 662955a3f9aSAlex Richardson exit(rval); 6638ac5aef8SEnji Cooper } 6648ac5aef8SEnji Cooper 6658ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 666955a3f9aSAlex Richardson // At this point the current process has both a child process and a 667955a3f9aSAlex Richardson // child thread that were created before entering capability mode. 668955a3f9aSAlex Richardson // - The child process is unaffected by capability mode. 669955a3f9aSAlex Richardson // - The child thread is affected by capability mode. 670955a3f9aSAlex Richardson SEND_INT_MESSAGE(proc_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN); 671955a3f9aSAlex Richardson 6728ac5aef8SEnji Cooper // Do an allowed syscall. 6738ac5aef8SEnji Cooper EXPECT_OK(getpid_()); 674955a3f9aSAlex Richardson // Wait for the first child to exit (should get a zero exit code message). 675955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(proc_pipe[0], 0); 676955a3f9aSAlex Richardson 677955a3f9aSAlex Richardson // The child processes/threads return HasFailure(), so we depend on no prior errors. 678955a3f9aSAlex Richardson ASSERT_FALSE(testing::Test::HasFailure()) 679955a3f9aSAlex Richardson << "Cannot continue test with pre-existing failures."; 680955a3f9aSAlex Richardson // Now that we're in capability mode, if we create a second child process 681955a3f9aSAlex Richardson // it will be affected by capability mode. 682955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " starting second child (in capability mode)\n"); 6838ac5aef8SEnji Cooper int child = fork(); 6848ac5aef8SEnji Cooper EXPECT_OK(child); 6858ac5aef8SEnji Cooper if (child == 0) { 686955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " second child started\n"); 687955a3f9aSAlex Richardson EXPECT_OK(close(proc_pipe[0])); 6888ac5aef8SEnji Cooper // Child: do an allowed and a disallowed syscall. 6898ac5aef8SEnji Cooper EXPECT_OK(getpid_()); 6908ac5aef8SEnji Cooper EXPECT_CAPMODE(open("/dev/null", O_RDWR)); 691955a3f9aSAlex Richardson // Notify the parent of success/failure. 692955a3f9aSAlex Richardson int rval = (int)testing::Test::HasFailure(); 693955a3f9aSAlex Richardson SEND_INT_MESSAGE(proc_pipe[1], rval); 694955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " second child finished: %d\n", rval); 695955a3f9aSAlex Richardson exit(rval); 6968ac5aef8SEnji Cooper } 697955a3f9aSAlex Richardson // Now tell the early_started thread that it can run. We expect it to also 698955a3f9aSAlex Richardson // be affected by capability mode since it's per-process not per-thread. 699955a3f9aSAlex Richardson // Note: it is important that we don't allow the thread to run before fork(), 700955a3f9aSAlex Richardson // since that could result in fork() being called while the thread holds one 701955a3f9aSAlex Richardson // of the gtest-internal mutexes, so the child process deadlocks. 702955a3f9aSAlex Richardson SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN); 7038ac5aef8SEnji Cooper // Wait for the early-started thread. 704955a3f9aSAlex Richardson EXPECT_OK(pthread_join(early_thread, &thread_rval)); 705955a3f9aSAlex Richardson EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure"; 7068ac5aef8SEnji Cooper 707955a3f9aSAlex Richardson // Wait for the second child to exit (should get a zero exit code message). 708955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(proc_pipe[0], 0); 709955a3f9aSAlex Richardson 710955a3f9aSAlex Richardson // Fire off a new (second) child thread, which is also affected by capability mode. 711955a3f9aSAlex Richardson ASSERT_FALSE(testing::Test::HasFailure()) 712955a3f9aSAlex Richardson << "Cannot continue test with pre-existing failures."; 7138ac5aef8SEnji Cooper pthread_t child_thread; 714955a3f9aSAlex Richardson EXPECT_OK(pthread_create(&child_thread, NULL, thread_fn, 715955a3f9aSAlex Richardson (void *)(intptr_t)thread_pipe[1])); 716955a3f9aSAlex Richardson SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN); 717955a3f9aSAlex Richardson EXPECT_OK(pthread_join(child_thread, &thread_rval)); 718955a3f9aSAlex Richardson EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure"; 7198ac5aef8SEnji Cooper 7208ac5aef8SEnji Cooper // Fork a subprocess which fires off a new thread. 721955a3f9aSAlex Richardson ASSERT_FALSE(testing::Test::HasFailure()) 722955a3f9aSAlex Richardson << "Cannot continue test with pre-existing failures."; 723955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " starting third child (in capability mode)\n"); 7248ac5aef8SEnji Cooper child = fork(); 7258ac5aef8SEnji Cooper EXPECT_OK(child); 7268ac5aef8SEnji Cooper if (child == 0) { 727955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " third child started\n"); 728955a3f9aSAlex Richardson EXPECT_OK(close(proc_pipe[0])); 7298ac5aef8SEnji Cooper pthread_t child_thread2; 730955a3f9aSAlex Richardson EXPECT_OK(pthread_create(&child_thread2, NULL, thread_fn, 731955a3f9aSAlex Richardson (void *)(intptr_t)thread_pipe[1])); 732955a3f9aSAlex Richardson SEND_INT_MESSAGE(thread_pipe[0], MSG_PARENT_CHILD_SHOULD_RUN); 733955a3f9aSAlex Richardson EXPECT_OK(pthread_join(child_thread2, &thread_rval)); 734955a3f9aSAlex Richardson EXPECT_FALSE((bool)(intptr_t)thread_rval) << "thread returned failure"; 735955a3f9aSAlex Richardson // Notify the parent of success/failure. 736955a3f9aSAlex Richardson int rval = (int)testing::Test::HasFailure(); 737955a3f9aSAlex Richardson SEND_INT_MESSAGE(proc_pipe[1], rval); 738955a3f9aSAlex Richardson if (verbose) fprintf(stderr, " third child finished: %d\n", rval); 739955a3f9aSAlex Richardson exit(rval); 7408ac5aef8SEnji Cooper } 741955a3f9aSAlex Richardson // Wait for the third child to exit (should get a zero exit code message). 742955a3f9aSAlex Richardson AWAIT_INT_MESSAGE(proc_pipe[0], 0); 743955a3f9aSAlex Richardson close(proc_pipe[0]); 744955a3f9aSAlex Richardson close(proc_pipe[1]); 745955a3f9aSAlex Richardson close(thread_pipe[0]); 746955a3f9aSAlex Richardson close(thread_pipe[1]); 7478ac5aef8SEnji Cooper } 7488ac5aef8SEnji Cooper 749955a3f9aSAlex Richardson static volatile sig_atomic_t had_signal = 0; 7508ac5aef8SEnji Cooper static void handle_signal(int) { had_signal = 1; } 7518ac5aef8SEnji Cooper 7528ac5aef8SEnji Cooper FORK_TEST(Capmode, SelfKill) { 7538ac5aef8SEnji Cooper pid_t me = getpid(); 7548ac5aef8SEnji Cooper sighandler_t original = signal(SIGUSR1, handle_signal); 7558ac5aef8SEnji Cooper 7568ac5aef8SEnji Cooper pid_t child = fork(); 7578ac5aef8SEnji Cooper if (child == 0) { 7588ac5aef8SEnji Cooper // Child: sleep and exit 7598ac5aef8SEnji Cooper sleep(1); 7608ac5aef8SEnji Cooper exit(0); 7618ac5aef8SEnji Cooper } 7628ac5aef8SEnji Cooper 7638ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode. 7648ac5aef8SEnji Cooper 7658ac5aef8SEnji Cooper // Can only kill(2) to own pid. 7668ac5aef8SEnji Cooper EXPECT_CAPMODE(kill(child, SIGUSR1)); 7678ac5aef8SEnji Cooper EXPECT_OK(kill(me, SIGUSR1)); 7688ac5aef8SEnji Cooper EXPECT_EQ(1, had_signal); 7698ac5aef8SEnji Cooper 7708ac5aef8SEnji Cooper signal(SIGUSR1, original); 7718ac5aef8SEnji Cooper } 772