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