xref: /freebsd/contrib/capsicum-test/ioctl.cc (revision cab6a39d7b343596a5823e65c0f7b426551ec22d)
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