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