1 #include <sys/select.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <poll.h>
6
7 #include "capsicum.h"
8 #include "syscalls.h"
9 #include "capsicum-test.h"
10
11 namespace {
12
AddFDToSet(fd_set * fset,int fd,int maxfd)13 int AddFDToSet(fd_set* fset, int fd, int maxfd) {
14 FD_SET(fd, fset);
15 if (fd > maxfd) maxfd = fd;
16 return maxfd;
17 }
18
InitFDSet(fd_set * fset,int * fds,int fdcount)19 int InitFDSet(fd_set* fset, int *fds, int fdcount) {
20 FD_ZERO(fset);
21 int maxfd = -1;
22 for (int ii = 0; ii < fdcount; ii++) {
23 maxfd = AddFDToSet(fset, fds[ii], maxfd);
24 }
25 return maxfd;
26 }
27
28 } // namespace
29
30 FORK_TEST_ON(Select, LotsOFileDescriptors, TmpFile("cap_select")) {
31 int fd = open(TmpFile("cap_select"), O_RDWR | O_CREAT, 0644);
32 EXPECT_OK(fd);
33 if (fd < 0) return;
34
35 // Create many POLL_EVENT capabilities.
36 const int kCapCount = 64;
37 int cap_fd[kCapCount];
38 cap_rights_t r_poll;
39 cap_rights_init(&r_poll, CAP_EVENT);
40 for (int ii = 0; ii < kCapCount; ii++) {
41 cap_fd[ii] = dup(fd);
42 EXPECT_OK(cap_fd[ii]);
43 EXPECT_OK(cap_rights_limit(cap_fd[ii], &r_poll));
44 }
45 cap_rights_t r_rw;
46 cap_rights_init(&r_rw, CAP_READ, CAP_WRITE, CAP_SEEK);
47 int cap_rw = dup(fd);
48 EXPECT_OK(cap_rw);
49 EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
50
51 EXPECT_OK(cap_enter()); // Enter capability mode
52
53 struct timeval tv;
54 tv.tv_sec = 0;
55 tv.tv_usec = 100;
56 // Add normal file descriptor and all CAP_EVENT capabilities
57 fd_set rset;
58 fd_set wset;
59 int maxfd = InitFDSet(&rset, cap_fd, kCapCount);
60 maxfd = AddFDToSet(&rset, fd, maxfd);
61 InitFDSet(&wset, cap_fd, kCapCount);
62 AddFDToSet(&rset, fd, 0);
63 int ret = select(maxfd+1, &rset, &wset, NULL, &tv);
64 EXPECT_OK(ret);
65
66 // Now also include the capability with no CAP_EVENT.
67 InitFDSet(&rset, cap_fd, kCapCount);
68 AddFDToSet(&rset, fd, maxfd);
69 maxfd = AddFDToSet(&rset, cap_rw, maxfd);
70 InitFDSet(&wset, cap_fd, kCapCount);
71 AddFDToSet(&wset, fd, maxfd);
72 AddFDToSet(&wset, cap_rw, maxfd);
73 ret = select(maxfd+1, &rset, &wset, NULL, &tv);
74 EXPECT_NOTCAPABLE(ret);
75
76 // And again with pselect
77 struct timespec ts;
78 ts.tv_sec = 0;
79 ts.tv_nsec = 100000;
80 maxfd = InitFDSet(&rset, cap_fd, kCapCount);
81 maxfd = AddFDToSet(&rset, fd, maxfd);
82 InitFDSet(&wset, cap_fd, kCapCount);
83 AddFDToSet(&rset, fd, 0);
84 ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
85 EXPECT_OK(ret);
86
87 InitFDSet(&rset, cap_fd, kCapCount);
88 AddFDToSet(&rset, fd, maxfd);
89 maxfd = AddFDToSet(&rset, cap_rw, maxfd);
90 InitFDSet(&wset, cap_fd, kCapCount);
91 AddFDToSet(&wset, fd, maxfd);
92 AddFDToSet(&wset, cap_rw, maxfd);
93 ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
94 EXPECT_NOTCAPABLE(ret);
95 }
96
97 FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
98 int fd = open(TmpFile("cap_poll"), O_RDWR | O_CREAT, 0644);
99 EXPECT_OK(fd);
100 if (fd < 0) return;
101
102 // Create many POLL_EVENT capabilities.
103 const int kCapCount = 64;
104 struct pollfd cap_fd[kCapCount + 2];
105 cap_rights_t r_poll;
106 cap_rights_init(&r_poll, CAP_EVENT);
107 for (int ii = 0; ii < kCapCount; ii++) {
108 cap_fd[ii].fd = dup(fd);
109 EXPECT_OK(cap_fd[ii].fd);
110 EXPECT_OK(cap_rights_limit(cap_fd[ii].fd, &r_poll));
111 cap_fd[ii].events = POLLIN|POLLOUT;
112 }
113 cap_fd[kCapCount].fd = fd;
114 cap_fd[kCapCount].events = POLLIN|POLLOUT;
115 cap_rights_t r_rw;
116 cap_rights_init(&r_rw, CAP_READ, CAP_WRITE, CAP_SEEK);
117 int cap_rw = dup(fd);
118 EXPECT_OK(cap_rw);
119 EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
120 cap_fd[kCapCount + 1].fd = cap_rw;
121 cap_fd[kCapCount + 1].events = POLLIN|POLLOUT;
122
123 EXPECT_OK(cap_enter()); // Enter capability mode
124
125 EXPECT_OK(poll(cap_fd, kCapCount + 1, 10));
126 // Now also include the capability with no CAP_EVENT.
127 EXPECT_OK(poll(cap_fd, kCapCount + 2, 10));
128 EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
129
130 // And again with ppoll
131 struct timespec ts;
132 ts.tv_sec = 0;
133 ts.tv_nsec = 100000;
134 EXPECT_OK(ppoll(cap_fd, kCapCount + 1, &ts, NULL));
135 // Now also include the capability with no CAP_EVENT.
136 EXPECT_OK(ppoll(cap_fd, kCapCount + 2, &ts, NULL));
137 EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
138 }
139