xref: /freebsd/contrib/capsicum-test/fcntl.cc (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 // Test that fcntl works in capability mode.
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/mman.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <stdint.h>
12 
13 #include <string>
14 #include <map>
15 
16 #include "capsicum.h"
17 #include "capsicum-test.h"
18 #include "syscalls.h"
19 
20 // Ensure that fcntl() works consistently for both regular file descriptors and
21 // capability-wrapped ones.
22 FORK_TEST(Fcntl, Basic) {
23   cap_rights_t rights;
24   cap_rights_init(&rights, CAP_READ, CAP_FCNTL);
25 
26   typedef std::map<std::string, int> FileMap;
27 
28   // Open some files of different types, and wrap them in capabilities.
29   FileMap files;
30   files["file"] = open("/etc/passwd", O_RDONLY);
31   EXPECT_OK(files["file"]);
32   files["socket"] = socket(PF_LOCAL, SOCK_STREAM, 0);
33   EXPECT_OK(files["socket"]);
34   char shm_name[128];
35   sprintf(shm_name, "/capsicum-test-%d", getuid());
36   files["SHM"] = shm_open(shm_name, (O_CREAT|O_RDWR), 0600);
37   if ((files["SHM"] == -1) && errno == ENOSYS) {
38     // shm_open() is not implemented in user-mode Linux.
39     files.erase("SHM");
40   } else {
41     EXPECT_OK(files["SHM"]);
42   }
43 
44   FileMap caps;
45   for (FileMap::iterator ii = files.begin(); ii != files.end(); ++ii) {
46     std::string key = ii->first + " cap";
47     caps[key] = dup(ii->second);
48     EXPECT_OK(cap_rights_limit(caps[key], &rights));
49     EXPECT_OK(caps[key]) << " on " << ii->first;
50   }
51 
52   FileMap all(files);
53   all.insert(files.begin(), files.end());
54 
55   EXPECT_OK(cap_enter());  // Enter capability mode.
56 
57   // Ensure that we can fcntl() all the files that we opened above.
58   cap_rights_t r_ro;
59   cap_rights_init(&r_ro, CAP_READ);
60   for (FileMap::iterator ii = all.begin(); ii != all.end(); ++ii) {
61     EXPECT_OK(fcntl(ii->second, F_GETFL, 0)) << " on " << ii->first;
62     int cap = dup(ii->second);
63     EXPECT_OK(cap) << " on " << ii->first;
64     EXPECT_OK(cap_rights_limit(cap, &r_ro)) << " on " << ii->first;
65     EXPECT_EQ(-1, fcntl(cap, F_GETFL, 0)) << " on " << ii->first;
66     EXPECT_EQ(ENOTCAPABLE, errno) << " on " << ii->first;
67     close(cap);
68   }
69   for (FileMap::iterator ii = all.begin(); ii != all.end(); ++ii) {
70     close(ii->second);
71   }
72   shm_unlink(shm_name);
73 }
74 
75 // Supported fcntl(2) operations:
76 //   FreeBSD10         FreeBSD9.1:  Linux:           Rights:            Summary:
77 //   F_DUPFD           F_DUPFD      F_DUPFD          NONE               as dup(2)
78 //   F_DUPFD_CLOEXEC                F_DUPFD_CLOEXEC  NONE               as dup(2) with close-on-exec
79 //   F_DUP2FD          F_DUP2FD                      NONE               as dup2(2)
80 //   F_DUP2FD_CLOEXEC                                NONE               as dup2(2) with close-on-exec
81 //   F_GETFD           F_GETFD      F_GETFD          NONE               get close-on-exec flag
82 //   F_SETFD           F_SETFD      F_SETFD          NONE               set close-on-exec flag
83 // * F_GETFL           F_GETFL      F_GETFL          FCNTL              get file status flag
84 // * F_SETFL           F_SETFL      F_SETFL          FCNTL              set file status flag
85 // * F_GETOWN          F_GETOWN     F_GETOWN         FCNTL              get pid receiving SIGIO/SIGURG
86 // * F_SETOWN          F_SETOWN     F_SETOWN         FCNTL              set pid receiving SIGIO/SIGURG
87 // *                                F_GETOWN_EX      FCNTL              get pid/thread receiving SIGIO/SIGURG
88 // *                                F_SETOWN_EX      FCNTL              set pid/thread receiving SIGIO/SIGURG
89 //   F_GETLK           F_GETLK      F_GETLK          FLOCK              get lock info
90 //   F_SETLK           F_SETLK      F_SETLK          FLOCK              set lock info
91 //   F_SETLK_REMOTE                                  FLOCK              set lock info
92 //   F_SETLKW          F_SETLKW     F_SETLKW         FLOCK              set lock info (blocking)
93 //   F_READAHEAD       F_READAHEAD                   NONE               set or clear readahead amount
94 //   F_RDAHEAD         F_RDAHEAD                     NONE               set or clear readahead amount to 128KB
95 //                                  F_GETSIG         POLL_EVENT+FSIGNAL get signal sent when I/O possible
96 //                                  F_SETSIG         POLL_EVENT+FSIGNAL set signal sent when I/O possible
97 //                                  F_GETLEASE       FLOCK+FSIGNAL      get lease on file descriptor
98 //                                  F_SETLEASE       FLOCK+FSIGNAL      set new lease on file descriptor
99 //                                  F_NOTIFY         NOTIFY             generate signal on changes (dnotify)
100 //                                  F_GETPIPE_SZ     GETSOCKOPT         get pipe size
101 //                                  F_SETPIPE_SZ     SETSOCKOPT         set pipe size
102 //                                  F_GET_SEAL       FSTAT              get memfd seals
103 //                                  F_ADD_SEAL       FCHMOD             set memfd seal
104 // If HAVE_CAP_FCNTLS_LIMIT is defined, then fcntl(2) operations that require
105 // CAP_FCNTL (marked with * above) can be further limited with cap_fcntls_limit(2).
106 namespace {
107 #define FCNTL_NUM_RIGHTS 9
108 cap_rights_t fcntl_rights[FCNTL_NUM_RIGHTS];
109 void InitRights() {
110   cap_rights_init(&(fcntl_rights[0]), 0);  // Later code assumes this is at [0]
111   cap_rights_init(&(fcntl_rights[1]), CAP_READ, CAP_WRITE);
112   cap_rights_init(&(fcntl_rights[2]), CAP_FCNTL);
113   cap_rights_init(&(fcntl_rights[3]), CAP_FLOCK);
114 #ifdef CAP_FSIGNAL
115   cap_rights_init(&(fcntl_rights[4]), CAP_EVENT, CAP_FSIGNAL);
116   cap_rights_init(&(fcntl_rights[5]), CAP_FLOCK, CAP_FSIGNAL);
117 #else
118   cap_rights_init(&(fcntl_rights[4]), 0);
119   cap_rights_init(&(fcntl_rights[5]), 0);
120 #endif
121 #ifdef CAP_NOTIFY
122   cap_rights_init(&(fcntl_rights[6]), CAP_NOTIFY);
123 #else
124   cap_rights_init(&(fcntl_rights[6]), 0);
125 #endif
126   cap_rights_init(&(fcntl_rights[7]), CAP_SETSOCKOPT);
127   cap_rights_init(&(fcntl_rights[8]), CAP_GETSOCKOPT);
128 }
129 
130 int CheckFcntl(unsigned long long right, int caps[FCNTL_NUM_RIGHTS], int cmd, long arg, const char* context) {
131   SCOPED_TRACE(context);
132   cap_rights_t rights;
133   cap_rights_init(&rights, right);
134   int ok_index = -1;
135   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
136     if (cap_rights_contains(&(fcntl_rights[ii]), &rights)) {
137       if (ok_index == -1) ok_index = ii;
138       continue;
139     }
140     EXPECT_NOTCAPABLE(fcntl(caps[ii], cmd, arg));
141   }
142   EXPECT_NE(-1, ok_index);
143   int rc = fcntl(caps[ok_index], cmd, arg);
144   EXPECT_OK(rc);
145   return rc;
146 }
147 }  // namespace
148 
149 #define CHECK_FCNTL(right, caps, cmd, arg) \
150     CheckFcntl(right, caps, cmd, arg, "fcntl(" #cmd ") expect " #right)
151 
152 TEST(Fcntl, Commands) {
153   InitRights();
154   int fd = open(TmpFile("cap_fcntl_cmds"), O_RDWR|O_CREAT, 0644);
155   EXPECT_OK(fd);
156   write(fd, "TEST", 4);
157   int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
158   EXPECT_OK(sock);
159   int caps[FCNTL_NUM_RIGHTS];
160   int sock_caps[FCNTL_NUM_RIGHTS];
161   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
162     caps[ii] = dup(fd);
163     EXPECT_OK(caps[ii]);
164     EXPECT_OK(cap_rights_limit(caps[ii], &(fcntl_rights[ii])));
165     sock_caps[ii] = dup(sock);
166     EXPECT_OK(sock_caps[ii]);
167     EXPECT_OK(cap_rights_limit(sock_caps[ii], &(fcntl_rights[ii])));
168   }
169 
170   // Check the things that need no rights against caps[0].
171   int newfd = fcntl(caps[0], F_DUPFD, 0);
172   EXPECT_OK(newfd);
173   // dup()'ed FD should have same rights.
174   cap_rights_t rights;
175   cap_rights_init(&rights, 0);
176   EXPECT_OK(cap_rights_get(newfd, &rights));
177   EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
178   close(newfd);
179 #ifdef HAVE_F_DUP2FD
180   EXPECT_OK(fcntl(caps[0], F_DUP2FD, newfd));
181   // dup2()'ed FD should have same rights.
182   EXPECT_OK(cap_rights_get(newfd, &rights));
183   EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
184   close(newfd);
185 #endif
186 
187   EXPECT_OK(fcntl(caps[0], F_GETFD, 0));
188   EXPECT_OK(fcntl(caps[0], F_SETFD, 0));
189 
190   // Check operations that need CAP_FCNTL.
191   int fd_flag = CHECK_FCNTL(CAP_FCNTL, caps, F_GETFL, 0);
192   EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, caps, F_SETFL, fd_flag));
193   int owner = CHECK_FCNTL(CAP_FCNTL, sock_caps, F_GETOWN, 0);
194   EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, sock_caps, F_SETOWN, owner));
195 
196   // Check an operation needing CAP_FLOCK.
197   struct flock fl;
198   memset(&fl, 0, sizeof(fl));
199   fl.l_type = F_RDLCK;
200   fl.l_whence = SEEK_SET;
201   fl.l_start = 0;
202   fl.l_len = 1;
203   EXPECT_EQ(0, CHECK_FCNTL(CAP_FLOCK, caps, F_GETLK, (long)&fl));
204 
205   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
206     close(sock_caps[ii]);
207     close(caps[ii]);
208   }
209   close(sock);
210   close(fd);
211   unlink(TmpFile("cap_fcntl_cmds"));
212 }
213 
214 TEST(Fcntl, WriteLock) {
215   int fd = open(TmpFile("cap_fcntl_readlock"), O_RDWR|O_CREAT, 0644);
216   EXPECT_OK(fd);
217   write(fd, "TEST", 4);
218 
219   int cap = dup(fd);
220   cap_rights_t rights;
221   cap_rights_init(&rights, CAP_FCNTL, CAP_READ, CAP_WRITE, CAP_FLOCK);
222   EXPECT_OK(cap_rights_limit(cap, &rights));
223 
224   struct flock fl;
225   memset(&fl, 0, sizeof(fl));
226   fl.l_type = F_WRLCK;
227   fl.l_whence = SEEK_SET;
228   fl.l_start = 0;
229   fl.l_len = 1;
230   // Write-Lock
231   EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
232 
233   // Check write-locked (from another process).
234   pid_t child = fork();
235   if (child == 0) {
236     fl.l_type = F_WRLCK;
237     fl.l_whence = SEEK_SET;
238     fl.l_start = 0;
239     fl.l_len = 1;
240     EXPECT_OK(fcntl(fd, F_GETLK, (long)&fl));
241     EXPECT_NE(F_UNLCK, fl.l_type);
242     exit(HasFailure());
243   }
244   int status;
245   EXPECT_EQ(child, waitpid(child, &status, 0));
246   int rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
247   EXPECT_EQ(0, rc);
248 
249   // Unlock
250   fl.l_type = F_UNLCK;
251   fl.l_whence = SEEK_SET;
252   fl.l_start = 0;
253   fl.l_len = 1;
254   EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
255 
256   close(cap);
257   close(fd);
258   unlink(TmpFile("cap_fcntl_readlock"));
259 }
260 
261 #ifdef HAVE_CAP_FCNTLS_LIMIT
262 TEST(Fcntl, SubRightNormalFD) {
263   int fd = open(TmpFile("cap_fcntl_subrightnorm"), O_RDWR|O_CREAT, 0644);
264   EXPECT_OK(fd);
265 
266   // Restrict the fcntl(2) subrights of a normal FD.
267   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
268   int fd_flag = fcntl(fd, F_GETFL, 0);
269   EXPECT_OK(fd_flag);
270   EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
271 
272   // Expect to have all capabilities.
273   cap_rights_t rights;
274   EXPECT_OK(cap_rights_get(fd, &rights));
275   cap_rights_t all;
276   CAP_SET_ALL(&all);
277   EXPECT_RIGHTS_EQ(&all, &rights);
278   cap_fcntl_t fcntls;
279   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
280   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
281 
282   // Can't widen the subrights.
283   EXPECT_NOTCAPABLE(cap_fcntls_limit(fd, CAP_FCNTL_GETFL|CAP_FCNTL_SETFL));
284 
285   close(fd);
286   unlink(TmpFile("cap_fcntl_subrightnorm"));
287 }
288 
289 TEST(Fcntl, PreserveSubRights) {
290   int fd = open(TmpFile("cap_fcntl_subrightpreserve"), O_RDWR|O_CREAT, 0644);
291   EXPECT_OK(fd);
292 
293   cap_rights_t rights;
294   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FCNTL);
295   EXPECT_OK(cap_rights_limit(fd, &rights));
296   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
297 
298   cap_rights_t cur_rights;
299   cap_fcntl_t fcntls;
300   EXPECT_OK(cap_rights_get(fd, &cur_rights));
301   EXPECT_RIGHTS_EQ(&rights, &cur_rights);
302   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
303   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
304 
305   // Limiting the top-level rights leaves the subrights unaffected...
306   cap_rights_clear(&rights, CAP_READ);
307   EXPECT_OK(cap_rights_limit(fd, &rights));
308   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
309   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
310 
311   // ... until we remove CAP_FCNTL.
312   cap_rights_clear(&rights, CAP_FCNTL);
313   EXPECT_OK(cap_rights_limit(fd, &rights));
314   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
315   EXPECT_EQ((cap_fcntl_t)0, fcntls);
316   EXPECT_EQ(-1, cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
317 
318   close(fd);
319   unlink(TmpFile("cap_fcntl_subrightpreserve"));
320 }
321 
322 TEST(Fcntl, FLSubRights) {
323   int fd = open(TmpFile("cap_fcntl_subrights"), O_RDWR|O_CREAT, 0644);
324   EXPECT_OK(fd);
325   write(fd, "TEST", 4);
326   cap_rights_t rights;
327   cap_rights_init(&rights, CAP_FCNTL);
328   EXPECT_OK(cap_rights_limit(fd, &rights));
329 
330   // Check operations that need CAP_FCNTL with subrights pristine => OK.
331   int fd_flag = fcntl(fd, F_GETFL, 0);
332   EXPECT_OK(fd_flag);
333   EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
334 
335   // Check operations that need CAP_FCNTL with all subrights => OK.
336   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_ALL));
337   fd_flag = fcntl(fd, F_GETFL, 0);
338   EXPECT_OK(fd_flag);
339   EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
340 
341   // Check operations that need CAP_FCNTL with specific subrights.
342   int fd_get = dup(fd);
343   int fd_set = dup(fd);
344   EXPECT_OK(cap_fcntls_limit(fd_get, CAP_FCNTL_GETFL));
345   EXPECT_OK(cap_fcntls_limit(fd_set, CAP_FCNTL_SETFL));
346 
347   fd_flag = fcntl(fd_get, F_GETFL, 0);
348   EXPECT_OK(fd_flag);
349   EXPECT_NOTCAPABLE(fcntl(fd_set, F_GETFL, 0));
350   EXPECT_OK(fcntl(fd_set, F_SETFL, fd_flag));
351   EXPECT_NOTCAPABLE(fcntl(fd_get, F_SETFL, fd_flag));
352   close(fd_get);
353   close(fd_set);
354 
355   // Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
356   EXPECT_OK(cap_fcntls_limit(fd, 0));
357   EXPECT_NOTCAPABLE(fcntl(fd, F_GETFL, 0));
358   EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
359 
360   close(fd);
361   unlink(TmpFile("cap_fcntl_subrights"));
362 }
363 
364 TEST(Fcntl, OWNSubRights) {
365   int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
366   EXPECT_OK(sock);
367   cap_rights_t rights;
368   cap_rights_init(&rights, CAP_FCNTL);
369   EXPECT_OK(cap_rights_limit(sock, &rights));
370 
371   // Check operations that need CAP_FCNTL with no subrights => OK.
372   int owner = fcntl(sock, F_GETOWN, 0);
373   EXPECT_OK(owner);
374   EXPECT_OK(fcntl(sock, F_SETOWN, owner));
375 
376   // Check operations that need CAP_FCNTL with all subrights => OK.
377   EXPECT_OK(cap_fcntls_limit(sock, CAP_FCNTL_ALL));
378   owner = fcntl(sock, F_GETOWN, 0);
379   EXPECT_OK(owner);
380   EXPECT_OK(fcntl(sock, F_SETOWN, owner));
381 
382   // Check operations that need CAP_FCNTL with specific subrights.
383   int sock_get = dup(sock);
384   int sock_set = dup(sock);
385   EXPECT_OK(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN));
386   EXPECT_OK(cap_fcntls_limit(sock_set, CAP_FCNTL_SETOWN));
387   owner = fcntl(sock_get, F_GETOWN, 0);
388   EXPECT_OK(owner);
389   EXPECT_NOTCAPABLE(fcntl(sock_set, F_GETOWN, 0));
390   EXPECT_OK(fcntl(sock_set, F_SETOWN, owner));
391   EXPECT_NOTCAPABLE(fcntl(sock_get, F_SETOWN, owner));
392   // Also check we can retrieve the subrights.
393   cap_fcntl_t fcntls;
394   EXPECT_OK(cap_fcntls_get(sock_get, &fcntls));
395   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETOWN, fcntls);
396   EXPECT_OK(cap_fcntls_get(sock_set, &fcntls));
397   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_SETOWN, fcntls);
398   // And that we can't widen the subrights.
399   EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
400   EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_set, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
401   close(sock_get);
402   close(sock_set);
403 
404   // Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
405   EXPECT_OK(cap_fcntls_limit(sock, 0));
406   EXPECT_NOTCAPABLE(fcntl(sock, F_GETOWN, 0));
407   EXPECT_NOTCAPABLE(fcntl(sock, F_SETOWN, owner));
408 
409   close(sock);
410 }
411 #endif
412