1// Tests involving 2 capability file descriptors.
2#include <sys/types.h>
3#include <sys/socket.h>
4#include <fcntl.h>
5
6#include "capsicum.h"
7#include "syscalls.h"
8#include "capsicum-test.h"
9
10TEST(CapabilityPair, sendfile) {
11  int in_fd = open(TmpFile("cap_sendfile_in"), O_CREAT|O_RDWR, 0644);
12  EXPECT_OK(write(in_fd, "1234", 4));
13  // Output fd for sendfile must be a stream socket in FreeBSD.
14  int sock_fds[2];
15  EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds));
16
17  cap_rights_t r_rs;
18  cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
19  cap_rights_t r_ws;
20  cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
21
22  int cap_in_ro = dup(in_fd);
23  EXPECT_OK(cap_in_ro);
24  EXPECT_OK(cap_rights_limit(cap_in_ro, &r_rs));
25  int cap_in_wo = dup(in_fd);
26  EXPECT_OK(cap_in_wo);
27  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_ws));
28  int cap_out_ro = dup(sock_fds[0]);
29  EXPECT_OK(cap_out_ro);
30  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_rs));
31  int cap_out_wo = dup(sock_fds[0]);
32  EXPECT_OK(cap_out_wo);
33  EXPECT_OK(cap_rights_limit(cap_out_wo, &r_ws));
34
35  off_t offset = 0;
36  EXPECT_NOTCAPABLE(sendfile_(cap_out_ro, cap_in_ro, &offset, 4));
37  EXPECT_NOTCAPABLE(sendfile_(cap_out_wo, cap_in_wo, &offset, 4));
38  EXPECT_OK(sendfile_(cap_out_wo, cap_in_ro, &offset, 4));
39
40  close(cap_in_ro);
41  close(cap_in_wo);
42  close(cap_out_ro);
43  close(cap_out_wo);
44  close(in_fd);
45  close(sock_fds[0]);
46  close(sock_fds[1]);
47  unlink(TmpFile("cap_sendfile_in"));
48}
49
50#ifdef HAVE_TEE
51TEST(CapabilityPair, tee) {
52  int pipe1_fds[2];
53  EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
54  int pipe2_fds[2];
55  EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
56
57  // Put some data into pipe1.
58  unsigned char buffer[4] = {1, 2, 3, 4};
59  EXPECT_OK(write(pipe1_fds[1], buffer, 4));
60
61  cap_rights_t r_ro;
62  cap_rights_init(&r_ro, CAP_READ);
63  cap_rights_t r_wo;
64  cap_rights_init(&r_wo, CAP_WRITE);
65  cap_rights_t r_rw;
66  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
67
68  // Various attempts to tee into pipe2.
69  int cap_in_wo = dup(pipe1_fds[0]);
70  EXPECT_OK(cap_in_wo);
71  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
72  int cap_in_rw = dup(pipe1_fds[0]);
73  EXPECT_OK(cap_in_rw);
74  EXPECT_OK(cap_rights_limit(cap_in_rw, &r_rw));
75  int cap_out_ro = dup(pipe2_fds[1]);
76  EXPECT_OK(cap_out_ro);
77  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
78  int cap_out_rw = dup(pipe2_fds[1]);
79  EXPECT_OK(cap_out_rw);
80  EXPECT_OK(cap_rights_limit(cap_out_rw, &r_rw));
81
82  EXPECT_NOTCAPABLE(tee(cap_in_wo, cap_out_rw, 4, SPLICE_F_NONBLOCK));
83  EXPECT_NOTCAPABLE(tee(cap_in_rw, cap_out_ro, 4, SPLICE_F_NONBLOCK));
84  EXPECT_OK(tee(cap_in_rw, cap_out_rw, 4, SPLICE_F_NONBLOCK));
85
86  close(cap_in_wo);
87  close(cap_in_rw);
88  close(cap_out_ro);
89  close(cap_out_rw);
90  close(pipe1_fds[0]);
91  close(pipe1_fds[1]);
92  close(pipe2_fds[0]);
93  close(pipe2_fds[1]);
94}
95#endif
96
97#ifdef HAVE_SPLICE
98TEST(CapabilityPair, splice) {
99  int pipe1_fds[2];
100  EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
101  int pipe2_fds[2];
102  EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
103
104  // Put some data into pipe1.
105  unsigned char buffer[4] = {1, 2, 3, 4};
106  EXPECT_OK(write(pipe1_fds[1], buffer, 4));
107
108  cap_rights_t r_ro;
109  cap_rights_init(&r_ro, CAP_READ);
110  cap_rights_t r_wo;
111  cap_rights_init(&r_wo, CAP_WRITE);
112  cap_rights_t r_rs;
113  cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
114  cap_rights_t r_ws;
115  cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
116
117  // Various attempts to splice.
118  int cap_in_wo = dup(pipe1_fds[0]);
119  EXPECT_OK(cap_in_wo);
120  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
121  int cap_in_ro = dup(pipe1_fds[0]);
122  EXPECT_OK(cap_in_ro);
123  EXPECT_OK(cap_rights_limit(cap_in_ro, &r_ro));
124  int cap_in_ro_seek = dup(pipe1_fds[0]);
125  EXPECT_OK(cap_in_ro_seek);
126  EXPECT_OK(cap_rights_limit(cap_in_ro_seek, &r_rs));
127  int cap_out_wo = dup(pipe2_fds[1]);
128  EXPECT_OK(cap_out_wo);
129  EXPECT_OK(cap_rights_limit(cap_out_wo, &r_wo));
130  int cap_out_ro = dup(pipe2_fds[1]);
131  EXPECT_OK(cap_out_ro);
132  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
133  int cap_out_wo_seek = dup(pipe2_fds[1]);
134  EXPECT_OK(cap_out_wo_seek);
135  EXPECT_OK(cap_rights_limit(cap_out_wo_seek, &r_ws));
136
137  EXPECT_NOTCAPABLE(splice(cap_in_ro, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
138  EXPECT_NOTCAPABLE(splice(cap_in_wo, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
139  EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_ro, NULL, 4, SPLICE_F_NONBLOCK));
140  EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_wo, NULL, 4, SPLICE_F_NONBLOCK));
141  EXPECT_OK(splice(cap_in_ro_seek, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
142
143  close(cap_in_wo);
144  close(cap_in_ro);
145  close(cap_in_ro_seek);
146  close(cap_out_wo);
147  close(cap_out_ro);
148  close(cap_out_wo_seek);
149  close(pipe1_fds[0]);
150  close(pipe1_fds[1]);
151  close(pipe2_fds[0]);
152  close(pipe2_fds[1]);
153}
154#endif
155
156#ifdef HAVE_VMSPLICE
157// Although it only involves a single file descriptor, test vmsplice(2) here too.
158TEST(CapabilityPair, vmsplice) {
159  int pipe_fds[2];
160  EXPECT_OK(pipe2(pipe_fds, O_NONBLOCK));
161
162  cap_rights_t r_ro;
163  cap_rights_init(&r_ro, CAP_READ);
164  cap_rights_t r_rw;
165  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
166
167  int cap_ro = dup(pipe_fds[1]);
168  EXPECT_OK(cap_ro);
169  EXPECT_OK(cap_rights_limit(cap_ro, &r_ro));
170  int cap_rw = dup(pipe_fds[1]);
171  EXPECT_OK(cap_rw);
172  EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
173
174  unsigned char buffer[4] = {1, 2, 3, 4};
175  struct iovec iov;
176  memset(&iov, 0, sizeof(iov));
177  iov.iov_base = buffer;
178  iov.iov_len = sizeof(buffer);
179
180  EXPECT_NOTCAPABLE(vmsplice(cap_ro, &iov, 1, SPLICE_F_NONBLOCK));
181  EXPECT_OK(vmsplice(cap_rw, &iov, 1, SPLICE_F_NONBLOCK));
182
183  close(cap_ro);
184  close(cap_rw);
185  close(pipe_fds[0]);
186  close(pipe_fds[1]);
187}
188#endif
189