1// Test that ioctl works in capability mode.
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <sys/socket.h>
5#include <fcntl.h>
6#include <sys/ioctl.h>
7
8#include "capsicum.h"
9#include "capsicum-test.h"
10
11// Ensure that ioctl() works consistently for both regular file descriptors and
12// capability-wrapped ones.
13TEST(Ioctl, Basic) {
14  cap_rights_t rights_ioctl;
15  cap_rights_init(&rights_ioctl, CAP_IOCTL);
16  cap_rights_t rights_many;
17  cap_rights_init(&rights_many, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT, CAP_FSYNC);
18
19  int fd = open("/etc/passwd", O_RDONLY);
20  EXPECT_OK(fd);
21  int fd_no = dup(fd);
22  EXPECT_OK(fd_no);
23  EXPECT_OK(cap_rights_limit(fd, &rights_ioctl));
24  EXPECT_OK(cap_rights_limit(fd_no, &rights_many));
25
26  // Check that CAP_IOCTL is required.
27  int bytes;
28  EXPECT_OK(ioctl(fd, FIONREAD, &bytes));
29  EXPECT_NOTCAPABLE(ioctl(fd_no, FIONREAD, &bytes));
30
31  int one = 1;
32  EXPECT_OK(ioctl(fd, FIOCLEX, &one));
33  EXPECT_NOTCAPABLE(ioctl(fd_no, FIOCLEX, &one));
34
35  close(fd);
36  close(fd_no);
37}
38
39#ifdef HAVE_CAP_IOCTLS_LIMIT
40TEST(Ioctl, SubRightNormalFD) {
41  int fd = open("/etc/passwd", O_RDONLY);
42  EXPECT_OK(fd);
43
44  // Restrict the ioctl(2) subrights of a normal FD.
45  cap_ioctl_t ioctl_nread = FIONREAD;
46  EXPECT_OK(cap_ioctls_limit(fd, &ioctl_nread, 1));
47  int bytes;
48  EXPECT_OK(ioctl(fd, FIONREAD, &bytes));
49  int one = 1;
50  EXPECT_NOTCAPABLE(ioctl(fd, FIOCLEX, &one));
51
52  // Expect to have all primary rights.
53  cap_rights_t rights;
54  EXPECT_OK(cap_rights_get(fd, &rights));
55  cap_rights_t all;
56  CAP_SET_ALL(&all);
57  EXPECT_RIGHTS_EQ(&all, &rights);
58  cap_ioctl_t ioctls[16];
59  memset(ioctls, 0, sizeof(ioctls));
60  ssize_t nioctls = cap_ioctls_get(fd, ioctls, 16);
61  EXPECT_OK(nioctls);
62  EXPECT_EQ(1, nioctls);
63  EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]);
64
65  // Can't widen the subrights.
66  cap_ioctl_t both_ioctls[2] = {FIONREAD, FIOCLEX};
67  EXPECT_NOTCAPABLE(cap_ioctls_limit(fd, both_ioctls, 2));
68
69  close(fd);
70}
71
72TEST(Ioctl, PreserveSubRights) {
73  int fd = open("/etc/passwd", O_RDONLY);
74  EXPECT_OK(fd);
75  cap_rights_t rights;
76  cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_IOCTL);
77  EXPECT_OK(cap_rights_limit(fd, &rights));
78  cap_ioctl_t ioctl_nread = FIONREAD;
79  EXPECT_OK(cap_ioctls_limit(fd, &ioctl_nread, 1));
80
81  cap_rights_t cur_rights;
82  cap_ioctl_t ioctls[16];
83  ssize_t nioctls;
84  EXPECT_OK(cap_rights_get(fd, &cur_rights));
85  EXPECT_RIGHTS_EQ(&rights, &cur_rights);
86  nioctls = cap_ioctls_get(fd, ioctls, 16);
87  EXPECT_OK(nioctls);
88  EXPECT_EQ(1, nioctls);
89  EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]);
90
91  // Limiting the top-level rights leaves the subrights unaffected...
92  cap_rights_clear(&rights, CAP_READ);
93  EXPECT_OK(cap_rights_limit(fd, &rights));
94  nioctls = cap_ioctls_get(fd, ioctls, 16);
95  EXPECT_OK(nioctls);
96  EXPECT_EQ(1, nioctls);
97  EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]);
98
99  // ... until we remove CAP_IOCTL
100  cap_rights_clear(&rights, CAP_IOCTL);
101  EXPECT_OK(cap_rights_limit(fd, &rights));
102  nioctls = cap_ioctls_get(fd, ioctls, 16);
103  EXPECT_OK(nioctls);
104  EXPECT_EQ(0, nioctls);
105  EXPECT_EQ(-1, cap_ioctls_limit(fd, &ioctl_nread, 1));
106
107  close(fd);
108}
109
110TEST(Ioctl, SubRights) {
111  int fd = open("/etc/passwd", O_RDONLY);
112  EXPECT_OK(fd);
113
114  cap_ioctl_t ioctls[16];
115  ssize_t nioctls;
116  memset(ioctls, 0, sizeof(ioctls));
117  nioctls = cap_ioctls_get(fd, ioctls, 16);
118  EXPECT_OK(nioctls);
119  EXPECT_EQ(CAP_IOCTLS_ALL, nioctls);
120
121  cap_rights_t rights_ioctl;
122  cap_rights_init(&rights_ioctl, CAP_IOCTL);
123  EXPECT_OK(cap_rights_limit(fd, &rights_ioctl));
124
125  nioctls = cap_ioctls_get(fd, ioctls, 16);
126  EXPECT_OK(nioctls);
127  EXPECT_EQ(CAP_IOCTLS_ALL, nioctls);
128
129  // Check operations that need CAP_IOCTL with subrights pristine => OK.
130  int bytes;
131  EXPECT_OK(ioctl(fd, FIONREAD, &bytes));
132  int one = 1;
133  EXPECT_OK(ioctl(fd, FIOCLEX, &one));
134
135  // Check operations that need CAP_IOCTL with all relevant subrights => OK.
136  cap_ioctl_t both_ioctls[2] = {FIONREAD, FIOCLEX};
137  EXPECT_OK(cap_ioctls_limit(fd, both_ioctls, 2));
138  EXPECT_OK(ioctl(fd, FIONREAD, &bytes));
139  EXPECT_OK(ioctl(fd, FIOCLEX, &one));
140
141
142  // Check what happens if we ask for subrights but don't have the space for them.
143  cap_ioctl_t before = 0xBBBBBBBB;
144  cap_ioctl_t one_ioctl = 0;
145  cap_ioctl_t after = 0xAAAAAAAA;
146  nioctls = cap_ioctls_get(fd, &one_ioctl, 1);
147  EXPECT_EQ(2, nioctls);
148  EXPECT_EQ(0xBBBBBBBB, before);
149  EXPECT_TRUE(one_ioctl == FIONREAD || one_ioctl == FIOCLEX);
150  EXPECT_EQ(0xAAAAAAAA, after);
151
152  // Check operations that need CAP_IOCTL with particular subrights.
153  int fd_nread = dup(fd);
154  int fd_clex = dup(fd);
155  cap_ioctl_t ioctl_nread = FIONREAD;
156  cap_ioctl_t ioctl_clex = FIOCLEX;
157  EXPECT_OK(cap_ioctls_limit(fd_nread, &ioctl_nread, 1));
158  EXPECT_OK(cap_ioctls_limit(fd_clex, &ioctl_clex, 1));
159  EXPECT_OK(ioctl(fd_nread, FIONREAD, &bytes));
160  EXPECT_NOTCAPABLE(ioctl(fd_clex, FIONREAD, &bytes));
161  EXPECT_OK(ioctl(fd_clex, FIOCLEX, &one));
162  EXPECT_NOTCAPABLE(ioctl(fd_nread, FIOCLEX, &one));
163
164  // Also check we can retrieve the subrights.
165  memset(ioctls, 0, sizeof(ioctls));
166  nioctls = cap_ioctls_get(fd_nread, ioctls, 16);
167  EXPECT_OK(nioctls);
168  EXPECT_EQ(1, nioctls);
169  EXPECT_EQ((cap_ioctl_t)FIONREAD, ioctls[0]);
170  memset(ioctls, 0, sizeof(ioctls));
171  nioctls = cap_ioctls_get(fd_clex, ioctls, 16);
172  EXPECT_OK(nioctls);
173  EXPECT_EQ(1, nioctls);
174  EXPECT_EQ((cap_ioctl_t)FIOCLEX, ioctls[0]);
175  // And that we can't widen the subrights.
176  EXPECT_NOTCAPABLE(cap_ioctls_limit(fd_nread, both_ioctls, 2));
177  EXPECT_NOTCAPABLE(cap_ioctls_limit(fd_clex, both_ioctls, 2));
178  close(fd_nread);
179  close(fd_clex);
180
181  // Check operations that need CAP_IOCTL with no subrights => ENOTCAPABLE.
182  EXPECT_OK(cap_ioctls_limit(fd, NULL, 0));
183  EXPECT_NOTCAPABLE(ioctl(fd, FIONREAD, &bytes));
184  EXPECT_NOTCAPABLE(ioctl(fd, FIOCLEX, &one));
185
186  close(fd);
187}
188
189#ifdef CAP_IOCTLS_LIMIT_MAX
190TEST(Ioctl, TooManySubRights) {
191  int fd = open("/etc/passwd", O_RDONLY);
192  EXPECT_OK(fd);
193
194  cap_ioctl_t ioctls[CAP_IOCTLS_LIMIT_MAX + 1];
195  for (int ii = 0; ii <= CAP_IOCTLS_LIMIT_MAX; ii++) {
196    ioctls[ii] = ii + 1;
197  }
198
199  cap_rights_t rights_ioctl;
200  cap_rights_init(&rights_ioctl, CAP_IOCTL);
201  EXPECT_OK(cap_rights_limit(fd, &rights_ioctl));
202
203  // Can only limit to a certain number of ioctls
204  EXPECT_EQ(-1, cap_ioctls_limit(fd, ioctls, CAP_IOCTLS_LIMIT_MAX + 1));
205  EXPECT_EQ(EINVAL, errno);
206  EXPECT_OK(cap_ioctls_limit(fd, ioctls, CAP_IOCTLS_LIMIT_MAX));
207
208  close(fd);
209}
210#else
211TEST(Ioctl, ManySubRights) {
212  int fd = open("/etc/passwd", O_RDONLY);
213  EXPECT_OK(fd);
214
215  const int nioctls = 150000;
216  cap_ioctl_t* ioctls = (cap_ioctl_t*)calloc(nioctls, sizeof(cap_ioctl_t));
217  for (int ii = 0; ii < nioctls; ii++) {
218    ioctls[ii] = ii + 1;
219  }
220
221  cap_rights_t rights_ioctl;
222  cap_rights_init(&rights_ioctl, CAP_IOCTL);
223  EXPECT_OK(cap_rights_limit(fd, &rights_ioctl));
224
225  EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls));
226  // Limit to a subset; if this takes a long time then there's an
227  // O(N^2) implementation of the ioctl list comparison.
228  EXPECT_OK(cap_ioctls_limit(fd, ioctls, nioctls - 1));
229
230  close(fd);
231}
232#endif
233
234#endif
235