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_trace",
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_trace",
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 *test_data = "data";
1494 int result = TEST_FAILURE;
1495 int src_fd = -1;
1496 int bpf_fd = -1;
1497 int fuse_dev = -1;
1498 int fd = -1;
1499
1500 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1501 src_fd != -1);
1502 TEST(fd = openat(src_fd, file, O_CREAT | O_RDWR | O_CLOEXEC, 0777),
1503 fd != -1);
1504 TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
1505 TESTSYSCALL(close(fd));
1506 fd = -1;
1507 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
1508 &bpf_fd, NULL, NULL), 0);
1509 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1510
1511 TEST(fd = s_open(s_path(s(mount_dir), s(file)), O_RDONLY | O_CLOEXEC),
1512 fd != -1);
1513 TESTEQUAL(lseek(fd, 3, SEEK_SET), 3);
1514 TESTEQUAL(bpf_test_trace("lseek"), 0);
1515 TESTEQUAL(lseek(fd, 5, SEEK_END), 9);
1516 TESTEQUAL(bpf_test_trace("lseek"), 0);
1517 TESTEQUAL(lseek(fd, 1, SEEK_CUR), 10);
1518 TESTEQUAL(bpf_test_trace("lseek"), 0);
1519 TESTEQUAL(lseek(fd, 1, SEEK_DATA), 1);
1520 TESTEQUAL(bpf_test_trace("lseek"), 0);
1521 result = TEST_SUCCESS;
1522 out:
1523 close(fd);
1524 umount(mount_dir);
1525 close(fuse_dev);
1526 close(bpf_fd);
1527 close(src_fd);
1528 return result;
1529 }
1530
1531 /*
1532 * State:
1533 * Original: dst/folder1/content.txt
1534 * ^
1535 * |
1536 * |
1537 * Backing: src/folder1/content.txt
1538 *
1539 * Step 1: open(folder1) - set backing to src/folder1
1540 * Check 1: cat(content.txt) - check not receiving call on the fuse daemon
1541 * and content is the same
1542 * Step 2: readdirplus(dst)
1543 * Check 2: cat(content.txt) - check not receiving call on the fuse daemon
1544 * and content is the same
1545 */
bpf_test_readdirplus_not_overriding_backing(const char * mount_dir)1546 static int bpf_test_readdirplus_not_overriding_backing(const char *mount_dir)
1547 {
1548 const char *folder1 = "folder1";
1549 const char *content_file = "content.txt";
1550 const char *content = "hello world";
1551
1552 int result = TEST_FAILURE;
1553 int fuse_dev = -1;
1554 int src_fd = -1;
1555 int content_fd = -1;
1556 FUSE_DECLARE_DAEMON;
1557
1558 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1559 TEST(content_fd = s_creat(s_pathn(3, s(ft_src), s(folder1), s(content_file)), 0777),
1560 content_fd != -1);
1561 TESTEQUAL(write(content_fd, content, strlen(content)), strlen(content));
1562 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1563
1564 FUSE_START_DAEMON();
1565 if (action) {
1566 DIR *open_mount_dir = NULL;
1567 struct dirent *mount_dirent;
1568 int dst_folder1_fd = -1;
1569 int dst_content_fd = -1;
1570 char content_buffer[12];
1571
1572 // Step 1: Lookup folder1
1573 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1574 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1575
1576 // Check 1: Read content file (backed)
1577 TESTERR(dst_content_fd =
1578 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1579 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1580
1581 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1582 strlen(content));
1583 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1584
1585 TESTSYSCALL(close(dst_content_fd));
1586 dst_content_fd = -1;
1587 TESTSYSCALL(close(dst_folder1_fd));
1588 dst_folder1_fd = -1;
1589 memset(content_buffer, 0, strlen(content));
1590
1591 // Step 2: readdir folder 1
1592 TEST(open_mount_dir = s_opendir(s(mount_dir)),
1593 open_mount_dir != NULL);
1594 TEST(mount_dirent = readdir(open_mount_dir), mount_dirent != NULL);
1595 TESTSYSCALL(closedir(open_mount_dir));
1596 open_mount_dir = NULL;
1597
1598 // Check 2: Read content file again (must be backed)
1599 TESTERR(dst_content_fd =
1600 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1601 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1602
1603 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1604 strlen(content));
1605 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1606
1607 TESTSYSCALL(close(dst_content_fd));
1608 dst_content_fd = -1;
1609 } else {
1610 size_t read_size = 0;
1611 struct fuse_in_header *in_header = (struct fuse_in_header *)bytes_in;
1612 struct fuse_read_out *read_out = NULL;
1613 struct fuse_attr attr = {};
1614 int backing_fd = -1;
1615 DECL_FUSE_IN(open);
1616 DECL_FUSE_IN(getattr);
1617
1618 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1619
1620 // Step 1: Lookup folder 1 with backing
1621 TESTFUSELOOKUP(folder1, 0);
1622 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1623 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1624 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1625 backing_fd != -1);
1626 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1627 .nodeid = attr.ino,
1628 .generation = 0,
1629 .entry_valid = UINT64_MAX,
1630 .attr_valid = UINT64_MAX,
1631 .entry_valid_nsec = UINT32_MAX,
1632 .attr_valid_nsec = UINT32_MAX,
1633 .attr = attr,
1634 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1635 .backing_action = FUSE_ACTION_REPLACE,
1636 .backing_fd = backing_fd,
1637 }));
1638 TESTSYSCALL(close(backing_fd));
1639
1640 // Step 2: Open root dir
1641 TESTFUSEIN(FUSE_OPENDIR, open_in);
1642 TESTFUSEOUT1(fuse_open_out, ((struct fuse_open_out) {
1643 .fh = 100,
1644 .open_flags = open_in->flags
1645 }));
1646
1647 // Step 2: Handle getattr
1648 TESTFUSEIN(FUSE_GETATTR, getattr_in);
1649 TESTSYSCALL(s_fuse_attr(s(ft_src), &attr));
1650 TESTFUSEOUT1(fuse_attr_out, ((struct fuse_attr_out) {
1651 .attr_valid = UINT64_MAX,
1652 .attr_valid_nsec = UINT32_MAX,
1653 .attr = attr
1654 }));
1655
1656 // Step 2: Handle readdirplus
1657 read_size = read(fuse_dev, bytes_in, sizeof(bytes_in));
1658 TESTEQUAL(in_header->opcode, FUSE_READDIRPLUS);
1659
1660 struct fuse_direntplus *dirent_plus =
1661 (struct fuse_direntplus *) (bytes_in + read_size);
1662 struct fuse_dirent dirent;
1663 struct fuse_entry_out entry_out;
1664
1665 read_out = (struct fuse_read_out *) (bytes_in +
1666 sizeof(*in_header) +
1667 sizeof(struct fuse_read_in));
1668
1669 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1670
1671 dirent = (struct fuse_dirent) {
1672 .ino = attr.ino,
1673 .off = 1,
1674 .namelen = strlen(folder1),
1675 .type = DT_REG
1676 };
1677 entry_out = (struct fuse_entry_out) {
1678 .nodeid = attr.ino,
1679 .generation = 0,
1680 .entry_valid = UINT64_MAX,
1681 .attr_valid = UINT64_MAX,
1682 .entry_valid_nsec = UINT32_MAX,
1683 .attr_valid_nsec = UINT32_MAX,
1684 .attr = attr
1685 };
1686 *dirent_plus = (struct fuse_direntplus) {
1687 .dirent = dirent,
1688 .entry_out = entry_out
1689 };
1690
1691 strcpy((char *)(bytes_in + read_size + sizeof(*dirent_plus)), folder1);
1692 read_size += FUSE_DIRENT_ALIGN(sizeof(*dirent_plus) + strlen(folder1) +
1693 1);
1694 TESTFUSEDIROUTREAD(read_out,
1695 bytes_in +
1696 sizeof(struct fuse_in_header) +
1697 sizeof(struct fuse_read_in) +
1698 sizeof(struct fuse_read_out),
1699 read_size - sizeof(struct fuse_in_header) -
1700 sizeof(struct fuse_read_in) -
1701 sizeof(struct fuse_read_out));
1702 exit(TEST_SUCCESS);
1703 }
1704 FUSE_END_DAEMON();
1705 close(fuse_dev);
1706 close(content_fd);
1707 close(src_fd);
1708 umount(mount_dir);
1709 return result;
1710 }
1711
bpf_test_no_readdirplus_without_nodeid(const char * mount_dir)1712 static int bpf_test_no_readdirplus_without_nodeid(const char *mount_dir)
1713 {
1714 const char *folder1 = "folder1";
1715 const char *folder2 = "folder2";
1716 int result = TEST_FAILURE;
1717 int fuse_dev = -1;
1718 int src_fd = -1;
1719 int content_fd = -1;
1720 int bpf_fd = -1;
1721 FUSE_DECLARE_DAEMON;
1722
1723 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_readdirplus",
1724 &bpf_fd, NULL, NULL), 0);
1725 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1726 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder2)), 0777));
1727 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1728 FUSE_START_DAEMON();
1729 if (action) {
1730 DIR *open_dir = NULL;
1731 struct dirent *dirent;
1732
1733 // Folder 1: Readdir with no nodeid
1734 TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder1))),
1735 open_dir != NULL);
1736 TEST(dirent = readdir(open_dir), dirent == NULL);
1737 TESTCOND(errno == EINVAL);
1738 TESTSYSCALL(closedir(open_dir));
1739 open_dir = NULL;
1740
1741 // Folder 2: Readdir with a nodeid
1742 TEST(open_dir = s_opendir(s_path(s(ft_dst), s(folder2))),
1743 open_dir != NULL);
1744 TEST(dirent = readdir(open_dir), dirent == NULL);
1745 TESTCOND(errno == EINVAL);
1746 TESTSYSCALL(closedir(open_dir));
1747 open_dir = NULL;
1748 } else {
1749 size_t read_size;
1750 struct fuse_in_header *in_header = (struct fuse_in_header *)bytes_in;
1751 struct fuse_attr attr = {};
1752 int backing_fd = -1;
1753
1754 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1755
1756 // folder 1: Set 0 as nodeid, Expect READDIR
1757 TESTFUSELOOKUP(folder1, 0);
1758 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1759 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1760 backing_fd != -1);
1761 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1762 .nodeid = 0,
1763 .generation = 0,
1764 .entry_valid = UINT64_MAX,
1765 .attr_valid = UINT64_MAX,
1766 .entry_valid_nsec = UINT32_MAX,
1767 .attr_valid_nsec = UINT32_MAX,
1768 .attr = attr,
1769 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1770 .backing_action = FUSE_ACTION_REPLACE,
1771 .backing_fd = backing_fd,
1772 .bpf_action = FUSE_ACTION_REPLACE,
1773 .bpf_fd = bpf_fd,
1774 }));
1775 TESTSYSCALL(close(backing_fd));
1776 TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
1777 TESTEQUAL(in_header->opcode, FUSE_READDIR);
1778 TESTFUSEOUTERROR(-EINVAL);
1779
1780 // folder 2: Set 10 as nodeid, Expect READDIRPLUS
1781 TESTFUSELOOKUP(folder2, 0);
1782 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder2)),
1783 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1784 backing_fd != -1);
1785 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1786 .nodeid = 10,
1787 .generation = 0,
1788 .entry_valid = UINT64_MAX,
1789 .attr_valid = UINT64_MAX,
1790 .entry_valid_nsec = UINT32_MAX,
1791 .attr_valid_nsec = UINT32_MAX,
1792 .attr = attr,
1793 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1794 .backing_action = FUSE_ACTION_REPLACE,
1795 .backing_fd = backing_fd,
1796 .bpf_action = FUSE_ACTION_REPLACE,
1797 .bpf_fd = bpf_fd,
1798 }));
1799 TESTSYSCALL(close(backing_fd));
1800 TEST(read_size = read(fuse_dev, bytes_in, sizeof(bytes_in)), read_size > 0);
1801 TESTEQUAL(in_header->opcode, FUSE_READDIRPLUS);
1802 TESTFUSEOUTERROR(-EINVAL);
1803 exit(TEST_SUCCESS);
1804 }
1805 FUSE_END_DAEMON();
1806 close(fuse_dev);
1807 close(content_fd);
1808 close(src_fd);
1809 close(bpf_fd);
1810 umount(mount_dir);
1811 return result;
1812 }
1813
1814 /*
1815 * State:
1816 * Original: dst/folder1/content.txt
1817 * ^
1818 * |
1819 * |
1820 * Backing: src/folder1/content.txt
1821 *
1822 * Step 1: open(folder1) - lookup folder1 with entry_timeout set to 0
1823 * Step 2: open(folder1) - lookup folder1 again to trigger revalidate wich will
1824 * set backing fd
1825 *
1826 * Check 1: cat(content.txt) - check not receiving call on the fuse daemon
1827 * and content is the same
1828 */
bpf_test_revalidate_handle_backing_fd(const char * mount_dir)1829 static int bpf_test_revalidate_handle_backing_fd(const char *mount_dir)
1830 {
1831 const char *folder1 = "folder1";
1832 const char *content_file = "content.txt";
1833 const char *content = "hello world";
1834 int result = TEST_FAILURE;
1835 int fuse_dev = -1;
1836 int src_fd = -1;
1837 int content_fd = -1;
1838 FUSE_DECLARE_DAEMON;
1839
1840 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(folder1)), 0777));
1841 TEST(content_fd = s_creat(s_pathn(3, s(ft_src), s(folder1), s(content_file)), 0777),
1842 content_fd != -1);
1843 TESTEQUAL(write(content_fd, content, strlen(content)), strlen(content));
1844 TESTSYSCALL(close(content_fd));
1845 content_fd = -1;
1846 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, -1, &fuse_dev), 0);
1847 FUSE_START_DAEMON();
1848 if (action) {
1849 int dst_folder1_fd = -1;
1850 int dst_content_fd = -1;
1851 char content_buffer[9] = {0};
1852 // Step 1: Lookup folder1
1853 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1854 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1855 TESTSYSCALL(close(dst_folder1_fd));
1856 dst_folder1_fd = -1;
1857 // Step 2: Lookup folder1 again
1858 TESTERR(dst_folder1_fd = s_open(s_path(s(mount_dir), s(folder1)),
1859 O_RDONLY | O_CLOEXEC), dst_folder1_fd != -1);
1860 TESTSYSCALL(close(dst_folder1_fd));
1861 dst_folder1_fd = -1;
1862 // Check 1: Read content file (must be backed)
1863 TESTERR(dst_content_fd =
1864 s_open(s_pathn(3, s(mount_dir), s(folder1), s(content_file)),
1865 O_RDONLY | O_CLOEXEC), dst_content_fd != -1);
1866 TESTEQUAL(read(dst_content_fd, content_buffer, strlen(content)),
1867 strlen(content));
1868 TESTEQUAL(strncmp(content, content_buffer, strlen(content)), 0);
1869 TESTSYSCALL(close(dst_content_fd));
1870 dst_content_fd = -1;
1871 } else {
1872 struct fuse_attr attr = {};
1873 int backing_fd = -1;
1874
1875 TESTFUSEINITFLAGS(FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO);
1876 // Step 1: Lookup folder1 set entry_timeout to 0 to trigger
1877 // revalidate later
1878 TESTFUSELOOKUP(folder1, 0);
1879 TESTSYSCALL(s_fuse_attr(s_path(s(ft_src), s(folder1)), &attr));
1880 TEST(backing_fd = s_open(s_path(s(ft_src), s(folder1)),
1881 O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1882 backing_fd != -1);
1883 TESTFUSEOUT2(fuse_entry_out, ((struct fuse_entry_out) {
1884 .nodeid = attr.ino,
1885 .generation = 0,
1886 .entry_valid = 0,
1887 .attr_valid = UINT64_MAX,
1888 .entry_valid_nsec = 0,
1889 .attr_valid_nsec = UINT32_MAX,
1890 .attr = attr,
1891 }), fuse_entry_bpf_out, ((struct fuse_entry_bpf_out) {
1892 .backing_action = FUSE_ACTION_REPLACE,
1893 .backing_fd = backing_fd,
1894 }));
1895 TESTSYSCALL(close(backing_fd));
1896 // Step 1: Lookup folder1 as a reaction to revalidate call
1897 // This attempts to change the backing node, which is not allowed on revalidate
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 = UINT64_MAX,
1907 .attr_valid = UINT64_MAX,
1908 .entry_valid_nsec = UINT32_MAX,
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
1917 // Lookup folder1 as a reaction to failed 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 exit(TEST_SUCCESS);
1937 }
1938 FUSE_END_DAEMON();
1939 close(fuse_dev);
1940 close(content_fd);
1941 close(src_fd);
1942 umount(mount_dir);
1943 return result;
1944 }
1945
bpf_test_lookup_postfilter(const char * mount_dir)1946 static int bpf_test_lookup_postfilter(const char *mount_dir)
1947 {
1948 const char *file1_name = "file1";
1949 const char *file2_name = "file2";
1950 const char *file3_name = "file3";
1951 int result = TEST_FAILURE;
1952 int bpf_fd = -1;
1953 int src_fd = -1;
1954 int fuse_dev = -1;
1955 int file_fd = -1;
1956 FUSE_DECLARE_DAEMON;
1957
1958 TEST(file_fd = s_creat(s_path(s(ft_src), s(file1_name)), 0777),
1959 file_fd != -1);
1960 TESTSYSCALL(close(file_fd));
1961 TEST(file_fd = s_creat(s_path(s(ft_src), s(file2_name)), 0777),
1962 file_fd != -1);
1963 TESTSYSCALL(close(file_fd));
1964 file_fd = -1;
1965 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_lookup_postfilter",
1966 &bpf_fd, NULL, NULL), 0);
1967 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
1968 src_fd != -1);
1969 TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
1970 FUSE_START_DAEMON();
1971 if (action) {
1972 int fd = -1;
1973
1974 TESTEQUAL(s_open(s_path(s(mount_dir), s(file1_name)), O_RDONLY),
1975 -1);
1976 TESTEQUAL(errno, ENOENT);
1977 TEST(fd = s_open(s_path(s(mount_dir), s(file2_name)), O_RDONLY),
1978 fd != -1);
1979 TESTSYSCALL(close(fd));
1980 TESTEQUAL(s_open(s_path(s(mount_dir), s(file3_name)), O_RDONLY),
1981 -1);
1982 } else {
1983 struct fuse_in_postfilter_header *in_header =
1984 (struct fuse_in_postfilter_header *)bytes_in;
1985 struct fuse_entry_out *feo;
1986 struct fuse_entry_bpf_out *febo;
1987
1988 TESTFUSELOOKUP(file1_name, FUSE_POSTFILTER);
1989 TESTFUSEOUTERROR(-ENOENT);
1990
1991 TESTFUSELOOKUP(file2_name, FUSE_POSTFILTER);
1992 feo = (struct fuse_entry_out *) (bytes_in +
1993 sizeof(struct fuse_in_header) + strlen(file2_name) + 1);
1994 febo = (struct fuse_entry_bpf_out *) ((char *)feo +
1995 sizeof(*feo));
1996 TESTFUSEOUT2(fuse_entry_out, *feo, fuse_entry_bpf_out, *febo);
1997
1998 TESTFUSELOOKUP(file3_name, FUSE_POSTFILTER);
1999 TESTEQUAL(in_header->error_in, -ENOENT);
2000 TESTFUSEOUTERROR(-ENOENT);
2001 exit(TEST_SUCCESS);
2002 }
2003 FUSE_END_DAEMON();
2004 close(file_fd);
2005 close(fuse_dev);
2006 umount(mount_dir);
2007 close(src_fd);
2008 close(bpf_fd);
2009 return result;
2010 }
2011
2012 /**
2013 * Test that a file made via create_and_open correctly gets the bpf assigned
2014 * from the negative lookup
2015 * bpf blocks file open, but also removes itself from children
2016 * This test will fail if the 'remove' is unsuccessful
2017 */
bpf_test_create_and_remove_bpf(const char * mount_dir)2018 static int bpf_test_create_and_remove_bpf(const char *mount_dir)
2019 {
2020 const char *file = "file";
2021
2022 int result = TEST_FAILURE;
2023 int src_fd = -1;
2024 int bpf_fd = -1;
2025 int fuse_dev = -1;
2026 int fd = -1;
2027 int fd2 = -1;
2028
2029 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2030 src_fd != -1);
2031 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_create_remove", &bpf_fd,
2032 NULL, NULL), 0);
2033 TESTEQUAL(mount_fuse_no_init(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
2034 TEST(fd = s_creat(s_path(s(mount_dir), s(file)), 0777),
2035 fd != -1);
2036 TEST(fd2 = s_open(s_path(s(mount_dir), s(file)), O_RDONLY),
2037 fd2 != -1);
2038
2039 result = TEST_SUCCESS;
2040 out:
2041 close(fd2);
2042 close(fd);
2043 close(fuse_dev);
2044 close(bpf_fd);
2045 close(src_fd);
2046 umount(mount_dir);
2047 return result;
2048 }
2049
bpf_test_mkdir_and_remove_bpf(const char * mount_dir)2050 static int bpf_test_mkdir_and_remove_bpf(const char *mount_dir)
2051 {
2052 const char *dir = "dir";
2053
2054 int result = TEST_FAILURE;
2055 int src_fd = -1;
2056 int bpf_fd = -1;
2057 int fuse_dev = -1;
2058 int fd = -1;
2059 int fd2 = -1;
2060
2061 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2062 src_fd != -1);
2063 TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_mkdir_remove", &bpf_fd,
2064 NULL, NULL), 0);
2065 TESTEQUAL(mount_fuse_no_init(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
2066 TEST(fd = s_mkdir(s_path(s(mount_dir), s(dir)), 0777),
2067 fd != -1);
2068 TEST(fd2 = s_open(s_path(s(mount_dir), s(dir)), O_RDONLY),
2069 fd2 != -1);
2070
2071 result = TEST_SUCCESS;
2072 out:
2073 close(fd2);
2074 close(fd);
2075 close(fuse_dev);
2076 close(bpf_fd);
2077 close(src_fd);
2078 umount(mount_dir);
2079 return result;
2080 }
2081
bpf_test_readahead(const char * mount_dir)2082 static int bpf_test_readahead(const char *mount_dir)
2083 {
2084 const char *file_name = "file";
2085
2086 int result = TEST_FAILURE;
2087 int file_fd = -1;
2088 int src_fd = -1;
2089 int fuse_dev = -1;
2090
2091 TEST(file_fd = s_creat(s_path(s(ft_src), s(file_name)), 0777),
2092 file_fd != -1);
2093 TESTSYSCALL(fallocate(file_fd, 0, 0, 4096));
2094 TESTSYSCALL(close(file_fd));
2095 file_fd = -1;
2096
2097 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2098 src_fd != -1);
2099 TEST(fuse_dev = open("/dev/fuse", O_RDWR | O_CLOEXEC), fuse_dev != -1);
2100 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
2101
2102 TEST(file_fd = s_open(s_path(s(mount_dir), s(file_name)), O_RDONLY),
2103 file_fd != -1);
2104 TESTSYSCALL(posix_fadvise(file_fd, 0, 4096, POSIX_FADV_WILLNEED));
2105 usleep(1000);
2106 TESTSYSCALL(close(file_fd));
2107 file_fd = -1;
2108 result = TEST_SUCCESS;
2109 out:
2110 umount(mount_dir);
2111 close(fuse_dev);
2112 close(src_fd);
2113 close(file_fd);
2114 return result;
2115 }
2116
splice_test(const char * mount_dir)2117 static int splice_test(const char *mount_dir)
2118 {
2119 const char *in_name = "in";
2120 const char *out_name = "out";
2121 const int splice_size = 4096;
2122
2123 int result = TEST_FAILURE;
2124 int file_fd = -1;
2125 int src_fd = -1;
2126 int fuse_dev = -1;
2127 int in_fd = -1;
2128 int out_fd = -1;
2129 int pipefd[2] = {-1, -1};
2130
2131 TEST(file_fd = s_creat(s_path(s(ft_src), s(in_name)), 0777),
2132 file_fd != -1);
2133 TESTSYSCALL(fallocate(file_fd, 0, 0, splice_size));
2134 TESTSYSCALL(close(file_fd));
2135 file_fd = -1;
2136
2137 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2138 src_fd != -1);
2139 TEST(fuse_dev = open("/dev/fuse", O_RDWR | O_CLOEXEC), fuse_dev != -1);
2140 TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
2141
2142 TESTSYSCALL(pipe(pipefd));
2143 TEST(in_fd = s_open(s_path(s(mount_dir), s(in_name)), O_RDONLY),
2144 in_fd != -1);
2145 TEST(out_fd = s_creat(s_path(s(mount_dir), s(out_name)), 0777),
2146 out_fd != -1);
2147 TESTEQUAL(splice(in_fd, NULL, pipefd[1], NULL, splice_size, 0),
2148 splice_size);
2149 TESTEQUAL(splice(pipefd[0], NULL, out_fd, NULL, splice_size, 0),
2150 splice_size);
2151 TESTSYSCALL(close(in_fd));
2152 in_fd = -1;
2153 TESTSYSCALL(close(out_fd));
2154 out_fd = -1;
2155 TESTSYSCALL(close(pipefd[0]));
2156 pipefd[0] = -1;
2157 TESTSYSCALL(close(pipefd[1]));
2158 pipefd[1] = -1;
2159 result = TEST_SUCCESS;
2160 out:
2161 umount(mount_dir);
2162 close(fuse_dev);
2163 close(src_fd);
2164 close(in_fd);
2165 close(out_fd);
2166 close(pipefd[0]);
2167 close(pipefd[1]);
2168 return result;
2169 }
2170
2171 /**
2172 * Test that fuse passthrough correctly traverses a mount point on the lower fs
2173 */
bpf_test_follow_mounts(const char * mount_dir)2174 static int bpf_test_follow_mounts(const char *mount_dir)
2175 {
2176 const char *bind_src = "bind_src";
2177 const char *bind_dst = "bind_dst";
2178 const char *file = "file";
2179 int fd = -1;
2180 int src_fd = -1;
2181 int result = TEST_FAILURE;
2182
2183 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_src)), 0777));
2184 TESTSYSCALL(s_mkdir(s_path(s(ft_src), s(bind_dst)), 0777));
2185 TEST(fd = s_creat(s_pathn(3, s(ft_src), s(bind_src), s(file)), 0777),
2186 fd != -1);
2187 TESTSYSCALL(close(fd));
2188 fd = -1;
2189 TESTSYSCALL(s_mount(s_path(s(ft_src), s(bind_src)),
2190 s_path(s(ft_src), s(bind_dst)),
2191 s(NULL), MS_BIND, s(NULL)));
2192 TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
2193 src_fd != -1);
2194 TESTEQUAL(mount_fuse_no_init(mount_dir, -1, src_fd, NULL), 0);
2195 TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_src), s(file)),
2196 O_RDONLY),
2197 fd != -1);
2198 TESTSYSCALL(close(fd));
2199 fd = -1;
2200 TEST(fd = s_open(s_pathn(3, s(mount_dir), s(bind_dst), s(file)),
2201 O_RDONLY),
2202 fd != -1);
2203 TESTSYSCALL(close(fd));
2204 fd = -1;
2205
2206 result = TEST_SUCCESS;
2207 out:
2208 umount(mount_dir);
2209 close(src_fd);
2210 s_umount(s_path(s(ft_src), s(bind_dst)));
2211 close(fd);
2212 return result;
2213 }
2214
parse_range(const char * ranges,bool * run_test,size_t tests)2215 static void parse_range(const char *ranges, bool *run_test, size_t tests)
2216 {
2217 size_t i;
2218 char *range;
2219
2220 for (i = 0; i < tests; ++i)
2221 run_test[i] = false;
2222
2223 range = strtok(optarg, ",");
2224 while (range) {
2225 char *dash = strchr(range, '-');
2226
2227 if (dash) {
2228 size_t start = 1, end = tests;
2229 char *end_ptr;
2230
2231 if (dash > range) {
2232 start = strtol(range, &end_ptr, 10);
2233 if (*end_ptr != '-' || start <= 0 || start > tests)
2234 ksft_exit_fail_msg("Bad range\n");
2235 }
2236
2237 if (dash[1]) {
2238 end = strtol(dash + 1, &end_ptr, 10);
2239 if (*end_ptr || end <= start || end > tests)
2240 ksft_exit_fail_msg("Bad range\n");
2241 }
2242
2243 for (i = start; i <= end; ++i)
2244 run_test[i - 1] = true;
2245 } else {
2246 char *end;
2247 long value = strtol(range, &end, 10);
2248
2249 if (*end || value <= 0 || value > tests)
2250 ksft_exit_fail_msg("Bad range\n");
2251 run_test[value - 1] = true;
2252 }
2253 range = strtok(NULL, ",");
2254 }
2255 }
2256
parse_options(int argc,char * const * argv,bool * run_test,size_t tests)2257 static int parse_options(int argc, char *const *argv, bool *run_test,
2258 size_t tests)
2259 {
2260 signed char c;
2261
2262 while ((c = getopt(argc, argv, "f:t:v")) != -1)
2263 switch (c) {
2264 case 'f':
2265 test_options.file = strtol(optarg, NULL, 10);
2266 break;
2267
2268 case 't':
2269 parse_range(optarg, run_test, tests);
2270 break;
2271
2272 case 'v':
2273 test_options.verbose = true;
2274 break;
2275
2276 default:
2277 return -EINVAL;
2278 }
2279
2280 return 0;
2281 }
2282
2283 struct test_case {
2284 int (*pfunc)(const char *dir);
2285 const char *name;
2286 };
2287
run_one_test(const char * mount_dir,const struct test_case * test_case)2288 static void run_one_test(const char *mount_dir,
2289 const struct test_case *test_case)
2290 {
2291 ksft_print_msg("Running %s\n", test_case->name);
2292 if (test_case->pfunc(mount_dir) == TEST_SUCCESS)
2293 ksft_test_result_pass("%s\n", test_case->name);
2294 else
2295 ksft_test_result_fail("%s\n", test_case->name);
2296 }
2297
main(int argc,char * argv[])2298 int main(int argc, char *argv[])
2299 {
2300 char *mount_dir = NULL;
2301 char *src_dir = NULL;
2302 int i;
2303 int fd, count;
2304
2305 #define MAKE_TEST(test) \
2306 { \
2307 test, #test \
2308 }
2309 const struct test_case cases[] = {
2310 MAKE_TEST(basic_test),
2311 MAKE_TEST(bpf_test_real),
2312 MAKE_TEST(bpf_test_partial),
2313 MAKE_TEST(bpf_test_attrs),
2314 MAKE_TEST(bpf_test_readdir),
2315 MAKE_TEST(bpf_test_creat),
2316 MAKE_TEST(bpf_test_hidden_entries),
2317 MAKE_TEST(bpf_test_dir),
2318 MAKE_TEST(bpf_test_file_early_close),
2319 MAKE_TEST(bpf_test_file_late_close),
2320 MAKE_TEST(bpf_test_mknod),
2321 MAKE_TEST(bpf_test_largedir),
2322 MAKE_TEST(bpf_test_link),
2323 MAKE_TEST(bpf_test_symlink),
2324 MAKE_TEST(bpf_test_xattr),
2325 MAKE_TEST(bpf_test_redact_readdir),
2326 MAKE_TEST(bpf_test_set_backing),
2327 MAKE_TEST(bpf_test_remove_backing),
2328 MAKE_TEST(bpf_test_dir_rename),
2329 MAKE_TEST(bpf_test_file_rename),
2330 MAKE_TEST(bpf_test_alter_errcode_bpf),
2331 MAKE_TEST(bpf_test_alter_errcode_userspace),
2332 MAKE_TEST(mmap_test),
2333 MAKE_TEST(readdir_perms_test),
2334 MAKE_TEST(inotify_test),
2335 MAKE_TEST(bpf_test_statfs),
2336 MAKE_TEST(bpf_test_lseek),
2337 MAKE_TEST(bpf_test_readdirplus_not_overriding_backing),
2338 MAKE_TEST(bpf_test_no_readdirplus_without_nodeid),
2339 MAKE_TEST(bpf_test_revalidate_handle_backing_fd),
2340 MAKE_TEST(bpf_test_lookup_postfilter),
2341 MAKE_TEST(flock_test),
2342 MAKE_TEST(bpf_test_create_and_remove_bpf),
2343 MAKE_TEST(bpf_test_mkdir_and_remove_bpf),
2344 MAKE_TEST(bpf_test_readahead),
2345 MAKE_TEST(splice_test),
2346 MAKE_TEST(bpf_test_follow_mounts),
2347 };
2348 #undef MAKE_TEST
2349
2350 bool run_test[ARRAY_SIZE(cases)];
2351
2352 for (int i = 0; i < ARRAY_SIZE(cases); ++i)
2353 run_test[i] = true;
2354
2355 if (parse_options(argc, argv, run_test, ARRAY_SIZE(cases)))
2356 ksft_exit_fail_msg("Bad options\n");
2357
2358 // Seed randomness pool for testing on QEMU
2359 // NOTE - this abuses the concept of randomness - do *not* ever do this
2360 // on a machine for production use - the device will think it has good
2361 // randomness when it does not.
2362 fd = open("/dev/urandom", O_WRONLY | O_CLOEXEC);
2363 count = 4096;
2364 for (int i = 0; i < 128; ++i)
2365 ioctl(fd, RNDADDTOENTCNT, &count);
2366 close(fd);
2367
2368 ksft_print_header();
2369
2370 if (geteuid() != 0)
2371 ksft_print_msg("Not a root, might fail to mount.\n");
2372
2373 if (tracing_on() != TEST_SUCCESS)
2374 ksft_exit_fail_msg("Can't turn on tracing\n");
2375
2376 src_dir = setup_mount_dir(ft_src);
2377 mount_dir = setup_mount_dir(ft_dst);
2378 if (src_dir == NULL || mount_dir == NULL)
2379 ksft_exit_fail_msg("Can't create a mount dir\n");
2380
2381 ksft_set_plan(ARRAY_SIZE(run_test));
2382
2383 for (i = 0; i < ARRAY_SIZE(run_test); ++i)
2384 if (run_test[i]) {
2385 delete_dir_tree(mount_dir, false);
2386 delete_dir_tree(src_dir, false);
2387 run_one_test(mount_dir, &cases[i]);
2388 } else
2389 ksft_cnt.ksft_xskip++;
2390
2391 umount2(mount_dir, MNT_FORCE);
2392 delete_dir_tree(mount_dir, true);
2393 delete_dir_tree(src_dir, true);
2394 return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
2395 }
2396