aboutsummaryrefslogtreecommitdiff
path: root/contrib/capsicum-test/select.cc
blob: 3fa02c639f032a7442362fbc89c0e040fce862ce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>

#include "capsicum.h"
#include "syscalls.h"
#include "capsicum-test.h"

namespace {

int AddFDToSet(fd_set* fset, int fd, int maxfd) {
  FD_SET(fd, fset);
  if (fd > maxfd) maxfd = fd;
  return maxfd;
}

int InitFDSet(fd_set* fset, int *fds, int fdcount) {
  FD_ZERO(fset);
  int maxfd = -1;
  for (int ii = 0; ii < fdcount; ii++) {
    maxfd = AddFDToSet(fset, fds[ii], maxfd);
  }
  return maxfd;
}

}  // namespace

FORK_TEST_ON(Select, LotsOFileDescriptors, TmpFile("cap_select")) {
  int fd = open(TmpFile("cap_select"), O_RDWR | O_CREAT, 0644);
  EXPECT_OK(fd);
  if (fd < 0) return;

  // Create many POLL_EVENT capabilities.
  const int kCapCount = 64;
  int cap_fd[kCapCount];
  cap_rights_t r_poll;
  cap_rights_init(&r_poll, CAP_EVENT);
  for (int ii = 0; ii < kCapCount; ii++) {
    cap_fd[ii] = dup(fd);
    EXPECT_OK(cap_fd[ii]);
    EXPECT_OK(cap_rights_limit(cap_fd[ii], &r_poll));
  }
  cap_rights_t r_rw;
  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE, CAP_SEEK);
  int cap_rw = dup(fd);
  EXPECT_OK(cap_rw);
  EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));

  EXPECT_OK(cap_enter());  // Enter capability mode

  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = 100;
  // Add normal file descriptor and all CAP_EVENT capabilities
  fd_set rset;
  fd_set wset;
  int maxfd = InitFDSet(&rset, cap_fd, kCapCount);
  maxfd = AddFDToSet(&rset, fd, maxfd);
  InitFDSet(&wset, cap_fd, kCapCount);
  AddFDToSet(&rset, fd, 0);
  int ret = select(maxfd+1, &rset, &wset, NULL, &tv);
  EXPECT_OK(ret);

  // Now also include the capability with no CAP_EVENT.
  InitFDSet(&rset, cap_fd, kCapCount);
  AddFDToSet(&rset, fd, maxfd);
  maxfd = AddFDToSet(&rset, cap_rw, maxfd);
  InitFDSet(&wset, cap_fd, kCapCount);
  AddFDToSet(&wset, fd, maxfd);
  AddFDToSet(&wset, cap_rw, maxfd);
  ret = select(maxfd+1, &rset, &wset, NULL, &tv);
  EXPECT_NOTCAPABLE(ret);

#ifdef HAVE_PSELECT
  // And again with pselect
  struct timespec ts;
  ts.tv_sec = 0;
  ts.tv_nsec = 100000;
  maxfd = InitFDSet(&rset, cap_fd, kCapCount);
  maxfd = AddFDToSet(&rset, fd, maxfd);
  InitFDSet(&wset, cap_fd, kCapCount);
  AddFDToSet(&rset, fd, 0);
  ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
  EXPECT_OK(ret);

  InitFDSet(&rset, cap_fd, kCapCount);
  AddFDToSet(&rset, fd, maxfd);
  maxfd = AddFDToSet(&rset, cap_rw, maxfd);
  InitFDSet(&wset, cap_fd, kCapCount);
  AddFDToSet(&wset, fd, maxfd);
  AddFDToSet(&wset, cap_rw, maxfd);
  ret = pselect(maxfd+1, &rset, &wset, NULL, &ts, NULL);
  EXPECT_NOTCAPABLE(ret);
#endif
}

FORK_TEST_ON(Poll, LotsOFileDescriptors, TmpFile("cap_poll")) {
  int fd = open(TmpFile("cap_poll"), O_RDWR | O_CREAT, 0644);
  EXPECT_OK(fd);
  if (fd < 0) return;

  // Create many POLL_EVENT capabilities.
  const int kCapCount = 64;
  struct pollfd cap_fd[kCapCount + 2];
  cap_rights_t r_poll;
  cap_rights_init(&r_poll, CAP_EVENT);
  for (int ii = 0; ii < kCapCount; ii++) {
    cap_fd[ii].fd = dup(fd);
    EXPECT_OK(cap_fd[ii].fd);
    EXPECT_OK(cap_rights_limit(cap_fd[ii].fd, &r_poll));
    cap_fd[ii].events = POLLIN|POLLOUT;
  }
  cap_fd[kCapCount].fd = fd;
  cap_fd[kCapCount].events = POLLIN|POLLOUT;
  cap_rights_t r_rw;
  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE, CAP_SEEK);
  int cap_rw = dup(fd);
  EXPECT_OK(cap_rw);
  EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
  cap_fd[kCapCount + 1].fd = cap_rw;
  cap_fd[kCapCount + 1].events = POLLIN|POLLOUT;

  EXPECT_OK(cap_enter());  // Enter capability mode

  EXPECT_OK(poll(cap_fd, kCapCount + 1, 10));
  // Now also include the capability with no CAP_EVENT.
  EXPECT_OK(poll(cap_fd, kCapCount + 2, 10));
  EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));

#ifdef HAVE_PPOLL
  // And again with ppoll
  struct timespec ts;
  ts.tv_sec = 0;
  ts.tv_nsec = 100000;
  EXPECT_OK(ppoll(cap_fd, kCapCount + 1, &ts, NULL));
  // Now also include the capability with no CAP_EVENT.
  EXPECT_OK(ppoll(cap_fd, kCapCount + 2, &ts, NULL));
  EXPECT_NE(0, (cap_fd[kCapCount + 1].revents & POLLNVAL));
#endif
}