Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/capsicum-test/ioctl.cc
39475 views
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.
13
TEST(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
40
TEST(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
72
TEST(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
110
TEST(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
190
TEST(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
211
TEST(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
236