xref: /src/tests/sys/capsicum/fcntl.cc (revision fba81b33aabff74ad03d5f9f9663c176cf060fa6)
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.
FORK_TEST(Fcntl,Basic)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];
InitRights()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   cap_rights_init(&(fcntl_rights[4]), 0);
115   cap_rights_init(&(fcntl_rights[5]), 0);
116 #ifdef CAP_NOTIFY
117   cap_rights_init(&(fcntl_rights[6]), CAP_NOTIFY);
118 #else
119   cap_rights_init(&(fcntl_rights[6]), 0);
120 #endif
121   cap_rights_init(&(fcntl_rights[7]), CAP_SETSOCKOPT);
122   cap_rights_init(&(fcntl_rights[8]), CAP_GETSOCKOPT);
123 }
124 
CheckFcntl(unsigned long long right,int caps[FCNTL_NUM_RIGHTS],int cmd,long arg,const char * context)125 int CheckFcntl(unsigned long long right, int caps[FCNTL_NUM_RIGHTS], int cmd, long arg, const char* context) {
126   SCOPED_TRACE(context);
127   cap_rights_t rights;
128   cap_rights_init(&rights, right);
129   int ok_index = -1;
130   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
131     if (cap_rights_contains(&(fcntl_rights[ii]), &rights)) {
132       if (ok_index == -1) ok_index = ii;
133       continue;
134     }
135     EXPECT_NOTCAPABLE(fcntl(caps[ii], cmd, arg));
136   }
137   EXPECT_NE(-1, ok_index);
138   int rc = fcntl(caps[ok_index], cmd, arg);
139   EXPECT_OK(rc);
140   return rc;
141 }
142 }  // namespace
143 
144 #define CHECK_FCNTL(right, caps, cmd, arg) \
145     CheckFcntl(right, caps, cmd, arg, "fcntl(" #cmd ") expect " #right)
146 
TEST(Fcntl,Commands)147 TEST(Fcntl, Commands) {
148   InitRights();
149   int fd = open(TmpFile("cap_fcntl_cmds"), O_RDWR|O_CREAT, 0644);
150   EXPECT_OK(fd);
151   write(fd, "TEST", 4);
152   int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
153   EXPECT_OK(sock);
154   int caps[FCNTL_NUM_RIGHTS];
155   int sock_caps[FCNTL_NUM_RIGHTS];
156   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
157     caps[ii] = dup(fd);
158     EXPECT_OK(caps[ii]);
159     EXPECT_OK(cap_rights_limit(caps[ii], &(fcntl_rights[ii])));
160     sock_caps[ii] = dup(sock);
161     EXPECT_OK(sock_caps[ii]);
162     EXPECT_OK(cap_rights_limit(sock_caps[ii], &(fcntl_rights[ii])));
163   }
164 
165   // Check the things that need no rights against caps[0].
166   int newfd = fcntl(caps[0], F_DUPFD, 0);
167   EXPECT_OK(newfd);
168   // dup()'ed FD should have same rights.
169   cap_rights_t rights;
170   cap_rights_init(&rights, 0);
171   EXPECT_OK(cap_rights_get(newfd, &rights));
172   EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
173   close(newfd);
174   EXPECT_OK(fcntl(caps[0], F_DUP2FD, newfd));
175   // dup2()'ed FD should have same rights.
176   EXPECT_OK(cap_rights_get(newfd, &rights));
177   EXPECT_RIGHTS_EQ(&(fcntl_rights[0]), &rights);
178   close(newfd);
179 
180   EXPECT_OK(fcntl(caps[0], F_GETFD, 0));
181   EXPECT_OK(fcntl(caps[0], F_SETFD, 0));
182 
183   // Check operations that need CAP_FCNTL.
184   int fd_flag = CHECK_FCNTL(CAP_FCNTL, caps, F_GETFL, 0);
185   EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, caps, F_SETFL, fd_flag));
186   int owner = CHECK_FCNTL(CAP_FCNTL, sock_caps, F_GETOWN, 0);
187   EXPECT_EQ(0, CHECK_FCNTL(CAP_FCNTL, sock_caps, F_SETOWN, owner));
188 
189   // Check an operation needing CAP_FLOCK.
190   struct flock fl;
191   memset(&fl, 0, sizeof(fl));
192   fl.l_type = F_RDLCK;
193   fl.l_whence = SEEK_SET;
194   fl.l_start = 0;
195   fl.l_len = 1;
196   EXPECT_EQ(0, CHECK_FCNTL(CAP_FLOCK, caps, F_GETLK, (long)&fl));
197 
198   for (int ii = 0; ii < FCNTL_NUM_RIGHTS; ++ii) {
199     close(sock_caps[ii]);
200     close(caps[ii]);
201   }
202   close(sock);
203   close(fd);
204   unlink(TmpFile("cap_fcntl_cmds"));
205 }
206 
TEST(Fcntl,WriteLock)207 TEST(Fcntl, WriteLock) {
208   int fd = open(TmpFile("cap_fcntl_readlock"), O_RDWR|O_CREAT, 0644);
209   EXPECT_OK(fd);
210   write(fd, "TEST", 4);
211 
212   int cap = dup(fd);
213   cap_rights_t rights;
214   cap_rights_init(&rights, CAP_FCNTL, CAP_READ, CAP_WRITE, CAP_FLOCK);
215   EXPECT_OK(cap_rights_limit(cap, &rights));
216 
217   struct flock fl;
218   memset(&fl, 0, sizeof(fl));
219   fl.l_type = F_WRLCK;
220   fl.l_whence = SEEK_SET;
221   fl.l_start = 0;
222   fl.l_len = 1;
223   // Write-Lock
224   EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
225 
226   // Check write-locked (from another process).
227   pid_t child = fork();
228   if (child == 0) {
229     fl.l_type = F_WRLCK;
230     fl.l_whence = SEEK_SET;
231     fl.l_start = 0;
232     fl.l_len = 1;
233     EXPECT_OK(fcntl(fd, F_GETLK, (long)&fl));
234     EXPECT_NE(F_UNLCK, fl.l_type);
235     exit(HasFailure());
236   }
237   int status;
238   EXPECT_EQ(child, waitpid(child, &status, 0));
239   int rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
240   EXPECT_EQ(0, rc);
241 
242   // Unlock
243   fl.l_type = F_UNLCK;
244   fl.l_whence = SEEK_SET;
245   fl.l_start = 0;
246   fl.l_len = 1;
247   EXPECT_OK(fcntl(cap, F_SETLK, (long)&fl));
248 
249   close(cap);
250   close(fd);
251   unlink(TmpFile("cap_fcntl_readlock"));
252 }
253 
TEST(Fcntl,SubRightNormalFD)254 TEST(Fcntl, SubRightNormalFD) {
255   int fd = open(TmpFile("cap_fcntl_subrightnorm"), O_RDWR|O_CREAT, 0644);
256   EXPECT_OK(fd);
257 
258   // Restrict the fcntl(2) subrights of a normal FD.
259   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
260   int fd_flag = fcntl(fd, F_GETFL, 0);
261   EXPECT_OK(fd_flag);
262   EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
263 
264   // Expect to have all capabilities.
265   cap_rights_t rights;
266   EXPECT_OK(cap_rights_get(fd, &rights));
267   cap_rights_t all;
268   CAP_ALL(&all);
269   EXPECT_RIGHTS_EQ(&all, &rights);
270   cap_fcntl_t fcntls;
271   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
272   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
273 
274   // Can't widen the subrights.
275   EXPECT_NOTCAPABLE(cap_fcntls_limit(fd, CAP_FCNTL_GETFL|CAP_FCNTL_SETFL));
276 
277   close(fd);
278   unlink(TmpFile("cap_fcntl_subrightnorm"));
279 }
280 
TEST(Fcntl,PreserveSubRights)281 TEST(Fcntl, PreserveSubRights) {
282   int fd = open(TmpFile("cap_fcntl_subrightpreserve"), O_RDWR|O_CREAT, 0644);
283   EXPECT_OK(fd);
284 
285   cap_rights_t rights;
286   cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FCNTL);
287   EXPECT_OK(cap_rights_limit(fd, &rights));
288   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
289 
290   cap_rights_t cur_rights;
291   cap_fcntl_t fcntls;
292   EXPECT_OK(cap_rights_get(fd, &cur_rights));
293   EXPECT_RIGHTS_EQ(&rights, &cur_rights);
294   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
295   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
296 
297   // Limiting the top-level rights leaves the subrights unaffected...
298   cap_rights_clear(&rights, CAP_READ);
299   EXPECT_OK(cap_rights_limit(fd, &rights));
300   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
301   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETFL, fcntls);
302 
303   // ... until we remove CAP_FCNTL.
304   cap_rights_clear(&rights, CAP_FCNTL);
305   EXPECT_OK(cap_rights_limit(fd, &rights));
306   EXPECT_OK(cap_fcntls_get(fd, &fcntls));
307   EXPECT_EQ((cap_fcntl_t)0, fcntls);
308   EXPECT_EQ(-1, cap_fcntls_limit(fd, CAP_FCNTL_GETFL));
309 
310   close(fd);
311   unlink(TmpFile("cap_fcntl_subrightpreserve"));
312 }
313 
TEST(Fcntl,FLSubRights)314 TEST(Fcntl, FLSubRights) {
315   int fd = open(TmpFile("cap_fcntl_subrights"), O_RDWR|O_CREAT, 0644);
316   EXPECT_OK(fd);
317   write(fd, "TEST", 4);
318   cap_rights_t rights;
319   cap_rights_init(&rights, CAP_FCNTL);
320   EXPECT_OK(cap_rights_limit(fd, &rights));
321 
322   // Check operations that need CAP_FCNTL with subrights pristine => OK.
323   int fd_flag = fcntl(fd, F_GETFL, 0);
324   EXPECT_OK(fd_flag);
325   EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
326 
327   // Check operations that need CAP_FCNTL with all subrights => OK.
328   EXPECT_OK(cap_fcntls_limit(fd, CAP_FCNTL_ALL));
329   fd_flag = fcntl(fd, F_GETFL, 0);
330   EXPECT_OK(fd_flag);
331   EXPECT_OK(fcntl(fd, F_SETFL, fd_flag));
332 
333   // Check operations that need CAP_FCNTL with specific subrights.
334   int fd_get = dup(fd);
335   int fd_set = dup(fd);
336   EXPECT_OK(cap_fcntls_limit(fd_get, CAP_FCNTL_GETFL));
337   EXPECT_OK(cap_fcntls_limit(fd_set, CAP_FCNTL_SETFL));
338 
339   fd_flag = fcntl(fd_get, F_GETFL, 0);
340   EXPECT_OK(fd_flag);
341   EXPECT_NOTCAPABLE(fcntl(fd_set, F_GETFL, 0));
342   EXPECT_OK(fcntl(fd_set, F_SETFL, fd_flag));
343   EXPECT_NOTCAPABLE(fcntl(fd_get, F_SETFL, fd_flag));
344   close(fd_get);
345   close(fd_set);
346 
347   // Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
348   EXPECT_OK(cap_fcntls_limit(fd, 0));
349   EXPECT_NOTCAPABLE(fcntl(fd, F_GETFL, 0));
350   EXPECT_NOTCAPABLE(fcntl(fd, F_SETFL, fd_flag));
351 
352   close(fd);
353   unlink(TmpFile("cap_fcntl_subrights"));
354 }
355 
TEST(Fcntl,OWNSubRights)356 TEST(Fcntl, OWNSubRights) {
357   int sock = socket(PF_LOCAL, SOCK_STREAM, 0);
358   EXPECT_OK(sock);
359   cap_rights_t rights;
360   cap_rights_init(&rights, CAP_FCNTL);
361   EXPECT_OK(cap_rights_limit(sock, &rights));
362 
363   // Check operations that need CAP_FCNTL with no subrights => OK.
364   int owner = fcntl(sock, F_GETOWN, 0);
365   EXPECT_OK(owner);
366   EXPECT_OK(fcntl(sock, F_SETOWN, owner));
367 
368   // Check operations that need CAP_FCNTL with all subrights => OK.
369   EXPECT_OK(cap_fcntls_limit(sock, CAP_FCNTL_ALL));
370   owner = fcntl(sock, F_GETOWN, 0);
371   EXPECT_OK(owner);
372   EXPECT_OK(fcntl(sock, F_SETOWN, owner));
373 
374   // Check operations that need CAP_FCNTL with specific subrights.
375   int sock_get = dup(sock);
376   int sock_set = dup(sock);
377   EXPECT_OK(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN));
378   EXPECT_OK(cap_fcntls_limit(sock_set, CAP_FCNTL_SETOWN));
379   owner = fcntl(sock_get, F_GETOWN, 0);
380   EXPECT_OK(owner);
381   EXPECT_NOTCAPABLE(fcntl(sock_set, F_GETOWN, 0));
382   EXPECT_OK(fcntl(sock_set, F_SETOWN, owner));
383   EXPECT_NOTCAPABLE(fcntl(sock_get, F_SETOWN, owner));
384   // Also check we can retrieve the subrights.
385   cap_fcntl_t fcntls;
386   EXPECT_OK(cap_fcntls_get(sock_get, &fcntls));
387   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_GETOWN, fcntls);
388   EXPECT_OK(cap_fcntls_get(sock_set, &fcntls));
389   EXPECT_EQ((cap_fcntl_t)CAP_FCNTL_SETOWN, fcntls);
390   // And that we can't widen the subrights.
391   EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_get, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
392   EXPECT_NOTCAPABLE(cap_fcntls_limit(sock_set, CAP_FCNTL_GETOWN|CAP_FCNTL_SETOWN));
393   close(sock_get);
394   close(sock_set);
395 
396   // Check operations that need CAP_FCNTL with no subrights => ENOTCAPABLE.
397   EXPECT_OK(cap_fcntls_limit(sock, 0));
398   EXPECT_NOTCAPABLE(fcntl(sock, F_GETOWN, 0));
399   EXPECT_NOTCAPABLE(fcntl(sock, F_SETOWN, owner));
400 
401   close(sock);
402 }
403