1#include <sys/types.h>
2#include <fcntl.h>
3
4#include <string>
5
6#include "capsicum.h"
7#include "capsicum-test.h"
8#include "syscalls.h"
9
10#define TOPDIR "cap_copy_file_range"
11#define INFILE "infile"
12#define OUTFILE "outfile"
13
14/* Test that copy_file_range() checks capabilities correctly.
15 * When used without offset arguments, copy_file_range() should
16 * require only CAP_READ on the source and CAP_WRITE on the destination
17 * file descriptors, respectively.
18 * When used with offset arguments, copy_file_range() should
19 * additionally require CAP_SEEK.
20 */
21class CopyFileRangeTest : public ::testing::Test {
22 public:
23  CopyFileRangeTest() {
24    int rc = mkdir(TmpFile(TOPDIR), 0755);
25    EXPECT_OK(rc);
26    if (rc < 0) {
27      EXPECT_EQ(EEXIST, errno);
28    }
29    wd_ = open(TmpFile(TOPDIR), O_DIRECTORY);
30    EXPECT_OK(wd_);
31    CreateFile(TmpFile(TOPDIR "/" INFILE));
32    CreateFile(TmpFile(TOPDIR "/" OUTFILE));
33  }
34  ~CopyFileRangeTest() {
35    close(wd_);
36    unlink(TmpFile(TOPDIR "/" INFILE));
37    unlink(TmpFile(TOPDIR "/" OUTFILE));
38    rmdir(TmpFile(TOPDIR));
39  }
40
41 private:
42  void CreateFile(const char *filename) {
43    int fd = open(filename, O_CREAT|O_RDWR, 0644);
44    const char *contents = "lorem ipsum dolor sit amet";
45    EXPECT_OK(fd);
46    for (int i = 0; i < 100; i++) {
47      EXPECT_OK(write(fd, contents, strlen(contents)));
48    }
49    close(fd);
50  }
51
52 protected:
53  int wd_;
54
55  int openInFile(cap_rights_t *rights) {
56    int fd = openat(wd_, INFILE, O_RDONLY);
57    EXPECT_OK(fd);
58    EXPECT_OK(cap_rights_limit(fd, rights));
59    return fd;
60  }
61  int openOutFile(cap_rights_t *rights) {
62    int fd = openat(wd_, OUTFILE, O_WRONLY);
63    EXPECT_OK(fd);
64    EXPECT_OK(cap_rights_limit(fd, rights));
65    return fd;
66  }
67};
68
69TEST_F(CopyFileRangeTest, WriteReadNeg) {
70  cap_rights_t rights_in, rights_out;
71
72  cap_rights_init(&rights_in, CAP_WRITE);
73  cap_rights_init(&rights_out, CAP_READ);
74
75  int fd_in = openInFile(&rights_in);
76  int fd_out = openOutFile(&rights_out);
77  off_t off_in = 0, off_out = 0;
78
79  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
80  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
81  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
82  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
83  off_in = 20;
84  off_out = 20;
85  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
86  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
87  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
88  close(fd_in);
89  close(fd_out);
90}
91
92TEST_F(CopyFileRangeTest, ReadReadNeg) {
93  cap_rights_t rights_in, rights_out;
94
95  cap_rights_init(&rights_in, CAP_READ);
96  cap_rights_init(&rights_out, CAP_READ);
97
98  int fd_in = openInFile(&rights_in);
99  int fd_out = openOutFile(&rights_out);
100  off_t off_in = 0, off_out = 0;
101
102  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
103  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
104  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
105  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
106  off_in = 20;
107  off_out = 20;
108  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
109  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
110  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
111  close(fd_in);
112  close(fd_out);
113}
114
115TEST_F(CopyFileRangeTest, WriteWriteNeg) {
116  cap_rights_t rights_in, rights_out;
117
118  cap_rights_init(&rights_in, CAP_WRITE);
119  cap_rights_init(&rights_out, CAP_WRITE);
120
121  int fd_in = openInFile(&rights_in);
122  int fd_out = openOutFile(&rights_out);
123  off_t off_in = 0, off_out = 0;
124
125  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
126  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
127  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
128  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
129  off_in = 20;
130  off_out = 20;
131  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
132  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
133  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
134  close(fd_in);
135  close(fd_out);
136}
137
138TEST_F(CopyFileRangeTest, ReadWrite) {
139  cap_rights_t rights_in, rights_out;
140
141  cap_rights_init(&rights_in, CAP_READ);
142  cap_rights_init(&rights_out, CAP_WRITE);
143
144  int fd_in = openInFile(&rights_in);
145  int fd_out = openOutFile(&rights_out);
146  off_t off_in = 0, off_out = 0;
147
148  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
149  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
150  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
151  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
152  off_in = 20;
153  off_out = 20;
154  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
155  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
156  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
157  close(fd_in);
158  close(fd_out);
159}
160
161TEST_F(CopyFileRangeTest, ReadSeekWrite) {
162  cap_rights_t rights_in, rights_out;
163
164  cap_rights_init(&rights_in, CAP_READ, CAP_SEEK);
165  cap_rights_init(&rights_out, CAP_WRITE);
166
167  int fd_in = openInFile(&rights_in);
168  int fd_out = openOutFile(&rights_out);
169  off_t off_in = 0, off_out = 0;
170
171  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
172  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
173  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
174  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
175  off_in = 20;
176  off_out = 20;
177  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
178  EXPECT_NOTCAPABLE(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
179  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
180  close(fd_in);
181  close(fd_out);
182}
183
184TEST_F(CopyFileRangeTest, ReadWriteSeek) {
185  cap_rights_t rights_in, rights_out;
186
187  cap_rights_init(&rights_in, CAP_READ);
188  cap_rights_init(&rights_out, CAP_WRITE, CAP_SEEK);
189
190  int fd_in = openInFile(&rights_in);
191  int fd_out = openOutFile(&rights_out);
192  off_t off_in = 0, off_out = 0;
193
194  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
195  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
196  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
197  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
198  off_in = 20;
199  off_out = 20;
200  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
201  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
202  EXPECT_NOTCAPABLE(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
203  close(fd_in);
204  close(fd_out);
205}
206
207TEST_F(CopyFileRangeTest, ReadSeekWriteSeek) {
208  cap_rights_t rights_in, rights_out;
209
210  cap_rights_init(&rights_in, CAP_READ, CAP_SEEK);
211  cap_rights_init(&rights_out, CAP_WRITE, CAP_SEEK);
212
213  int fd_in = openInFile(&rights_in);
214  int fd_out = openOutFile(&rights_out);
215  off_t off_in = 0, off_out = 0;
216
217  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, NULL, 8, 0));
218  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
219  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
220  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
221  off_in = 20;
222  off_out = 20;
223  EXPECT_OK(copy_file_range(fd_in, NULL, fd_out, &off_out, 8, 0));
224  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, NULL, 8, 0));
225  EXPECT_OK(copy_file_range(fd_in, &off_in, fd_out, &off_out, 8, 0));
226  close(fd_in);
227  close(fd_out);
228}
229