1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2021 Google LLC
4 */
5 #define _GNU_SOURCE
6
7 #include "test_fuse.h"
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <sys/file.h>
16 #include <sys/inotify.h>
17 #include <sys/mman.h>
18 #include <sys/mount.h>
19 #include <sys/syscall.h>
20 #include <sys/wait.h>
21
22 #include <linux/capability.h>
23 #include <linux/random.h>
24
25 #include <include/uapi/linux/fuse.h>
26 #include <include/uapi/linux/bpf.h>
27
28 static const char *ft_src = "ft-src";
29 static const char *ft_dst = "ft-dst";
30
fill_buffer(uint8_t * data,size_t len,int file,int block)31 static void fill_buffer(uint8_t *data, size_t len, int file, int block)
32 {
33 int i;
34 int seed = 7919 * file + block;
35
36 for (i = 0; i < len; i++) {
37 seed = 1103515245 * seed + 12345;
38 data[i] = (uint8_t)(seed >> (i % 13));
39 }
40 }
41
test_buffer(uint8_t * data,size_t len,int file,int block)42 static bool test_buffer(uint8_t *data, size_t len, int file, int block)
43 {
44 int i;
45 int seed = 7919 * file + block;
46
47 for (i = 0; i < len; i++) {
48 seed = 1103515245 * seed + 12345;
49 if (data[i] != (uint8_t)(seed >> (i % 13)))
50 return false;
51 }
52
53 return true;
54 }
55
create_file(int dir,struct s name,int index,size_t blocks)56 static int create_file(int dir, struct s name, int index, size_t blocks)
57 {
58 int result = TEST_FAILURE;
59 int fd = -1;
60 int i;
61 uint8_t data[PAGE_SIZE];
62
63 TEST(fd = s_openat(dir, name, O_CREAT | O_WRONLY, 0777), fd != -1);
64 for (i = 0; i < blocks; ++i) {
65 fill_buffer(data, PAGE_SIZE, index, i);
66 TESTEQUAL(write(fd, data, sizeof(data)), PAGE_SIZE);
67 }
68 TESTSYSCALL(close(fd));
69 result = TEST_SUCCESS;
70
71 out:
72 close(fd);
73 return result;
74 }
75
bpf_clear_trace(void)76 static int bpf_clear_trace(void)
77 {
78 int result = TEST_FAILURE;
79 int tp = -1;
80
81 TEST(tp = s_open(s_path(tracing_folder(), s("trace")),
82 O_WRONLY | O_TRUNC | O_CLOEXEC), tp != -1);
83
84 result = TEST_SUCCESS;
85 out:
86 close(tp);
87 return result;
88 }
89
bpf_test_trace_maybe(const char * substr,bool present)90 static int bpf_test_trace_maybe(const char *substr, bool present)
91 {
92 int result = TEST_FAILURE;
93 int tp = -1;
94 char trace_buffer[4096] = {};
95 ssize_t bytes_read;
96
97 TEST(tp = s_open(s_path(tracing_folder(), s("trace_pipe")),
98 O_RDONLY | O_CLOEXEC),
99 tp != -1);
100 fcntl(tp, F_SETFL, O_NONBLOCK);
101
102 for (;;) {
103 bytes_read = read(tp, trace_buffer, sizeof(trace_buffer));
104 if (present)
105 TESTCOND(bytes_read > 0);
106 else if (bytes_read <= 0) {
107 result = TEST_SUCCESS;
108 break;
109 }
110
111 if (test_options.verbose)
112 ksft_print_msg("%s\n", trace_buffer);
113
114 if (strstr(trace_buffer, substr)) {
115 if (present)
116 result = TEST_SUCCESS;
117 break;
118 }
119 }
120 out:
121 close(tp);
122 return result;
123 }
124
bpf_test_trace(const char * substr)125 static int bpf_test_trace(const char *substr)
126 {
127 return bpf_test_trace_maybe(substr, true);
128 }
129
bpf_test_no_trace(const char * substr)130 static int bpf_test_no_trace(const char *substr)
131 {
132 return bpf_test_trace_maybe(substr, false);
133 }
134
basic_test(const char * mount_dir)135 static int basic_test(const char *mount_dir)
136 {
137 const char *test_name = "test";
138 const char *test_data = "data";
139
140 int result = TEST_FAILURE;
141 int fuse_dev = -1;
142 char *filename = NULL;
143 int fd = -1;
144 FUSE_DECLARE_DAEMON;
145
146 TESTEQUAL(mount_fuse(mount_dir, -1, -1, &fuse_dev), 0);
147 FUSE_START_DAEMON();
148 if (action) {
149 char data[256];
150
151 filename = concat_file_name(mount_dir, test_name);
152 TESTERR(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
153 TESTEQUAL(read(fd, data, strlen(test_data)), strlen(test_data));
154 TESTCOND(!strcmp(data, test_data));
155 TESTSYSCALL(close(fd));
156 fd = -1;
157 } else {
158 DECL_FUSE_IN(open);
159 DECL_FUSE_IN(read);
160 DECL_FUSE_IN(flush);
161 DECL_FUSE_IN(release);
162
163 TESTFUSELOOKUP(test_name, 0);
164 TESTFUSEOUT1(fuse_entry_out, ((struct fuse_entry_out) {
165 .nodeid = 2,
166 .generation = 1,
167 .attr.ino = 100,
168 .attr.size = 4,
169 .attr.blksize = 512,
170 .attr.mode = S_IFREG | 0777,
171 }));
172
173 TESTFUSEIN(FUSE_OPEN, open_in);
174 TESTFUSEOUT1(fuse_open_out, ((struct fuse_open_out) {
175 .fh = 1,
176 .open_flags = open_in->flags,
177 }));
178
179 TESTFUSEINNULL(FUSE_CANONICAL_PATH);
180 TESTFUSEOUTREAD("ignored", 7);
181
182 TESTFUSEIN(FUSE_READ, read_in);
183 TESTFUSEOUTREAD(test_data, strlen(test_data));
184
185 TESTFUSEIN(FUSE_FLUSH, flush_in);
186 TESTFUSEOUTEMPTY();
187
188 TESTFUSEIN(FUSE_RELEASE, release_in);
189 TESTFUSEOUTEMPTY();
190 exit(TEST_SUCCESS);
191 }
192 FUSE_END_DAEMON();
193 close(fuse_dev);
194 close(fd);
195 free(filename);
196 umount(mount_dir);
197 return result;
198 }
199
bpf_test_real(const char * mount_dir)200 static int bpf_test_real(const char *mount_dir)
201 {
202 const char *test_name = "real";
203 const char *test_data = "Weebles wobble but they don't fall down";
204 int result = TEST_FAILURE;
205 int bpf_fd = -1;
206 int src_fd = -1;
207 int fuse_dev = -1;
208 char *filename = NULL;
209 int fd = -1;
210 char read_buffer[256] = {};
211 ssize_t bytes_read;
212
213 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
214 src_fd != -1);
215 TEST(fd = openat(src_fd, test_name, O_CREAT | O_RDWR | O_CLOEXEC, 0777),
216 fd != -1);
217 TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
218 TESTSYSCALL(close(fd));
219 fd = -1;
220
221 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
222 &bpf_fd, NULL, NULL), 0);
223 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
224
225 filename = concat_file_name(mount_dir, test_name);
226 TESTERR(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
227 bytes_read = read(fd, read_buffer, strlen(test_data));
228 TESTEQUAL(bytes_read, strlen(test_data));
229 TESTEQUAL(strcmp(test_data, read_buffer), 0);
230 TESTEQUAL(bpf_test_trace("read"), 0);
231
232 result = TEST_SUCCESS;
233 out:
234 close(fuse_dev);
235 close(fd);
236 free(filename);
237 umount(mount_dir);
238 close(src_fd);
239 close(bpf_fd);
240 return result;
241 }
242
243
bpf_test_partial(const char * mount_dir)244 static int bpf_test_partial(const char *mount_dir)
245 {
246 const char *test_name = "partial";
247 int result = TEST_FAILURE;
248 int bpf_fd = -1;
249 int src_fd = -1;
250 int fuse_dev = -1;
251 char *filename = NULL;
252 int fd = -1;
253 FUSE_DECLARE_DAEMON;
254
255 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
256 src_fd != -1);
257 TESTEQUAL(create_file(src_fd, s(test_name), 1, 2), 0);
258 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_partial",
259 &bpf_fd, NULL, NULL), 0);
260 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
261
262 FUSE_START_DAEMON();
263 if (action) {
264 uint8_t data[PAGE_SIZE];
265
266 TEST(filename = concat_file_name(mount_dir, test_name),
267 filename);
268 TESTERR(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
269 TESTEQUAL(read(fd, data, PAGE_SIZE), PAGE_SIZE);
270 TESTEQUAL(bpf_test_trace("read"), 0);
271 TESTCOND(test_buffer(data, PAGE_SIZE, 2, 0));
272 TESTCOND(!test_buffer(data, PAGE_SIZE, 1, 0));
273 TESTEQUAL(read(fd, data, PAGE_SIZE), PAGE_SIZE);
274 TESTCOND(test_buffer(data, PAGE_SIZE, 1, 1));
275 TESTCOND(!test_buffer(data, PAGE_SIZE, 2, 1));
276 TESTSYSCALL(close(fd));
277 fd = -1;
278 } else {
279 DECL_FUSE(open);
280 DECL_FUSE(read);
281 DECL_FUSE(release);
282 uint8_t data[PAGE_SIZE];
283
284 TESTFUSEIN2(FUSE_OPEN | FUSE_POSTFILTER, open_in, open_out);
285 TESTFUSEOUT1(fuse_open_out, ((struct fuse_open_out) {
286 .fh = 1,
287 .open_flags = open_in->flags,
288 }));
289
290 TESTFUSEIN(FUSE_READ, read_in);
291 fill_buffer(data, PAGE_SIZE, 2, 0);
292 TESTFUSEOUTREAD(data, PAGE_SIZE);
293
294 TESTFUSEIN(FUSE_RELEASE, release_in);
295 TESTFUSEOUTEMPTY();
296 exit(TEST_SUCCESS);
297 }
298 FUSE_END_DAEMON();
299 close(fuse_dev);
300 close(fd);
301 free(filename);
302 umount(mount_dir);
303 close(src_fd);
304 close(bpf_fd);
305 return result;
306 }
307
bpf_test_attrs(const char * mount_dir)308 static int bpf_test_attrs(const char *mount_dir)
309 {
310 const char *test_name = "partial";
311 int result = TEST_FAILURE;
312 int bpf_fd = -1;
313 int src_fd = -1;
314 int fuse_dev = -1;
315 char *filename = NULL;
316 struct stat st;
317
318 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
319 src_fd != -1);
320 TESTEQUAL(create_file(src_fd, s(test_name), 1, 2), 0);
321 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
322 &bpf_fd, NULL, NULL), 0);
323 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
324
325 TEST(filename = concat_file_name(mount_dir, test_name), filename);
326 TESTSYSCALL(stat(filename, &st));
327 TESTSYSCALL(chmod(filename, 0111));
328 TESTSYSCALL(stat(filename, &st));
329 TESTEQUAL(st.st_mode & 0777, 0111);
330 TESTSYSCALL(chmod(filename, 0777));
331 TESTSYSCALL(stat(filename, &st));
332 TESTEQUAL(st.st_mode & 0777, 0777);
333 TESTSYSCALL(chown(filename, 5, 6));
334 TESTSYSCALL(stat(filename, &st));
335 TESTEQUAL(st.st_uid, 5);
336 TESTEQUAL(st.st_gid, 6);
337
338 result = TEST_SUCCESS;
339 out:
340 close(fuse_dev);
341 free(filename);
342 umount(mount_dir);
343 close(src_fd);
344 close(bpf_fd);
345 return result;
346 }
347
bpf_test_readdir(const char * mount_dir)348 static int bpf_test_readdir(const char *mount_dir)
349 {
350 static const char * const names[] = {
351 "real", "partial", "fake", ".", ".."
352 };
353 bool used[ARRAY_SIZE(names)] = { false };
354 int result = TEST_FAILURE;
355 int bpf_fd = -1;
356 int src_fd = -1;
357 int fuse_dev = -1;
358 DIR *dir = NULL;
359 struct dirent *dirent;
360 FUSE_DECLARE_DAEMON;
361
362 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
363 src_fd != -1);
364 TESTEQUAL(create_file(src_fd, s(names[0]), 1, 2), 0);
365 TESTEQUAL(create_file(src_fd, s(names[1]), 1, 2), 0);
366 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_partial",
367 &bpf_fd, NULL, NULL), 0);
368 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
369
370 FUSE_START_DAEMON();
371 if (action) {
372 int i, j;
373
374 TEST(dir = s_opendir(s(mount_dir)), dir);
375 TESTEQUAL(bpf_test_trace("opendir"), 0);
376
377 for (i = 0; i < ARRAY_SIZE(names); ++i) {
378 TEST(dirent = readdir(dir), dirent);
379
380 for (j = 0; j < ARRAY_SIZE(names); ++j)
381 if (!used[j] &&
382 strcmp(names[j], dirent->d_name) == 0) {
383 used[j] = true;
384 break;
385 }
386 TESTNE(j, ARRAY_SIZE(names));
387 }
388 TEST(dirent = readdir(dir), dirent == NULL);
389 TESTSYSCALL(closedir(dir));
390 dir = NULL;
391 TESTEQUAL(bpf_test_trace("readdir"), 0);
392 } else {
393 struct fuse_in_header *in_header =
394 (struct fuse_in_header *)bytes_in;
395 ssize_t res = read(fuse_dev, bytes_in, sizeof(bytes_in));
396 struct fuse_read_out *read_out =
397 (struct fuse_read_out *) (bytes_in +
398 sizeof(*in_header) +
399 sizeof(struct fuse_read_in));
400 struct fuse_dirent *fuse_dirent =
401 (struct fuse_dirent *) (bytes_in + res);
402
403 TESTGE(res, sizeof(*in_header) + sizeof(struct fuse_read_in));
404 TESTEQUAL(in_header->opcode, FUSE_READDIR | FUSE_POSTFILTER);
405 *fuse_dirent = (struct fuse_dirent) {
406 .ino = 100,
407 .off = 5,
408 .namelen = strlen("fake"),
409 .type = DT_REG,
410 };
411 strcpy((char *)(bytes_in + res + sizeof(*fuse_dirent)), "fake");
412 res += FUSE_DIRENT_ALIGN(sizeof(*fuse_dirent) + strlen("fake") +
413 1);
414 TESTFUSEDIROUTREAD(read_out,
415 bytes_in +
416 sizeof(struct fuse_in_header) +
417 sizeof(struct fuse_read_in) +
418 sizeof(struct fuse_read_out),
419 res - sizeof(struct fuse_in_header) -
420 sizeof(struct fuse_read_in) -
421 sizeof(struct fuse_read_out));
422 res = read(fuse_dev, bytes_in, sizeof(bytes_in));
423 TESTEQUAL(res, sizeof(*in_header) +
424 sizeof(struct fuse_read_in) +
425 sizeof(struct fuse_read_out));
426 TESTEQUAL(in_header->opcode, FUSE_READDIR | FUSE_POSTFILTER);
427 TESTFUSEDIROUTREAD(read_out, bytes_in, 0);
428 exit(TEST_SUCCESS);
429 }
430 FUSE_END_DAEMON();
431 closedir(dir);
432 close(fuse_dev);
433 umount(mount_dir);
434 close(src_fd);
435 close(bpf_fd);
436 return result;
437 }
438
bpf_test_redact_readdir(const char * mount_dir)439 static int bpf_test_redact_readdir(const char *mount_dir)
440 {
441 static const char * const names[] = {
442 "f1", "f2", "f3", "f4", "f5", "f6", ".", ".."
443 };
444 bool used[ARRAY_SIZE(names)] = { false };
445 int num_shown = (ARRAY_SIZE(names) - 2) / 2 + 2;
446 int result = TEST_FAILURE;
447 int bpf_fd = -1;
448 int src_fd = -1;
449 int fuse_dev = -1;
450 DIR *dir = NULL;
451 struct dirent *dirent;
452 int i;
453 int count = 0;
454 FUSE_DECLARE_DAEMON;
455
456 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
457 src_fd != -1);
458 for (i = 0; i < ARRAY_SIZE(names) - 2; i++)
459 TESTEQUAL(create_file(src_fd, s(names[i]), 1, 2), 0);
460
461 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_readdir_redact",
462 &bpf_fd, NULL, NULL), 0);
463 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
464
465 FUSE_START_DAEMON();
466 if (action) {
467 int j;
468
469 TEST(dir = s_opendir(s(mount_dir)), dir);
470 while ((dirent = readdir(dir))) {
471 errno = 0;
472 TESTEQUAL(errno, 0);
473
474 for (j = 0; j < ARRAY_SIZE(names); ++j)
475 if (!used[j] &&
476 strcmp(names[j], dirent->d_name) == 0) {
477 used[j] = true;
478 count++;
479 break;
480 }
481 TESTNE(j, ARRAY_SIZE(names));
482 TESTGE(num_shown, count);
483 }
484 TESTEQUAL(count, num_shown);
485 TESTSYSCALL(closedir(dir));
486 dir = NULL;
487 } else {
488 bool skip = true;
489
490 for (int i = 0; i < ARRAY_SIZE(names) + 1; i++) {
491 uint8_t bytes_in[FUSE_MIN_READ_BUFFER];
492 uint8_t bytes_out[FUSE_MIN_READ_BUFFER];
493 struct fuse_in_header *in_header =
494 (struct fuse_in_header *)bytes_in;
495 ssize_t res = read(fuse_dev, bytes_in, sizeof(bytes_in));
496 int length_out = 0;
497 uint8_t *pos;
498 uint8_t *dirs_in;
499 uint8_t *dirs_out;
500 struct fuse_read_in *fuse_read_in;
501 struct fuse_read_out *fuse_read_out_in;
502 struct fuse_read_out *fuse_read_out_out;
503 struct fuse_dirent *fuse_dirent_in = NULL;
504 struct fuse_dirent *next = NULL;
505 bool again = false;
506 int dir_ent_len = 0;
507
508 TESTGE(res, sizeof(struct fuse_in_header) +
509 sizeof(struct fuse_read_in) +
510 sizeof(struct fuse_read_out));
511
512 pos = bytes_in + sizeof(struct fuse_in_header);
513 fuse_read_in = (struct fuse_read_in *) pos;
514 pos += sizeof(*fuse_read_in);
515 fuse_read_out_in = (struct fuse_read_out *) pos;
516 pos += sizeof(*fuse_read_out_in);
517 dirs_in = pos;
518
519 pos = bytes_out + sizeof(struct fuse_out_header);
520 fuse_read_out_out = (struct fuse_read_out *) pos;
521 pos += sizeof(*fuse_read_out_out);
522 dirs_out = pos;
523
524 if (dirs_in < bytes_in + res) {
525 bool is_dot;
526
527 fuse_dirent_in = (struct fuse_dirent *) dirs_in;
528 is_dot = (fuse_dirent_in->namelen == 1 &&
529 !strncmp(fuse_dirent_in->name, ".", 1)) ||
530 (fuse_dirent_in->namelen == 2 &&
531 !strncmp(fuse_dirent_in->name, "..", 2));
532
533 dir_ent_len = FUSE_DIRENT_ALIGN(
534 sizeof(*fuse_dirent_in) +
535 fuse_dirent_in->namelen);
536
537 if (dirs_in + dir_ent_len < bytes_in + res)
538 next = (struct fuse_dirent *)
539 (dirs_in + dir_ent_len);
540
541 if (!skip || is_dot) {
542 memcpy(dirs_out, fuse_dirent_in,
543 sizeof(struct fuse_dirent) +
544 fuse_dirent_in->namelen);
545 length_out += dir_ent_len;
546 }
547 again = ((skip && !is_dot) && next);
548
549 if (!is_dot)
550 skip = !skip;
551 }
552
553 fuse_read_out_out->offset = next ? next->off :
554 fuse_read_out_in->offset;
555 fuse_read_out_out->again = again;
556
557 {
558 struct fuse_out_header *out_header =
559 (struct fuse_out_header *)bytes_out;
560
561 *out_header = (struct fuse_out_header) {
562 .len = sizeof(*out_header) +
563 sizeof(*fuse_read_out_out) + length_out,
564 .unique = in_header->unique,
565 };
566 TESTEQUAL(write(fuse_dev, bytes_out, out_header->len),
567 out_header->len);
568 }
569 }
570 exit(TEST_SUCCESS);
571 }
572 FUSE_END_DAEMON();
573 closedir(dir);
574 close(fuse_dev);
575 umount(mount_dir);
576 close(src_fd);
577 close(bpf_fd);
578 return result;
579 }
580
581 /*
582 * This test is more to show what classic fuse does with a creat in a subdir
583 * than a test of any new functionality
584 */
bpf_test_creat(const char * mount_dir)585 static int bpf_test_creat(const char *mount_dir)
586 {
587 const char *dir_name = "show";
588 const char *file_name = "file";
589 int result = TEST_FAILURE;
590 int fuse_dev = -1;
591 int fd = -1;
592 FUSE_DECLARE_DAEMON;
593
594 TESTEQUAL(mount_fuse(mount_dir, -1, -1, &fuse_dev), 0);
595
596 FUSE_START_DAEMON();
597 if (action) {
598 TEST(fd = s_creat(s_path(s_path(s(mount_dir), s(dir_name)),
599 s(file_name)),
600 0777),
601 fd != -1);
602 TESTSYSCALL(close(fd));
603 } else {
604 DECL_FUSE_IN(create);
605 DECL_FUSE_IN(release);
606 DECL_FUSE_IN(flush);
607
608 TESTFUSELOOKUP(dir_name, 0);
609 TESTFUSEOUT1(fuse_entry_out, ((struct fuse_entry_out) {
610 .nodeid = 3,
611 .generation = 1,
612 .attr.ino = 100,
613 .attr.size = 4,
614 .attr.blksize = 512,
615 .attr.mode = S_IFDIR | 0777,
616 }));
617
618 TESTFUSELOOKUP(file_name, 0);
619 TESTFUSEOUTERROR(-ENOENT);
620
621 TESTFUSEINEXT(FUSE_CREATE, create_in, strlen(file_name) + 1);
622 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
623 .nodeid = 2,
624 .generation = 1,
625 .attr.ino = 200,
626 .attr.size = 4,
627 .attr.blksize = 512,
628 .attr.mode = S_IFREG,
629 }),
630 fuse_open_out, ((struct fuse_open_out) {
631 .fh = 1,
632 .open_flags = create_in->flags,
633 }));
634
635 TESTFUSEINNULL(FUSE_CANONICAL_PATH);
636 TESTFUSEOUTREAD("ignored", 7);
637
638 TESTFUSEIN(FUSE_FLUSH, flush_in);
639 TESTFUSEOUTEMPTY();
640
641 TESTFUSEIN(FUSE_RELEASE, release_in);
642 TESTFUSEOUTEMPTY();
643 exit(TEST_SUCCESS);
644 }
645 FUSE_END_DAEMON();
646 close(fuse_dev);
647 umount(mount_dir);
648 return result;
649 }
650
bpf_test_hidden_entries(const char * mount_dir)651 static int bpf_test_hidden_entries(const char *mount_dir)
652 {
653 static const char * const dir_names[] = {
654 "show",
655 "hide",
656 };
657 const char *file_name = "file";
658 const char *data = "The quick brown fox jumps over the lazy dog\n";
659 int result = TEST_FAILURE;
660 int src_fd = -1;
661 int bpf_fd = -1;
662 int fuse_dev = -1;
663 int fd = -1;
664
665 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
666 src_fd != -1);
667 TESTSYSCALL(mkdirat(src_fd, dir_names[0], 0777));
668 TESTSYSCALL(mkdirat(src_fd, dir_names[1], 0777));
669 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_hidden",
670 &bpf_fd, NULL, NULL), 0);
671 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
672
673 TEST(fd = s_creat(s_path(s_path(s(mount_dir), s(dir_names[0])),
674 s(file_name)),
675 0777),
676 fd != -1);
677 TESTSYSCALL(fallocate(fd, 0, 0, 4096));
678 TEST(write(fd, data, strlen(data)), strlen(data));
679 TESTSYSCALL(close(fd));
680 TESTEQUAL(bpf_test_trace("Create"), 0);
681
682 result = TEST_SUCCESS;
683 out:
684 close(fuse_dev);
685 umount(mount_dir);
686 close(bpf_fd);
687 close(src_fd);
688 return result;
689 }
690
bpf_test_dir(const char * mount_dir)691 static int bpf_test_dir(const char *mount_dir)
692 {
693 const char *dir_name = "dir";
694 int result = TEST_FAILURE;
695 int src_fd = -1;
696 int bpf_fd = -1;
697 int fuse_dev = -1;
698 struct stat st;
699
700 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
701 src_fd != -1);
702 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
703 &bpf_fd, NULL, NULL), 0);
704 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
705
706 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s(dir_name)), 0777));
707 TESTEQUAL(bpf_test_trace("mkdir"), 0);
708 TESTSYSCALL(s_stat(s_path(s(ft_src), s(dir_name)), &st));
709 TESTSYSCALL(s_rmdir(s_path(s(mount_dir), s(dir_name))));
710 TESTEQUAL(s_stat(s_path(s(ft_src), s(dir_name)), &st), -1);
711 TESTEQUAL(errno, ENOENT);
712 result = TEST_SUCCESS;
713 out:
714 close(fuse_dev);
715 umount(mount_dir);
716 close(bpf_fd);
717 close(src_fd);
718 return result;
719 }
720
bpf_test_file(const char * mount_dir,bool close_first)721 static int bpf_test_file(const char *mount_dir, bool close_first)
722 {
723 const char *file_name = "real";
724 int result = TEST_FAILURE;
725 int src_fd = -1;
726 int bpf_fd = -1;
727 int fuse_dev = -1;
728 int fd = -1;
729 struct stat st;
730
731 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
732 src_fd != -1);
733 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
734 &bpf_fd, NULL, NULL), 0);
735 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
736
737 TEST(fd = s_creat(s_path(s(mount_dir), s(file_name)),
738 0777),
739 fd != -1);
740 TESTEQUAL(bpf_test_trace("Create"), 0);
741 if (close_first) {
742 TESTSYSCALL(close(fd));
743 fd = -1;
744 }
745 TESTSYSCALL(s_stat(s_path(s(ft_src), s(file_name)), &st));
746 TESTSYSCALL(s_unlink(s_path(s(mount_dir), s(file_name))));
747 TESTEQUAL(bpf_test_trace("unlink"), 0);
748 TESTEQUAL(s_stat(s_path(s(ft_src), s(file_name)), &st), -1);
749 TESTEQUAL(errno, ENOENT);
750 if (!close_first) {
751 TESTSYSCALL(close(fd));
752 fd = -1;
753 }
754 result = TEST_SUCCESS;
755 out:
756 close(fd);
757 close(fuse_dev);
758 umount(mount_dir);
759 close(bpf_fd);
760 close(src_fd);
761 return result;
762 }
763
bpf_test_file_early_close(const char * mount_dir)764 static int bpf_test_file_early_close(const char *mount_dir)
765 {
766 return bpf_test_file(mount_dir, true);
767 }
768
bpf_test_file_late_close(const char * mount_dir)769 static int bpf_test_file_late_close(const char *mount_dir)
770 {
771 return bpf_test_file(mount_dir, false);
772 }
773
bpf_test_alter_errcode_bpf(const char * mount_dir)774 static int bpf_test_alter_errcode_bpf(const char *mount_dir)
775 {
776 const char *dir_name = "dir";
777 int result = TEST_FAILURE;
778 int src_fd = -1;
779 int bpf_fd = -1;
780 int fuse_dev = -1;
781 struct stat st;
782
783 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
784 src_fd != -1);
785 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_error",
786 &bpf_fd, NULL, NULL), 0);
787 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
788
789 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s(dir_name)), 0777));
790 //TESTEQUAL(bpf_test_trace("mkdir"), 0);
791 TESTSYSCALL(s_stat(s_path(s(ft_src), s(dir_name)), &st));
792 TESTEQUAL(s_mkdir(s_path(s(mount_dir), s(dir_name)), 0777), -EPERM);
793 TESTSYSCALL(s_rmdir(s_path(s(mount_dir), s(dir_name))));
794 TESTEQUAL(s_stat(s_path(s(ft_src), s(dir_name)), &st), -1);
795 TESTEQUAL(errno, ENOENT);
796 result = TEST_SUCCESS;
797 out:
798 close(fuse_dev);
799 umount(mount_dir);
800 close(bpf_fd);
801 close(src_fd);
802 return result;
803 }
804
bpf_test_alter_errcode_userspace(const char * mount_dir)805 static int bpf_test_alter_errcode_userspace(const char *mount_dir)
806 {
807 const char *dir_name = "doesnotexist";
808 int result = TEST_FAILURE;
809 int src_fd = -1;
810 int bpf_fd = -1;
811 int fuse_dev = -1;
812 FUSE_DECLARE_DAEMON;
813
814 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
815 src_fd != -1);
816 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_error",
817 &bpf_fd, NULL, NULL), 0);
818 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
819
820 FUSE_START_DAEMON();
821 if (action) {
822 TESTEQUAL(s_unlink(s_path(s(mount_dir), s(dir_name))),
823 -1);
824 TESTEQUAL(errno, ENOMEM);
825 } else {
826 TESTFUSELOOKUP("doesnotexist", FUSE_POSTFILTER);
827 TESTFUSEOUTERROR(-ENOMEM);
828 exit(TEST_SUCCESS);
829 }
830 FUSE_END_DAEMON();
831 close(fuse_dev);
832 umount(mount_dir);
833 close(bpf_fd);
834 close(src_fd);
835 return result;
836 }
837
bpf_test_mknod(const char * mount_dir)838 static int bpf_test_mknod(const char *mount_dir)
839 {
840 const char *file_name = "real";
841 int result = TEST_FAILURE;
842 int src_fd = -1;
843 int bpf_fd = -1;
844 int fuse_dev = -1;
845 struct stat st;
846
847 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
848 src_fd != -1);
849 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
850 &bpf_fd, NULL, NULL), 0);
851 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
852
853 TESTSYSCALL(s_mkfifo(s_path(s(mount_dir), s(file_name)), 0777));
854 TESTEQUAL(bpf_test_trace("mknod"), 0);
855 TESTSYSCALL(s_stat(s_path(s(ft_src), s(file_name)), &st));
856 TESTSYSCALL(s_unlink(s_path(s(mount_dir), s(file_name))));
857 TESTEQUAL(bpf_test_trace("unlink"), 0);
858 TESTEQUAL(s_stat(s_path(s(ft_src), s(file_name)), &st), -1);
859 TESTEQUAL(errno, ENOENT);
860 result = TEST_SUCCESS;
861 out:
862 close(fuse_dev);
863 umount(mount_dir);
864 close(bpf_fd);
865 close(src_fd);
866 return result;
867 }
868
bpf_test_largedir(const char * mount_dir)869 static int bpf_test_largedir(const char *mount_dir)
870 {
871 const char *show = "show";
872 const int files = 1000;
873
874 int result = TEST_FAILURE;
875 int src_fd = -1;
876 int bpf_fd = -1;
877 int fuse_dev = -1;
878 struct map_relocation *map_relocations = NULL;
879 size_t map_count = 0;
880 FUSE_DECLARE_DAEMON;
881
882 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
883 src_fd != -1);
884 TESTEQUAL(install_elf_bpf("fd_bpf.bpf", "test_daemon",
885 &bpf_fd, &map_relocations, &map_count), 0);
886 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
887
888 FUSE_START_DAEMON();
889 if (action) {
890 int i;
891 int fd;
892 DIR *dir = NULL;
893 struct dirent *dirent;
894
895 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s(show)), 0777));
896 for (i = 0; i < files; ++i) {
897 char filename[NAME_MAX];
898
899 sprintf(filename, "%d", i);
900 TEST(fd = s_creat(s_path(s_path(s(mount_dir), s(show)),
901 s(filename)), 0777), fd != -1);
902 TESTSYSCALL(close(fd));
903 }
904
905 TEST(dir = s_opendir(s_path(s(mount_dir), s(show))), dir);
906 for (dirent = readdir(dir); dirent; dirent = readdir(dir))
907 ;
908 closedir(dir);
909 } else {
910 int i;
911
912 for (i = 0; i < files + 2; ++i) {
913 TESTFUSELOOKUP(show, FUSE_PREFILTER);
914 TESTFUSEOUTREAD(show, 5);
915 }
916 exit(TEST_SUCCESS);
917 }
918 FUSE_END_DAEMON();
919 close(fuse_dev);
920 umount(mount_dir);
921 close(bpf_fd);
922 close(src_fd);
923 return result;
924 }
925
bpf_test_link(const char * mount_dir)926 static int bpf_test_link(const char *mount_dir)
927 {
928 const char *file_name = "real";
929 const char *link_name = "partial";
930 int result = TEST_FAILURE;
931 int fd = -1;
932 int src_fd = -1;
933 int bpf_fd = -1;
934 int fuse_dev = -1;
935 struct stat st;
936
937 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
938 src_fd != -1);
939 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace", &bpf_fd, NULL,
940 NULL),
941 0);
942 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
943
944 TEST(fd = s_creat(s_path(s(mount_dir), s(file_name)), 0777), fd != -1);
945 TESTEQUAL(bpf_test_trace("Create"), 0);
946 TESTSYSCALL(s_stat(s_path(s(ft_src), s(file_name)), &st));
947
948 TESTSYSCALL(s_link(s_path(s(mount_dir), s(file_name)),
949 s_path(s(mount_dir), s(link_name))));
950
951 TESTEQUAL(bpf_test_trace("link"), 0);
952 TESTSYSCALL(s_stat(s_path(s(ft_src), s(link_name)), &st));
953
954 TESTSYSCALL(s_unlink(s_path(s(mount_dir), s(link_name))));
955 TESTEQUAL(bpf_test_trace("unlink"), 0);
956 TESTEQUAL(s_stat(s_path(s(ft_src), s(link_name)), &st), -1);
957 TESTEQUAL(errno, ENOENT);
958
959 TESTSYSCALL(s_unlink(s_path(s(mount_dir), s(file_name))));
960 TESTEQUAL(bpf_test_trace("unlink"), 0);
961 TESTEQUAL(s_stat(s_path(s(ft_src), s(file_name)), &st), -1);
962 TESTEQUAL(errno, ENOENT);
963
964 result = TEST_SUCCESS;
965 out:
966 close(fd);
967 close(fuse_dev);
968 umount(mount_dir);
969 close(bpf_fd);
970 close(src_fd);
971 return result;
972 }
973
bpf_test_symlink(const char * mount_dir)974 static int bpf_test_symlink(const char *mount_dir)
975 {
976 const char *test_name = "real";
977 const char *symlink_name = "partial";
978 const char *test_data = "Weebles wobble but they don't fall down";
979 int result = TEST_FAILURE;
980 int bpf_fd = -1;
981 int src_fd = -1;
982 int fuse_dev = -1;
983 int fd = -1;
984 char read_buffer[256] = {};
985 ssize_t bytes_read;
986
987 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
988 src_fd != -1);
989 TEST(fd = openat(src_fd, test_name, O_CREAT | O_RDWR | O_CLOEXEC, 0777),
990 fd != -1);
991 TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
992 TESTSYSCALL(close(fd));
993 fd = -1;
994
995 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
996 &bpf_fd, NULL, NULL), 0);
997 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
998
999 TESTSYSCALL(s_symlink(s_path(s(mount_dir), s(test_name)),
1000 s_path(s(mount_dir), s(symlink_name))));
1001 TESTEQUAL(bpf_test_trace("symlink"), 0);
1002
1003 TESTERR(fd = s_open(s_path(s(mount_dir), s(symlink_name)), O_RDONLY | O_CLOEXEC), fd != -1);
1004 bytes_read = read(fd, read_buffer, strlen(test_data));
1005 TESTEQUAL(bpf_test_trace("readlink"), 0);
1006 TESTEQUAL(bytes_read, strlen(test_data));
1007 TESTEQUAL(strcmp(test_data, read_buffer), 0);
1008
1009 result = TEST_SUCCESS;
1010 out:
1011 close(fuse_dev);
1012 close(fd);
1013 umount(mount_dir);
1014 close(src_fd);
1015 close(bpf_fd);
1016 return result;
1017 }
1018
bpf_test_xattr(const char * mount_dir)1019 static int bpf_test_xattr(const char *mount_dir)
1020 {
1021 static const char file_name[] = "real";
1022 static const char xattr_name[] = "user.xattr_test_name";
1023 static const char xattr_value[] = "this_is_a_test";
1024 const size_t xattr_size = sizeof(xattr_value);
1025 char xattr_value_ret[256];
1026 ssize_t xattr_size_ret;
1027 ssize_t xattr_size_ret_se;
1028 int result = TEST_FAILURE;
1029 int fd = -1;
1030 int src_fd = -1;
1031 int bpf_fd = -1;
1032 int fuse_dev = -1;
1033 struct stat st;
1034
1035 memset(xattr_value_ret, '\0', sizeof(xattr_value_ret));
1036
1037 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1038 src_fd != -1);
1039 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace", &bpf_fd, NULL,
1040 NULL),
1041 0);
1042 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1043
1044 TEST(fd = s_creat(s_path(s(mount_dir), s(file_name)), 0777), fd != -1);
1045 TESTEQUAL(bpf_test_trace("Create"), 0);
1046 TESTSYSCALL(close(fd));
1047
1048 TESTSYSCALL(s_stat(s_path(s(ft_src), s(file_name)), &st));
1049 TEST(result = s_getxattr(s_path(s(mount_dir), s(file_name)), xattr_name,
1050 xattr_value_ret, sizeof(xattr_value_ret),
1051 &xattr_size_ret),
1052 result == -1);
1053 TESTEQUAL(errno, ENODATA);
1054 TESTEQUAL(bpf_test_trace("getxattr"), 0);
1055
1056 TESTSYSCALL(s_listxattr(s_path(s(mount_dir), s(file_name)),
1057 xattr_value_ret, sizeof(xattr_value_ret),
1058 &xattr_size_ret_se));
1059 TESTEQUAL(bpf_test_trace("listxattr"), 0);
1060
1061 TESTSYSCALL(s_setxattr(s_path(s(mount_dir), s(file_name)), xattr_name,
1062 xattr_value, xattr_size, 0));
1063 TESTEQUAL(bpf_test_trace("setxattr"), 0);
1064
1065 TESTSYSCALL(s_listxattr(s_path(s(mount_dir), s(file_name)),
1066 xattr_value_ret, sizeof(xattr_value_ret),
1067 &xattr_size_ret));
1068 TESTEQUAL(bpf_test_trace("listxattr"), 0);
1069 TESTEQUAL(xattr_size_ret - xattr_size_ret_se, sizeof(xattr_name));
1070 TESTEQUAL(strcmp(xattr_name, xattr_value_ret + xattr_size_ret_se), 0);
1071
1072 TESTSYSCALL(s_getxattr(s_path(s(mount_dir), s(file_name)), xattr_name,
1073 xattr_value_ret, sizeof(xattr_value_ret),
1074 &xattr_size_ret));
1075 TESTEQUAL(bpf_test_trace("getxattr"), 0);
1076 TESTEQUAL(xattr_size, xattr_size_ret);
1077 TESTEQUAL(strcmp(xattr_value, xattr_value_ret), 0);
1078
1079 TESTSYSCALL(s_removexattr(s_path(s(mount_dir), s(file_name)), xattr_name));
1080 TESTEQUAL(bpf_test_trace("removexattr"), 0);
1081
1082 TESTEQUAL(s_getxattr(s_path(s(mount_dir), s(file_name)), xattr_name,
1083 xattr_value_ret, sizeof(xattr_value_ret),
1084 &xattr_size_ret), -1);
1085 TESTEQUAL(errno, ENODATA);
1086
1087 TESTSYSCALL(s_unlink(s_path(s(mount_dir), s(file_name))));
1088 TESTEQUAL(bpf_test_trace("unlink"), 0);
1089 TESTEQUAL(s_stat(s_path(s(ft_src), s(file_name)), &st), -1);
1090 TESTEQUAL(errno, ENOENT);
1091
1092 result = TEST_SUCCESS;
1093 out:
1094 close(fuse_dev);
1095 umount(mount_dir);
1096 close(bpf_fd);
1097 close(src_fd);
1098 return result;
1099 }
1100
bpf_test_set_backing(const char * mount_dir)1101 static int bpf_test_set_backing(const char *mount_dir)
1102 {
1103 const char *backing_name = "backing";
1104 const char *test_data = "data";
1105 const char *test_name = "test";
1106
1107 int result = TEST_FAILURE;
1108 int fuse_dev = -1;
1109 int fd = -1;
1110 FUSE_DECLARE_DAEMON;
1111
1112 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1113 FUSE_START_DAEMON();
1114 if (action) {
1115 char data[256] = {0};
1116
1117 TESTERR(fd = s_open(s_path(s(mount_dir), s(test_name)),
1118 O_RDONLY | O_CLOEXEC), fd != -1);
1119 TESTEQUAL(read(fd, data, strlen(test_data)), strlen(test_data));
1120 TESTCOND(!strcmp(data, test_data));
1121 TESTSYSCALL(close(fd));
1122 fd = -1;
1123 TESTSYSCALL(umount(mount_dir));
1124 } else {
1125 int bpf_fd = -1;
1126 int backing_fd = -1;
1127
1128 TESTERR(backing_fd = s_creat(s_path(s(ft_src), s(backing_name)), 0777),
1129 backing_fd != -1);
1130 TESTEQUAL(write(backing_fd, test_data, strlen(test_data)),
1131 strlen(test_data));
1132 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_simple",
1133 &bpf_fd, NULL, NULL), 0);
1134
1135 TESTFUSEINIT();
1136 TESTFUSELOOKUP(test_name, 0);
1137 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {0}),
1138 fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1139 .backing_action = FUSE_ACTION_REPLACE,
1140 .backing_fd = backing_fd,
1141 .bpf_action = FUSE_ACTION_REPLACE,
1142 .bpf_fd = bpf_fd,
1143 }));
1144 read(fuse_dev, bytes_in, sizeof(bytes_in));
1145 TESTSYSCALL(close(bpf_fd));
1146 TESTSYSCALL(close(backing_fd));
1147 exit(TEST_SUCCESS);
1148 }
1149 FUSE_END_DAEMON();
1150 close(fuse_dev);
1151 close(fd);
1152 umount(mount_dir);
1153 return result;
1154 }
1155
bpf_test_remove_backing(const char * mount_dir)1156 static int bpf_test_remove_backing(const char *mount_dir)
1157 {
1158 const char *folder1 = "folder1";
1159 const char *folder2 = "folder2";
1160 const char *file = "file1";
1161 const char *contents1 = "contents1";
1162 const char *contents2 = "contents2";
1163
1164 int result = TEST_FAILURE;
1165 int fuse_dev = -1;
1166 int fd = -1;
1167 int src_fd = -1;
1168 int bpf_fd = -1;
1169 char data[256] = {0};
1170 FUSE_DECLARE_DAEMON;
1171
1172 /*
1173 * Create folder1/file
1174 * folder2/file
1175 *
1176 * test will install bpf into mount.
1177 * bpf will postfilter root lookup to daemon.
1178 * daemon will remove bpf and redirect opens on folder1 to folder2.
1179 * test will open folder1/file which will be redirected to folder2.
1180 * test will check no traces for file, and contents are folder2/file.
1181 */
1182 TESTEQUAL(bpf_clear_trace(), 0);
1183 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1184 TEST(fd = s_creat(s_pathn(3, s(ft_src), s(folder1), s(file)), 0777),
1185 fd != -1);
1186 TESTEQUAL(write(fd, contents1, strlen(contents1)), strlen(contents1));
1187 TESTSYSCALL(close(fd));
1188 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder2)), 0777));
1189 TEST(fd = s_creat(s_pathn(3, s(ft_src), s(folder2), s(file)), 0777),
1190 fd != -1);
1191 TESTEQUAL(write(fd, contents2, strlen(contents2)), strlen(contents2));
1192 TESTSYSCALL(close(fd));
1193
1194 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1195 src_fd != -1);
1196 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_passthrough", &bpf_fd,
1197 NULL, NULL), 0);
1198 TESTEQUAL(mount_fuse_no_init(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1199
1200 FUSE_START_DAEMON();
1201 if (action) {
1202 TESTERR(fd = s_open(s_pathn(3, s(mount_dir), s(folder1),
1203 s(file)),
1204 O_RDONLY | O_CLOEXEC), fd != -1);
1205 TESTEQUAL(read(fd, data, sizeof(data)), strlen(contents2));
1206 TESTCOND(!strcmp(data, contents2));
1207 TESTEQUAL(bpf_test_no_trace("file"), 0);
1208 TESTSYSCALL(close(fd));
1209 fd = -1;
1210 TESTSYSCALL(umount(mount_dir));
1211 } else {
1212 struct {
1213 char name[8];
1214 struct fuse_entry_out feo;
1215 struct fuse_entry_bpf_out febo;
1216 } __packed in;
1217 int backing_fd = -1;
1218
1219 TESTFUSEINIT();
1220 TESTFUSEIN(FUSE_LOOKUP | FUSE_POSTFILTER, &in);
1221 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder2)),
1222 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1223 backing_fd != -1);
1224 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {0}),
1225 fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1226 .bpf_action = FUSE_ACTION_REMOVE,
1227 .backing_action = FUSE_ACTION_REPLACE,
1228 .backing_fd = backing_fd,
1229 }));
1230
1231 while (read(fuse_dev, bytes_in, sizeof(bytes_in)) != -1)
1232 ;
1233 TESTSYSCALL(close(backing_fd));
1234 exit(TEST_SUCCESS);
1235 }
1236 FUSE_END_DAEMON();
1237 close(fuse_dev);
1238 close(fd);
1239 close(src_fd);
1240 close(bpf_fd);
1241 umount(mount_dir);
1242 return result;
1243 }
1244
bpf_test_dir_rename(const char * mount_dir)1245 static int bpf_test_dir_rename(const char *mount_dir)
1246 {
1247 const char *dir_name = "dir";
1248 const char *dir_name2 = "dir2";
1249 int result = TEST_FAILURE;
1250 int src_fd = -1;
1251 int bpf_fd = -1;
1252 int fuse_dev = -1;
1253 struct stat st;
1254
1255 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1256 src_fd != -1);
1257 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
1258 &bpf_fd, NULL, NULL), 0);
1259 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1260
1261 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s(dir_name)), 0777));
1262 TESTEQUAL(bpf_test_trace("mkdir"), 0);
1263 TESTSYSCALL(s_stat(s_path(s(ft_src), s(dir_name)), &st));
1264 TESTSYSCALL(s_rename(s_path(s(mount_dir), s(dir_name)),
1265 s_path(s(mount_dir), s(dir_name2))));
1266 TESTEQUAL(s_stat(s_path(s(ft_src), s(dir_name)), &st), -1);
1267 TESTEQUAL(errno, ENOENT);
1268 TESTSYSCALL(s_stat(s_path(s(ft_src), s(dir_name2)), &st));
1269 result = TEST_SUCCESS;
1270 out:
1271 close(fuse_dev);
1272 umount(mount_dir);
1273 close(bpf_fd);
1274 close(src_fd);
1275 return result;
1276 }
1277
bpf_test_file_rename(const char * mount_dir)1278 static int bpf_test_file_rename(const char *mount_dir)
1279 {
1280 const char *dir = "dir";
1281 const char *file1 = "file1";
1282 const char *file2 = "file2";
1283 int result = TEST_FAILURE;
1284 int src_fd = -1;
1285 int bpf_fd = -1;
1286 int fuse_dev = -1;
1287 int fd = -1;
1288
1289 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1290 src_fd != -1);
1291 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
1292 &bpf_fd, NULL, NULL), 0);
1293 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1294
1295 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s(dir)), 0777));
1296 TEST(fd = s_creat(s_pathn(3, s(mount_dir), s(dir), s(file1)), 0777),
1297 fd != -1);
1298 TESTSYSCALL(s_rename(s_pathn(3, s(mount_dir), s(dir), s(file1)),
1299 s_pathn(3, s(mount_dir), s(dir), s(file2))));
1300 result = TEST_SUCCESS;
1301 out:
1302 close(fd);
1303 umount(mount_dir);
1304 close(fuse_dev);
1305 close(bpf_fd);
1306 close(src_fd);
1307 return result;
1308 }
1309
mmap_test(const char * mount_dir)1310 static int mmap_test(const char *mount_dir)
1311 {
1312 const char *file = "file";
1313 int result = TEST_FAILURE;
1314 int src_fd = -1;
1315 int fuse_dev = -1;
1316 int fd = -1;
1317 char *addr = NULL;
1318
1319 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1320 src_fd != -1);
1321 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
1322 TEST(fd = s_open(s_path(s(mount_dir), s(file)),
1323 O_CREAT | O_RDWR | O_CLOEXEC, 0777),
1324 fd != -1);
1325 TESTSYSCALL(fallocate(fd, 0, 4096, SEEK_CUR));
1326 TEST(addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0),
1327 addr != (void *) -1);
1328 memset(addr, 'a', 4096);
1329
1330 result = TEST_SUCCESS;
1331 out:
1332 munmap(addr, 4096);
1333 close(fd);
1334 umount(mount_dir);
1335 close(fuse_dev);
1336 close(src_fd);
1337 return result;
1338 }
1339
flock_test(const char * mount_dir)1340 static int flock_test(const char *mount_dir)
1341 {
1342 const char *file = "file";
1343 int result = TEST_FAILURE;
1344 int src_fd = -1;
1345 int fuse_dev = -1;
1346 int fd = -1, fd2 = -1;
1347 int backing_fd = -1;
1348
1349 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1350 src_fd != -1);
1351 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
1352 TEST(fd = s_open(s_path(s(mount_dir), s(file)),
1353 O_CREAT | O_RDWR | O_CLOEXEC, 0777),
1354 fd != -1);
1355 TEST(fd2 = s_open(s_path(s(mount_dir), s(file)),
1356 O_RDWR | O_CLOEXEC, 0777),
1357 fd2 != -1);
1358 TESTSYSCALL(flock(fd, LOCK_EX | LOCK_NB));
1359 TESTCONDERR((flock(fd2, LOCK_EX | LOCK_NB)) == -1);
1360 TESTCOND(errno == EAGAIN);
1361 TESTSYSCALL(flock(fd, LOCK_UN));
1362 TESTSYSCALL(flock(fd2, LOCK_EX | LOCK_NB));
1363 TEST(backing_fd = s_open(s_path(s(ft_src), s(file)),
1364 O_RDONLY | O_CLOEXEC),
1365 backing_fd != -1);
1366 TESTCONDERR((flock(backing_fd, LOCK_EX | LOCK_NB)) == -1);
1367 TESTCOND(errno == EAGAIN);
1368 close(fd2);
1369 fd2 = 0;
1370 TESTSYSCALL(flock(backing_fd, LOCK_EX | LOCK_NB));
1371
1372 result = TEST_SUCCESS;
1373 out:
1374 close(fd);
1375 close(fd2);
1376 close(backing_fd);
1377 umount(mount_dir);
1378 close(fuse_dev);
1379 close(src_fd);
1380 return result;
1381 }
1382
readdir_perms_test(const char * mount_dir)1383 static int readdir_perms_test(const char *mount_dir)
1384 {
1385 int result = TEST_FAILURE;
1386 struct __user_cap_header_struct uchs = { _LINUX_CAPABILITY_VERSION_3 };
1387 struct __user_cap_data_struct ucds[2];
1388 int src_fd = -1;
1389 int fuse_dev = -1;
1390 DIR *dir = NULL;
1391
1392 /* Must remove capabilities for this test. */
1393 TESTSYSCALL(syscall(SYS_capget, &uchs, ucds));
1394 ucds[0].effective &= ~(1 << CAP_DAC_OVERRIDE | 1 << CAP_DAC_READ_SEARCH);
1395 TESTSYSCALL(syscall(SYS_capset, &uchs, ucds));
1396
1397 /* This is what we are testing in fuseland. First test without fuse, */
1398 TESTSYSCALL(mkdir("test", 0111));
1399 TEST(dir = opendir("test"), dir == NULL);
1400 closedir(dir);
1401 dir = NULL;
1402
1403 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1404 src_fd != -1);
1405 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
1406
1407 TESTSYSCALL(s_mkdir(s_path(s(mount_dir), s("test")), 0111));
1408 TEST(dir = s_opendir(s_path(s(mount_dir), s("test"))), dir == NULL);
1409
1410 result = TEST_SUCCESS;
1411 out:
1412 ucds[0].effective |= 1 << CAP_DAC_OVERRIDE | 1 << CAP_DAC_READ_SEARCH;
1413 syscall(SYS_capset, &uchs, ucds);
1414
1415 closedir(dir);
1416 s_rmdir(s_path(s(mount_dir), s("test")));
1417 umount(mount_dir);
1418 close(fuse_dev);
1419 close(src_fd);
1420 rmdir("test");
1421 return result;
1422 }
1423
inotify_test(const char * mount_dir)1424 static int inotify_test(const char *mount_dir)
1425 {
1426 int result = TEST_FAILURE;
1427 int src_fd = -1;
1428 int fuse_dev = -1;
1429 struct s dir;
1430 int inotify_fd = -1;
1431 int watch;
1432 int fd = -1;
1433 char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
1434
1435 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1436 src_fd != -1);
1437 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
1438
1439 TEST(inotify_fd = inotify_init1(IN_CLOEXEC), inotify_fd != -1);
1440 dir = s_path(s(mount_dir), s("dir"));
1441 TESTSYSCALL(mkdir(dir.s, 0777));
1442 TEST(watch = inotify_add_watch(inotify_fd, dir.s, IN_CREATE), watch);
1443 TEST(fd = s_creat(s_path(s(ft_src), s("dir/file")), 0777), fd != -1);
1444 // buffer will be two struct lengths, as "file" gets rounded up to the
1445 // next multiple of struct inotify_event
1446 TESTEQUAL(read(inotify_fd, &buffer, sizeof(buffer)),
1447 sizeof(struct inotify_event) * 2);
1448
1449 result = TEST_SUCCESS;
1450 out:
1451 close(fd);
1452 s_unlink(s_path(s(ft_src), s("dir/file")));
1453 close(inotify_fd);
1454 rmdir(dir.s);
1455 free(dir.s);
1456 umount(mount_dir);
1457 close(fuse_dev);
1458 close(src_fd);
1459 return result;
1460 }
1461
bpf_test_statfs(const char * mount_dir)1462 static int bpf_test_statfs(const char *mount_dir)
1463 {
1464 int result = TEST_FAILURE;
1465 int src_fd = -1;
1466 int bpf_fd = -1;
1467 int fuse_dev = -1;
1468 int fd = -1;
1469 struct statfs st;
1470
1471 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1472 src_fd != -1);
1473 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
1474 &bpf_fd, NULL, NULL), 0);
1475 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1476
1477 TESTSYSCALL(s_statfs(s(mount_dir), &st));
1478 TESTEQUAL(bpf_test_trace("statfs"), 0);
1479 TESTEQUAL(st.f_type, 0x65735546);
1480 result = TEST_SUCCESS;
1481 out:
1482 close(fd);
1483 umount(mount_dir);
1484 close(fuse_dev);
1485 close(bpf_fd);
1486 close(src_fd);
1487 return result;
1488 }
1489
bpf_test_lseek(const char * mount_dir)1490 static int bpf_test_lseek(const char *mount_dir)
1491 {
1492 const char *file = "real";
1493 const char *sparse_file = "sparse";
1494 const off_t sparse_length = 0x100000000u;
1495 const char *test_data = "data";
1496 int result = TEST_FAILURE;
1497 int src_fd = -1;
1498 int bpf_fd = -1;
1499 int fuse_dev = -1;
1500 int fd = -1;
1501
1502 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1503 src_fd != -1);
1504 TEST(fd = openat(src_fd, file, O_CREAT | O_RDWR | O_CLOEXEC, 0777),
1505 fd != -1);
1506 TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
1507 TESTSYSCALL(close(fd));
1508 fd = -1;
1509 TEST(fd = openat(src_fd, sparse_file, O_CREAT | O_RDWR | O_CLOEXEC,
1510 0777),
1511 fd != -1);
1512 TESTSYSCALL(ftruncate(fd, sparse_length));
1513 TESTSYSCALL(close(fd));
1514 fd = -1;
1515 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
1516 &bpf_fd, NULL, NULL), 0);
1517 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1518
1519 TEST(fd = s_open(s_path(s(mount_dir), s(file)), O_RDONLY | O_CLOEXEC),
1520 fd != -1);
1521 TESTEQUAL(lseek(fd, 3, SEEK_SET), 3);
1522 TESTEQUAL(bpf_test_trace("lseek"), 0);
1523 TESTEQUAL(lseek(fd, 5, SEEK_END), 9);
1524 TESTEQUAL(bpf_test_trace("lseek"), 0);
1525 TESTEQUAL(lseek(fd, 1, SEEK_CUR), 10);
1526 TESTEQUAL(bpf_test_trace("lseek"), 0);
1527 TESTEQUAL(lseek(fd, 1, SEEK_DATA), 1);
1528 TESTEQUAL(bpf_test_trace("lseek"), 0);
1529 TESTSYSCALL(close(fd));
1530 fd = -1;
1531
1532 TEST(fd = s_open(s_path(s(mount_dir), s(sparse_file)),
1533 O_RDONLY | O_CLOEXEC),
1534 fd != -1);
1535 TESTEQUAL(lseek(fd, -256, SEEK_END), sparse_length - 256);
1536 TESTEQUAL(lseek(fd, 0, SEEK_CUR), sparse_length - 256);
1537
1538 TESTSYSCALL(close(fd));
1539 fd = -1;
1540
1541 result = TEST_SUCCESS;
1542 out:
1543 close(fd);
1544 umount(mount_dir);
1545 close(fuse_dev);
1546 close(bpf_fd);
1547 close(src_fd);
1548 return result;
1549 }
1550
1551 /*
1552 * State:
1553 * Original: dst/folder1/content.txt
1554 * ^
1555 * |
1556 * |
1557 * Backing: src/folder1/content.txt
1558 *
1559 * Step 1: open(folder1) - set backing to src/folder1
1560 * Check 1: cat(content.txt) - check not receiving call on the fuse daemon
1561 * and content is the same
1562 * Step 2: readdirplus(dst)
1563 * Check 2: cat(content.txt) - check not receiving call on the fuse daemon
1564 * and content is the same
1565 */
bpf_test_readdirplus_not_overriding_backing(const char * mount_dir)1566 static int bpf_test_readdirplus_not_overriding_backing(const char *mount_dir)
1567 {
1568 const char *folder1 = "folder1";
1569 const char *content_file = "content.txt";
1570 const char *content = "hello world";
1571
1572 int result = TEST_FAILURE;
1573 int fuse_dev = -1;
1574 int src_fd = -1;
1575 int content_fd = -1;
1576 FUSE_DECLARE_DAEMON;
1577
1578 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1579 TEST(content_fd = s_creat(s_pathn(3, s(ft_src), s(folder1), s(content_file)), 0777),
1580 content_fd != -1);
1581 TESTEQUAL(write(content_fd, content, strlen(content)), strlen(content));
1582 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1583
1584 FUSE_START_DAEMON();
1585 if (action) {
1586 DIR *open_mount_dir = NULL;
1587 struct dirent *mount_dirent;
1588 int dst_folder1_fd = -1;
1589 int dst_content_fd = -1;
1590 char content_buffer[12];
1591
1592 // Step 1: Lookup folder1
1593 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1594 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1595
1596 // Check 1: Read content file (backed)
1597 TESTERR(dst_content_fd =
1598 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1599 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1600
1601 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1602 strlen(content));
1603 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1604
1605 TESTSYSCALL(close(dst_content_fd));
1606 dst_content_fd = -1;
1607 TESTSYSCALL(close(dst_folder1_fd));
1608 dst_folder1_fd = -1;
1609 memset(content_buffer, 0, strlen(content));
1610
1611 // Step 2: readdir folder 1
1612 TEST(open_mount_dir = s_opendir(s(mount_dir)),
1613 open_mount_dir != NULL);
1614 TEST(mount_dirent = readdir(open_mount_dir), mount_dirent != NULL);
1615 TESTSYSCALL(closedir(open_mount_dir));
1616 open_mount_dir = NULL;
1617
1618 // Check 2: Read content file again (must be backed)
1619 TESTERR(dst_content_fd =
1620 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1621 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1622
1623 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1624 strlen(content));
1625 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1626
1627 TESTSYSCALL(close(dst_content_fd));
1628 dst_content_fd = -1;
1629 } else {
1630 size_t read_size = 0;
1631 struct fuse_in_header *in_header = (struct fuse_in_header *)bytes_in;
1632 struct fuse_read_out *read_out = NULL;
1633 struct fuse_attr attr = {};
1634 int backing_fd = -1;
1635 DECL_FUSE_IN(open);
1636 DECL_FUSE_IN(getattr);
1637
1638 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1639
1640 // Step 1: Lookup folder 1 with backing
1641 TESTFUSELOOKUP(folder1, 0);
1642 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1643 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1644 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1645 backing_fd != -1);
1646 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1647 .nodeid = attr.ino,
1648 .generation = 0,
1649 .entry_valid = UINT64_MAX,
1650 .attr_valid = UINT64_MAX,
1651 .entry_valid_nsec = UINT32_MAX,
1652 .attr_valid_nsec = UINT32_MAX,
1653 .attr = attr,
1654 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1655 .backing_action = FUSE_ACTION_REPLACE,
1656 .backing_fd = backing_fd,
1657 }));
1658 TESTSYSCALL(close(backing_fd));
1659
1660 // Step 2: Open root dir
1661 TESTFUSEIN(FUSE_OPENDIR, open_in);
1662 TESTFUSEOUT1(fuse_open_out, ((struct fuse_open_out) {
1663 .fh = 100,
1664 .open_flags = open_in->flags
1665 }));
1666
1667 // Step 2: Handle getattr
1668 TESTFUSEIN(FUSE_GETATTR, getattr_in);
1669 TESTSYSCALL(s_fuse_attr(s(ft_src), &attr));
1670 TESTFUSEOUT1(fuse_attr_out, ((struct fuse_attr_out) {
1671 .attr_valid = UINT64_MAX,
1672 .attr_valid_nsec = UINT32_MAX,
1673 .attr = attr
1674 }));
1675
1676 // Step 2: Handle readdirplus
1677 read_size = read(fuse_dev, bytes_in, sizeof(bytes_in));
1678 TESTEQUAL(in_header->opcode, FUSE_READDIRPLUS);
1679
1680 struct fuse_direntplus *dirent_plus =
1681 (struct fuse_direntplus *) (bytes_in + read_size);
1682 struct fuse_dirent dirent;
1683 struct fuse_entry_out entry_out;
1684
1685 read_out = (struct fuse_read_out *) (bytes_in +
1686 sizeof(*in_header) +
1687 sizeof(struct fuse_read_in));
1688
1689 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1690
1691 dirent = (struct fuse_dirent) {
1692 .ino = attr.ino,
1693 .off = 1,
1694 .namelen = strlen(folder1),
1695 .type = DT_REG
1696 };
1697 entry_out = (struct fuse_entry_out) {
1698 .nodeid = attr.ino,
1699 .generation = 0,
1700 .entry_valid = UINT64_MAX,
1701 .attr_valid = UINT64_MAX,
1702 .entry_valid_nsec = UINT32_MAX,
1703 .attr_valid_nsec = UINT32_MAX,
1704 .attr = attr
1705 };
1706 *dirent_plus = (struct fuse_direntplus) {
1707 .dirent = dirent,
1708 .entry_out = entry_out
1709 };
1710
1711 strcpy((char *)(bytes_in + read_size + sizeof(*dirent_plus)), folder1);
1712 read_size += FUSE_DIRENT_ALIGN(sizeof(*dirent_plus) + strlen(folder1) +
1713 1);
1714 TESTFUSEDIROUTREAD(read_out,
1715 bytes_in +
1716 sizeof(struct fuse_in_header) +
1717 sizeof(struct fuse_read_in) +
1718 sizeof(struct fuse_read_out),
1719 read_size - sizeof(struct fuse_in_header) -
1720 sizeof(struct fuse_read_in) -
1721 sizeof(struct fuse_read_out));
1722 exit(TEST_SUCCESS);
1723 }
1724 FUSE_END_DAEMON();
1725 close(fuse_dev);
1726 close(content_fd);
1727 close(src_fd);
1728 umount(mount_dir);
1729 return result;
1730 }
1731
bpf_test_no_readdirplus_without_nodeid(const char * mount_dir)1732 static int bpf_test_no_readdirplus_without_nodeid(const char *mount_dir)
1733 {
1734 const char *folder1 = "folder1";
1735 const char *folder2 = "folder2";
1736 int result = TEST_FAILURE;
1737 int fuse_dev = -1;
1738 int src_fd = -1;
1739 int content_fd = -1;
1740 int bpf_fd = -1;
1741 FUSE_DECLARE_DAEMON;
1742
1743 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_readdirplus",
1744 &bpf_fd, NULL, NULL), 0);
1745 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1746 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder2)), 0777));
1747 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1748 FUSE_START_DAEMON();
1749 if (action) {
1750 DIR *open_dir = NULL;
1751 struct dirent *dirent;
1752
1753 // Folder 1: Readdir with no nodeid
1754 TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder1))),
1755 open_dir != NULL);
1756 TEST(dirent = readdir(open_dir), dirent == NULL);
1757 TESTCOND(errno == EINVAL);
1758 TESTSYSCALL(closedir(open_dir));
1759 open_dir = NULL;
1760
1761 // Folder 2: Readdir with a nodeid
1762 TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder2))),
1763 open_dir != NULL);
1764 TEST(dirent = readdir(open_dir), dirent == NULL);
1765 TESTCOND(errno == EINVAL);
1766 TESTSYSCALL(closedir(open_dir));
1767 open_dir = NULL;
1768 } else {
1769 size_t read_size;
1770 struct fuse_in_header *in_header = (struct fuse_in_header *)bytes_in;
1771 struct fuse_attr attr = {};
1772 int backing_fd = -1;
1773
1774 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1775
1776 // folder 1: Set 0 as nodeid, Expect READDIR
1777 TESTFUSELOOKUP(folder1, 0);
1778 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1779 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1780 backing_fd != -1);
1781 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1782 .nodeid = 0,
1783 .generation = 0,
1784 .entry_valid = UINT64_MAX,
1785 .attr_valid = UINT64_MAX,
1786 .entry_valid_nsec = UINT32_MAX,
1787 .attr_valid_nsec = UINT32_MAX,
1788 .attr = attr,
1789 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1790 .backing_action = FUSE_ACTION_REPLACE,
1791 .backing_fd = backing_fd,
1792 .bpf_action = FUSE_ACTION_REPLACE,
1793 .bpf_fd = bpf_fd,
1794 }));
1795 TESTSYSCALL(close(backing_fd));
1796 TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
1797 TESTEQUAL(in_header->opcode, FUSE_READDIR);
1798 TESTFUSEOUTERROR(-EINVAL);
1799
1800 // folder 2: Set 10 as nodeid, Expect READDIRPLUS
1801 TESTFUSELOOKUP(folder2, 0);
1802 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder2)),
1803 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1804 backing_fd != -1);
1805 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1806 .nodeid = 10,
1807 .generation = 0,
1808 .entry_valid = UINT64_MAX,
1809 .attr_valid = UINT64_MAX,
1810 .entry_valid_nsec = UINT32_MAX,
1811 .attr_valid_nsec = UINT32_MAX,
1812 .attr = attr,
1813 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1814 .backing_action = FUSE_ACTION_REPLACE,
1815 .backing_fd = backing_fd,
1816 .bpf_action = FUSE_ACTION_REPLACE,
1817 .bpf_fd = bpf_fd,
1818 }));
1819 TESTSYSCALL(close(backing_fd));
1820 TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
1821 TESTEQUAL(in_header->opcode, FUSE_READDIRPLUS);
1822 TESTFUSEOUTERROR(-EINVAL);
1823 exit(TEST_SUCCESS);
1824 }
1825 FUSE_END_DAEMON();
1826 close(fuse_dev);
1827 close(content_fd);
1828 close(src_fd);
1829 close(bpf_fd);
1830 umount(mount_dir);
1831 return result;
1832 }
1833
1834 /*
1835 * State:
1836 * Original: dst/folder1/content.txt
1837 * ^
1838 * |
1839 * |
1840 * Backing: src/folder1/content.txt
1841 *
1842 * Step 1: open(folder1) - lookup folder1 with entry_timeout set to 0
1843 * Step 2: open(folder1) - lookup folder1 again to trigger revalidate wich will
1844 * set backing fd
1845 *
1846 * Check 1: cat(content.txt) - check not receiving call on the fuse daemon
1847 * and content is the same
1848 */
bpf_test_revalidate_handle_backing_fd(const char * mount_dir)1849 static int bpf_test_revalidate_handle_backing_fd(const char *mount_dir)
1850 {
1851 const char *folder1 = "folder1";
1852 const char *content_file = "content.txt";
1853 const char *content = "hello world";
1854 int result = TEST_FAILURE;
1855 int fuse_dev = -1;
1856 int src_fd = -1;
1857 int content_fd = -1;
1858 FUSE_DECLARE_DAEMON;
1859
1860 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1861 TEST(content_fd = s_creat(s_pathn(3, s(ft_src), s(folder1), s(content_file)), 0777),
1862 content_fd != -1);
1863 TESTEQUAL(write(content_fd, content, strlen(content)), strlen(content));
1864 TESTSYSCALL(close(content_fd));
1865 content_fd = -1;
1866 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1867 FUSE_START_DAEMON();
1868 if (action) {
1869 int dst_folder1_fd = -1;
1870 int dst_content_fd = -1;
1871 char content_buffer[9] = {0};
1872 // Step 1: Lookup folder1
1873 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1874 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1875 TESTSYSCALL(close(dst_folder1_fd));
1876 dst_folder1_fd = -1;
1877 // Step 2: Lookup folder1 again
1878 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1879 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1880 TESTSYSCALL(close(dst_folder1_fd));
1881 dst_folder1_fd = -1;
1882 // Check 1: Read content file (must be backed)
1883 TESTERR(dst_content_fd =
1884 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1885 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1886 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1887 strlen(content));
1888 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1889 TESTSYSCALL(close(dst_content_fd));
1890 dst_content_fd = -1;
1891 } else {
1892 struct fuse_attr attr = {};
1893 int backing_fd = -1;
1894
1895 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1896 // Step 1: Lookup folder1 set entry_timeout to 0 to trigger
1897 // revalidate later
1898 TESTFUSELOOKUP(folder1, 0);
1899 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1900 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1901 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1902 backing_fd != -1);
1903 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1904 .nodeid = attr.ino,
1905 .generation = 0,
1906 .entry_valid = 0,
1907 .attr_valid = UINT64_MAX,
1908 .entry_valid_nsec = 0,
1909 .attr_valid_nsec = UINT32_MAX,
1910 .attr = attr,
1911 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1912 .backing_action = FUSE_ACTION_REPLACE,
1913 .backing_fd = backing_fd,
1914 }));
1915 TESTSYSCALL(close(backing_fd));
1916 // Step 1: Lookup folder1 as a reaction to revalidate call
1917 // This attempts to change the backing node, which is not allowed on revalidate
1918 TESTFUSELOOKUP(folder1, 0);
1919 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1920 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1921 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1922 backing_fd != -1);
1923 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1924 .nodeid = attr.ino,
1925 .generation = 0,
1926 .entry_valid = UINT64_MAX,
1927 .attr_valid = UINT64_MAX,
1928 .entry_valid_nsec = UINT32_MAX,
1929 .attr_valid_nsec = UINT32_MAX,
1930 .attr = attr,
1931 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1932 .backing_action = FUSE_ACTION_REPLACE,
1933 .backing_fd = backing_fd,
1934 }));
1935 TESTSYSCALL(close(backing_fd));
1936
1937 // Lookup folder1 as a reaction to failed revalidate
1938 TESTFUSELOOKUP(folder1, 0);
1939 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1940 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1941 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1942 backing_fd != -1);
1943 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1944 .nodeid = attr.ino,
1945 .generation = 0,
1946 .entry_valid = UINT64_MAX,
1947 .attr_valid = UINT64_MAX,
1948 .entry_valid_nsec = UINT32_MAX,
1949 .attr_valid_nsec = UINT32_MAX,
1950 .attr = attr,
1951 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1952 .backing_action = FUSE_ACTION_REPLACE,
1953 .backing_fd = backing_fd,
1954 }));
1955 TESTSYSCALL(close(backing_fd));
1956 exit(TEST_SUCCESS);
1957 }
1958 FUSE_END_DAEMON();
1959 close(fuse_dev);
1960 close(content_fd);
1961 close(src_fd);
1962 umount(mount_dir);
1963 return result;
1964 }
1965
bpf_test_lookup_postfilter(const char * mount_dir)1966 static int bpf_test_lookup_postfilter(const char *mount_dir)
1967 {
1968 const char *file1_name = "file1";
1969 const char *file2_name = "file2";
1970 const char *file3_name = "file3";
1971 int result = TEST_FAILURE;
1972 int bpf_fd = -1;
1973 int src_fd = -1;
1974 int fuse_dev = -1;
1975 int file_fd = -1;
1976 FUSE_DECLARE_DAEMON;
1977
1978 TEST(file_fd = s_creat(s_path(s(ft_src), s(file1_name)), 0777),
1979 file_fd != -1);
1980 TESTSYSCALL(close(file_fd));
1981 TEST(file_fd = s_creat(s_path(s(ft_src), s(file2_name)), 0777),
1982 file_fd != -1);
1983 TESTSYSCALL(close(file_fd));
1984 file_fd = -1;
1985 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_lookup_postfilter",
1986 &bpf_fd, NULL, NULL), 0);
1987 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1988 src_fd != -1);
1989 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1990 FUSE_START_DAEMON();
1991 if (action) {
1992 int fd = -1;
1993
1994 TESTEQUAL(s_open(s_path(s(mount_dir), s(file1_name)), O_RDONLY),
1995 -1);
1996 TESTEQUAL(errno, ENOENT);
1997 TEST(fd = s_open(s_path(s(mount_dir), s(file2_name)), O_RDONLY),
1998 fd != -1);
1999 TESTSYSCALL(close(fd));
2000 TESTEQUAL(s_open(s_path(s(mount_dir), s(file3_name)), O_RDONLY),
2001 -1);
2002 } else {
2003 struct fuse_in_postfilter_header *in_header =
2004 (struct fuse_in_postfilter_header *)bytes_in;
2005 struct fuse_entry_out *feo;
2006 struct fuse_entry_bpf_out *febo;
2007
2008 TESTFUSELOOKUP(file1_name, FUSE_POSTFILTER);
2009 TESTFUSEOUTERROR(-ENOENT);
2010
2011 TESTFUSELOOKUP(file2_name, FUSE_POSTFILTER);
2012 feo = (struct fuse_entry_out *) (bytes_in +
2013 sizeof(struct fuse_in_header) + strlen(file2_name) + 1);
2014 febo = (struct fuse_entry_bpf_out *) ((char *)feo +
2015 sizeof(*feo));
2016 TESTFUSEOUT2(fuse_entry_out, *feo, fuse_entry_bpf_out, *febo);
2017
2018 TESTFUSELOOKUP(file3_name, FUSE_POSTFILTER);
2019 TESTEQUAL(in_header->error_in, -ENOENT);
2020 TESTFUSEOUTERROR(-ENOENT);
2021 exit(TEST_SUCCESS);
2022 }
2023 FUSE_END_DAEMON();
2024 close(file_fd);
2025 close(fuse_dev);
2026 umount(mount_dir);
2027 close(src_fd);
2028 close(bpf_fd);
2029 return result;
2030 }
2031
2032 /**
2033 * Test that a file made via create_and_open correctly gets the bpf assigned
2034 * from the negative lookup
2035 * bpf blocks file open, but also removes itself from children
2036 * This test will fail if the 'remove' is unsuccessful
2037 */
bpf_test_create_and_remove_bpf(const char * mount_dir)2038 static int bpf_test_create_and_remove_bpf(const char *mount_dir)
2039 {
2040 const char *file = "file";
2041
2042 int result = TEST_FAILURE;
2043 int src_fd = -1;
2044 int bpf_fd = -1;
2045 int fuse_dev = -1;
2046 int fd = -1;
2047 int fd2 = -1;
2048
2049 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2050 src_fd != -1);
2051 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_create_remove", &bpf_fd,
2052 NULL, NULL), 0);
2053 TESTEQUAL(mount_fuse_no_init(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
2054 TEST(fd = s_creat(s_path(s(mount_dir), s(file)), 0777),
2055 fd != -1);
2056 TEST(fd2 = s_open(s_path(s(mount_dir), s(file)), O_RDONLY),
2057 fd2 != -1);
2058
2059 result = TEST_SUCCESS;
2060 out:
2061 close(fd2);
2062 close(fd);
2063 close(fuse_dev);
2064 close(bpf_fd);
2065 close(src_fd);
2066 umount(mount_dir);
2067 return result;
2068 }
2069
bpf_test_mkdir_and_remove_bpf(const char * mount_dir)2070 static int bpf_test_mkdir_and_remove_bpf(const char *mount_dir)
2071 {
2072 const char *dir = "dir";
2073
2074 int result = TEST_FAILURE;
2075 int src_fd = -1;
2076 int bpf_fd = -1;
2077 int fuse_dev = -1;
2078 int fd = -1;
2079 int fd2 = -1;
2080
2081 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2082 src_fd != -1);
2083 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_mkdir_remove", &bpf_fd,
2084 NULL, NULL), 0);
2085 TESTEQUAL(mount_fuse_no_init(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
2086 TEST(fd = s_mkdir(s_path(s(mount_dir), s(dir)), 0777),
2087 fd != -1);
2088 TEST(fd2 = s_open(s_path(s(mount_dir), s(dir)), O_RDONLY),
2089 fd2 != -1);
2090
2091 result = TEST_SUCCESS;
2092 out:
2093 close(fd2);
2094 close(fd);
2095 close(fuse_dev);
2096 close(bpf_fd);
2097 close(src_fd);
2098 umount(mount_dir);
2099 return result;
2100 }
2101
bpf_test_readahead(const char * mount_dir)2102 static int bpf_test_readahead(const char *mount_dir)
2103 {
2104 const char *file_name = "file";
2105
2106 int result = TEST_FAILURE;
2107 int file_fd = -1;
2108 int src_fd = -1;
2109 int fuse_dev = -1;
2110
2111 TEST(file_fd = s_creat(s_path(s(ft_src), s(file_name)), 0777),
2112 file_fd != -1);
2113 TESTSYSCALL(fallocate(file_fd, 0, 0, 4096));
2114 TESTSYSCALL(close(file_fd));
2115 file_fd = -1;
2116
2117 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2118 src_fd != -1);
2119 TEST(fuse_dev = open("/dev/fuse", O_RDWR | O_CLOEXEC), fuse_dev != -1);
2120 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
2121
2122 TEST(file_fd = s_open(s_path(s(mount_dir), s(file_name)), O_RDONLY),
2123 file_fd != -1);
2124 TESTSYSCALL(posix_fadvise(file_fd, 0, 4096, POSIX_FADV_WILLNEED));
2125 usleep(1000);
2126 TESTSYSCALL(close(file_fd));
2127 file_fd = -1;
2128 result = TEST_SUCCESS;
2129 out:
2130 umount(mount_dir);
2131 close(fuse_dev);
2132 close(src_fd);
2133 close(file_fd);
2134 return result;
2135 }
2136
2137 /**
2138 * Test that fuse passthrough correctly traverses a mount point on the lower fs
2139 */
bpf_test_follow_mounts(const char * mount_dir)2140 static int bpf_test_follow_mounts(const char *mount_dir)
2141 {
2142 const char *bind_src = "bind_src";
2143 const char *bind_dst = "bind_dst";
2144 const char *file = "file";
2145 int fd = -1;
2146 int src_fd = -1;
2147 int result = TEST_FAILURE;
2148
2149 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_src)), 0777));
2150 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_dst)), 0777));
2151 TEST(fd = s_creat(s_pathn(3, s(ft_src), s(bind_src), s(file)), 0777),
2152 fd != -1);
2153 TESTSYSCALL(close(fd));
2154 fd = -1;
2155 TESTSYSCALL(s_mount(s_path(s(ft_src), s(bind_src)),
2156 s_path(s(ft_src), s(bind_dst)),
2157 s(NULL), MS_BIND, s(NULL)));
2158 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2159 src_fd != -1);
2160 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, src_fd, NULL), 0);
2161 TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_src), s(file)),
2162 O_RDONLY),
2163 fd != -1);
2164 TESTSYSCALL(close(fd));
2165 fd = -1;
2166 TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_dst), s(file)),
2167 O_RDONLY),
2168 fd != -1);
2169 TESTSYSCALL(close(fd));
2170 fd = -1;
2171
2172 result = TEST_SUCCESS;
2173 out:
2174 umount(mount_dir);
2175 close(src_fd);
2176 s_umount(s_path(s(ft_src), s(bind_dst)));
2177 close(fd);
2178 return result;
2179 }
2180
parse_range(const char * ranges,bool * run_test,size_t tests)2181 static void parse_range(const char *ranges, bool *run_test, size_t tests)
2182 {
2183 size_t i;
2184 char *range;
2185
2186 for (i = 0; i < tests; ++i)
2187 run_test[i] = false;
2188
2189 range = strtok(optarg, ",");
2190 while (range) {
2191 char *dash = strchr(range, '-');
2192
2193 if (dash) {
2194 size_t start = 1, end = tests;
2195 char *end_ptr;
2196
2197 if (dash > range) {
2198 start = strtol(range, &end_ptr, 10);
2199 if (*end_ptr != '-' || start <= 0 || start > tests)
2200 ksft_exit_fail_msg("Bad range\n");
2201 }
2202
2203 if (dash[1]) {
2204 end = strtol(dash + 1, &end_ptr, 10);
2205 if (*end_ptr || end <= start || end > tests)
2206 ksft_exit_fail_msg("Bad range\n");
2207 }
2208
2209 for (i = start; i <= end; ++i)
2210 run_test[i - 1] = true;
2211 } else {
2212 char *end;
2213 long value = strtol(range, &end, 10);
2214
2215 if (*end || value <= 0 || value > tests)
2216 ksft_exit_fail_msg("Bad range\n");
2217 run_test[value - 1] = true;
2218 }
2219 range = strtok(NULL, ",");
2220 }
2221 }
2222
parse_options(int argc,char * const * argv,bool * run_test,size_t tests)2223 static int parse_options(int argc, char *const *argv, bool *run_test,
2224 size_t tests)
2225 {
2226 signed char c;
2227
2228 while ((c = getopt(argc, argv, "f:t:v")) != -1)
2229 switch (c) {
2230 case 'f':
2231 test_options.file = strtol(optarg, NULL, 10);
2232 break;
2233
2234 case 't':
2235 parse_range(optarg, run_test, tests);
2236 break;
2237
2238 case 'v':
2239 test_options.verbose = true;
2240 break;
2241
2242 default:
2243 return -EINVAL;
2244 }
2245
2246 return 0;
2247 }
2248
2249 struct test_case {
2250 int (*pfunc)(const char *dir);
2251 const char *name;
2252 };
2253
run_one_test(const char * mount_dir,const struct test_case * test_case)2254 static void run_one_test(const char *mount_dir,
2255 const struct test_case *test_case)
2256 {
2257 ksft_print_msg("Running %s\n", test_case->name);
2258 if (test_case->pfunc(mount_dir) == TEST_SUCCESS)
2259 ksft_test_result_pass("%s\n", test_case->name);
2260 else
2261 ksft_test_result_fail("%s\n", test_case->name);
2262 }
2263
main(int argc,char * argv[])2264 int main(int argc, char *argv[])
2265 {
2266 char *mount_dir = NULL;
2267 char *src_dir = NULL;
2268 int i;
2269 int fd, count;
2270
2271 #define MAKE_TEST(test) \
2272 { \
2273 test, #test \
2274 }
2275 const struct test_case cases[] = {
2276 MAKE_TEST(basic_test),
2277 MAKE_TEST(bpf_test_real),
2278 MAKE_TEST(bpf_test_partial),
2279 MAKE_TEST(bpf_test_attrs),
2280 MAKE_TEST(bpf_test_readdir),
2281 MAKE_TEST(bpf_test_creat),
2282 MAKE_TEST(bpf_test_hidden_entries),
2283 MAKE_TEST(bpf_test_dir),
2284 MAKE_TEST(bpf_test_file_early_close),
2285 MAKE_TEST(bpf_test_file_late_close),
2286 MAKE_TEST(bpf_test_mknod),
2287 MAKE_TEST(bpf_test_largedir),
2288 MAKE_TEST(bpf_test_link),
2289 MAKE_TEST(bpf_test_symlink),
2290 MAKE_TEST(bpf_test_xattr),
2291 MAKE_TEST(bpf_test_redact_readdir),
2292 MAKE_TEST(bpf_test_set_backing),
2293 MAKE_TEST(bpf_test_remove_backing),
2294 MAKE_TEST(bpf_test_dir_rename),
2295 MAKE_TEST(bpf_test_file_rename),
2296 MAKE_TEST(bpf_test_alter_errcode_bpf),
2297 MAKE_TEST(bpf_test_alter_errcode_userspace),
2298 MAKE_TEST(mmap_test),
2299 MAKE_TEST(readdir_perms_test),
2300 MAKE_TEST(inotify_test),
2301 MAKE_TEST(bpf_test_statfs),
2302 MAKE_TEST(bpf_test_lseek),
2303 MAKE_TEST(bpf_test_readdirplus_not_overriding_backing),
2304 MAKE_TEST(bpf_test_no_readdirplus_without_nodeid),
2305 MAKE_TEST(bpf_test_revalidate_handle_backing_fd),
2306 MAKE_TEST(bpf_test_lookup_postfilter),
2307 MAKE_TEST(flock_test),
2308 MAKE_TEST(bpf_test_create_and_remove_bpf),
2309 MAKE_TEST(bpf_test_mkdir_and_remove_bpf),
2310 MAKE_TEST(bpf_test_readahead),
2311 MAKE_TEST(bpf_test_follow_mounts),
2312 };
2313 #undef MAKE_TEST
2314
2315 bool run_test[ARRAY_SIZE(cases)];
2316
2317 for (int i = 0; i < ARRAY_SIZE(cases); ++i)
2318 run_test[i] = true;
2319
2320 if (parse_options(argc, argv, run_test, ARRAY_SIZE(cases)))
2321 ksft_exit_fail_msg("Bad options\n");
2322
2323 // Seed randomness pool for testing on QEMU
2324 // NOTE - this abuses the concept of randomness - do *not* ever do this
2325 // on a machine for production use - the device will think it has good
2326 // randomness when it does not.
2327 fd = open("/dev/urandom", O_WRONLY | O_CLOEXEC);
2328 count = 4096;
2329 for (int i = 0; i < 128; ++i)
2330 ioctl(fd, RNDADDTOENTCNT, &count);
2331 close(fd);
2332
2333 ksft_print_header();
2334
2335 if (geteuid() != 0)
2336 ksft_print_msg("Not a root, might fail to mount.\n");
2337
2338 if (tracing_on() != TEST_SUCCESS)
2339 ksft_exit_fail_msg("Can't turn on tracing\n");
2340
2341 src_dir = setup_mount_dir(ft_src);
2342 mount_dir = setup_mount_dir(ft_dst);
2343 if (src_dir == NULL || mount_dir == NULL)
2344 ksft_exit_fail_msg("Can't create a mount dir\n");
2345
2346 ksft_set_plan(ARRAY_SIZE(run_test));
2347
2348 for (i = 0; i < ARRAY_SIZE(run_test); ++i)
2349 if (run_test[i]) {
2350 delete_dir_tree(mount_dir, false);
2351 delete_dir_tree(src_dir, false);
2352 run_one_test(mount_dir, &cases[i]);
2353 } else
2354 ksft_cnt.ksft_xskip++;
2355
2356 umount2(mount_dir, MNT_FORCE);
2357 delete_dir_tree(mount_dir, true);
2358 delete_dir_tree(src_dir, true);
2359 return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
2360 }
2361