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  */
21 class 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 
69 TEST_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 
92 TEST_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 
115 TEST_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 
138 TEST_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 
161 TEST_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 
184 TEST_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 
207 TEST_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