• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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