xref: /freebsd-src/contrib/capsicum-test/capmode.cc (revision d0675399d09f02d347912e23d004329710338450)
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