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 #ifdef HAVE_PSELECT
77 // And again with pselect
78 struct timespec ts;
79 ts.tv_sec = 0;
80 ts.tv_nsec = 100000;
81 maxfd = InitFDSet(&rset, cap_fd, kCapCount);
82 maxfd = AddFDToSet(&rset, fd, maxfd);
83 InitFDSet(&wset, cap_fd, kCapCount);
84 AddFDToSet(&rset, fd, 0);
85 ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
86 EXPECT_OK(ret);
87
88 InitFDSet(&rset, cap_fd, kCapCount);
89 AddFDToSet(&rset, fd, maxfd);
90 maxfd = AddFDToSet(&rset, cap_rw, maxfd);
91 InitFDSet(&wset, cap_fd, kCapCount);
92 AddFDToSet(&wset, fd, maxfd);
93 AddFDToSet(&wset, cap_rw, maxfd);
94 ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
95 EXPECT_NOTCAPABLE(ret);
96 #endif
97 }
98
99 FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
100 int fd = open(TmpFile("cap_poll"), O_RDWR | O_CREAT, 0644);
101 EXPECT_OK(fd);
102 if (fd < 0) return;
103
104 // Create many POLL_EVENT capabilities.
105 const int kCapCount = 64;
106 struct pollfd cap_fd[kCapCount + 2];
107 cap_rights_t r_poll;
108 cap_rights_init(&r_poll, CAP_EVENT);
109 for (int ii = 0; ii < kCapCount; ii++) {
110 cap_fd[ii].fd = dup(fd);
111 EXPECT_OK(cap_fd[ii].fd);
112 EXPECT_OK(cap_rights_limit(cap_fd[ii].fd, &r_poll));
113 cap_fd[ii].events = POLLIN|POLLOUT;
114 }
115 cap_fd[kCapCount].fd = fd;
116 cap_fd[kCapCount].events = POLLIN|POLLOUT;
117 cap_rights_t r_rw;
118 cap_rights_init(&r_rw, CAP_READ, CAP_WRITE, CAP_SEEK);
119 int cap_rw = dup(fd);
120 EXPECT_OK(cap_rw);
121 EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
122 cap_fd[kCapCount + 1].fd = cap_rw;
123 cap_fd[kCapCount + 1].events = POLLIN|POLLOUT;
124
125 EXPECT_OK(cap_enter()); // Enter capability mode
126
127 EXPECT_OK(poll(cap_fd, kCapCount + 1, 10));
128 // Now also include the capability with no CAP_EVENT.
129 EXPECT_OK(poll(cap_fd, kCapCount + 2, 10));
130 EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
131
132 #ifdef HAVE_PPOLL
133 // And again with ppoll
134 struct timespec ts;
135 ts.tv_sec = 0;
136 ts.tv_nsec = 100000;
137 EXPECT_OK(ppoll(cap_fd, kCapCount + 1, &ts, NULL));
138 // Now also include the capability with no CAP_EVENT.
139 EXPECT_OK(ppoll(cap_fd, kCapCount + 2, &ts, NULL));
140 EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
141 #endif
142 }
143