• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2021 Google LLC
4  */
5 
6 #include "test_fuse.h"
7 
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include <sys/mount.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 
18 #include <linux/unistd.h>
19 
20 #include <include/uapi/linux/fuse.h>
21 #include <include/uapi/linux/bpf.h>
22 
23 bool user_messages;
24 bool kernel_messages;
25 
display_trace(void)26 static int display_trace(void)
27 {
28 	int pid = -1;
29 	int tp = -1;
30 	char c;
31 	ssize_t bytes_read;
32 	static char line[256] = {0};
33 
34 	if (!kernel_messages)
35 		return TEST_SUCCESS;
36 
37 	TEST(pid = fork(), pid != -1);
38 	if (pid != 0)
39 		return pid;
40 
41 	TESTEQUAL(tracing_on(), 0);
42 	TEST(tp = s_open(s_path(tracing_folder(), s("trace_pipe")),
43 			 O_RDONLY | O_CLOEXEC), tp != -1);
44 	for (;;) {
45 		TEST(bytes_read = read(tp, &c, sizeof(c)),
46 		     bytes_read == 1);
47 		if (c == '\n') {
48 			printf("%s\n", line);
49 			line[0] = 0;
50 		} else
51 			sprintf(line + strlen(line), "%c", c);
52 	}
53 out:
54 	if (pid == 0) {
55 		close(tp);
56 		exit(TEST_FAILURE);
57 	}
58 	return pid;
59 }
60 
fuse_opcode_to_string(int opcode)61 static const char *fuse_opcode_to_string(int opcode)
62 {
63 	switch (opcode & FUSE_OPCODE_FILTER) {
64 	case FUSE_LOOKUP:
65 		return "FUSE_LOOKUP";
66 	case FUSE_FORGET:
67 		return "FUSE_FORGET";
68 	case FUSE_GETATTR:
69 		return "FUSE_GETATTR";
70 	case FUSE_SETATTR:
71 		return "FUSE_SETATTR";
72 	case FUSE_READLINK:
73 		return "FUSE_READLINK";
74 	case FUSE_SYMLINK:
75 		return "FUSE_SYMLINK";
76 	case FUSE_MKNOD:
77 		return "FUSE_MKNOD";
78 	case FUSE_MKDIR:
79 		return "FUSE_MKDIR";
80 	case FUSE_UNLINK:
81 		return "FUSE_UNLINK";
82 	case FUSE_RMDIR:
83 		return "FUSE_RMDIR";
84 	case FUSE_RENAME:
85 		return "FUSE_RENAME";
86 	case FUSE_LINK:
87 		return "FUSE_LINK";
88 	case FUSE_OPEN:
89 		return "FUSE_OPEN";
90 	case FUSE_READ:
91 		return "FUSE_READ";
92 	case FUSE_WRITE:
93 		return "FUSE_WRITE";
94 	case FUSE_STATFS:
95 		return "FUSE_STATFS";
96 	case FUSE_RELEASE:
97 		return "FUSE_RELEASE";
98 	case FUSE_FSYNC:
99 		return "FUSE_FSYNC";
100 	case FUSE_SETXATTR:
101 		return "FUSE_SETXATTR";
102 	case FUSE_GETXATTR:
103 		return "FUSE_GETXATTR";
104 	case FUSE_LISTXATTR:
105 		return "FUSE_LISTXATTR";
106 	case FUSE_REMOVEXATTR:
107 		return "FUSE_REMOVEXATTR";
108 	case FUSE_FLUSH:
109 		return "FUSE_FLUSH";
110 	case FUSE_INIT:
111 		return "FUSE_INIT";
112 	case FUSE_OPENDIR:
113 		return "FUSE_OPENDIR";
114 	case FUSE_READDIR:
115 		return "FUSE_READDIR";
116 	case FUSE_RELEASEDIR:
117 		return "FUSE_RELEASEDIR";
118 	case FUSE_FSYNCDIR:
119 		return "FUSE_FSYNCDIR";
120 	case FUSE_GETLK:
121 		return "FUSE_GETLK";
122 	case FUSE_SETLK:
123 		return "FUSE_SETLK";
124 	case FUSE_SETLKW:
125 		return "FUSE_SETLKW";
126 	case FUSE_ACCESS:
127 		return "FUSE_ACCESS";
128 	case FUSE_CREATE:
129 		return "FUSE_CREATE";
130 	case FUSE_INTERRUPT:
131 		return "FUSE_INTERRUPT";
132 	case FUSE_BMAP:
133 		return "FUSE_BMAP";
134 	case FUSE_DESTROY:
135 		return "FUSE_DESTROY";
136 	case FUSE_IOCTL:
137 		return "FUSE_IOCTL";
138 	case FUSE_POLL:
139 		return "FUSE_POLL";
140 	case FUSE_NOTIFY_REPLY:
141 		return "FUSE_NOTIFY_REPLY";
142 	case FUSE_BATCH_FORGET:
143 		return "FUSE_BATCH_FORGET";
144 	case FUSE_FALLOCATE:
145 		return "FUSE_FALLOCATE";
146 	case FUSE_READDIRPLUS:
147 		return "FUSE_READDIRPLUS";
148 	case FUSE_RENAME2:
149 		return "FUSE_RENAME2";
150 	case FUSE_LSEEK:
151 		return "FUSE_LSEEK";
152 	case FUSE_COPY_FILE_RANGE:
153 		return "FUSE_COPY_FILE_RANGE";
154 	case FUSE_SETUPMAPPING:
155 		return "FUSE_SETUPMAPPING";
156 	case FUSE_REMOVEMAPPING:
157 		return "FUSE_REMOVEMAPPING";
158 	//case FUSE_SYNCFS:
159 	//	return "FUSE_SYNCFS";
160 	case CUSE_INIT:
161 		return "CUSE_INIT";
162 	case CUSE_INIT_BSWAP_RESERVED:
163 		return "CUSE_INIT_BSWAP_RESERVED";
164 	case FUSE_INIT_BSWAP_RESERVED:
165 		return "FUSE_INIT_BSWAP_RESERVED";
166 	}
167 	return "?";
168 }
169 
parse_options(int argc,char * const * argv)170 static int parse_options(int argc, char *const *argv)
171 {
172 	signed char c;
173 
174 	while ((c = getopt(argc, argv, "kuv")) != -1)
175 		switch (c) {
176 		case 'v':
177 			test_options.verbose = true;
178 			break;
179 
180 		case 'u':
181 			user_messages = true;
182 			break;
183 
184 		case 'k':
185 			kernel_messages = true;
186 			break;
187 
188 		default:
189 			return -EINVAL;
190 		}
191 
192 	return 0;
193 }
194 
main(int argc,char * argv[])195 int main(int argc, char *argv[])
196 {
197 	int result = TEST_FAILURE;
198 	int trace_pid = -1;
199 	char *mount_dir = NULL;
200 	char *src_dir = NULL;
201 	int bpf_fd = -1;
202 	int src_fd = -1;
203 	int fuse_dev = -1;
204 	struct map_relocation *map_relocations = NULL;
205 	size_t map_count = 0;
206 	int i;
207 
208 	if (geteuid() != 0)
209 		ksft_print_msg("Not a root, might fail to mount.\n");
210 	TESTEQUAL(parse_options(argc, argv), 0);
211 
212 	TEST(trace_pid = display_trace(), trace_pid != -1);
213 
214 	delete_dir_tree("fd-src", true);
215 	TEST(src_dir = setup_mount_dir("fd-src"), src_dir);
216 	delete_dir_tree("fd-dst", true);
217 	TEST(mount_dir = setup_mount_dir("fd-dst"), mount_dir);
218 
219 	TESTEQUAL(install_elf_bpf("fd_bpf.bpf", "test_daemon", &bpf_fd,
220 				  &map_relocations, &map_count), 0);
221 
222 	TEST(src_fd = open("fd-src", O_DIRECTORY | O_RDONLY | O_CLOEXEC),
223 	     src_fd != -1);
224 	TESTSYSCALL(mkdirat(src_fd, "show", 0777));
225 	TESTSYSCALL(mkdirat(src_fd, "hide", 0777));
226 
227 	for (i = 0; i < map_count; ++i)
228 		if (!strcmp(map_relocations[i].name, "test_map")) {
229 			uint32_t key = 23;
230 			uint32_t value = 1234;
231 			union bpf_attr attr = {
232 				.map_fd = map_relocations[i].fd,
233 				.key    = ptr_to_u64(&key),
234 				.value  = ptr_to_u64(&value),
235 				.flags  = BPF_ANY,
236 			};
237 			TESTSYSCALL(syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM,
238 					    &attr, sizeof(attr)));
239 		}
240 
241 	TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
242 
243 	if (fork())
244 		return 0;
245 
246 	for (;;) {
247 		uint8_t bytes_in[FUSE_MIN_READ_BUFFER];
248 		uint8_t bytes_out[FUSE_MIN_READ_BUFFER] __maybe_unused;
249 		struct fuse_in_header *in_header =
250 			(struct fuse_in_header *)bytes_in;
251 		ssize_t res = read(fuse_dev, bytes_in, sizeof(bytes_in));
252 
253 		if (res == -1)
254 			break;
255 
256 		switch (in_header->opcode) {
257 		case FUSE_LOOKUP | FUSE_PREFILTER: {
258 			char *name = (char *)(bytes_in + sizeof(*in_header));
259 
260 			if (user_messages)
261 				printf("Lookup %s\n", name);
262 			if (!strcmp(name, "hide"))
263 				TESTFUSEOUTERROR(-ENOENT);
264 			else
265 				TESTFUSEOUTREAD(name, strlen(name) + 1);
266 			break;
267 		}
268 		default:
269 			if (user_messages) {
270 				printf("opcode is %d (%s)\n", in_header->opcode,
271 				       fuse_opcode_to_string(
272 					       in_header->opcode));
273 			}
274 			break;
275 		}
276 	}
277 
278 	result = TEST_SUCCESS;
279 
280 out:
281 	for (i = 0; i < map_count; ++i) {
282 		free(map_relocations[i].name);
283 		close(map_relocations[i].fd);
284 	}
285 	free(map_relocations);
286 	umount2(mount_dir, MNT_FORCE);
287 	delete_dir_tree(mount_dir, true);
288 	free(mount_dir);
289 	delete_dir_tree(src_dir, true);
290 	free(src_dir);
291 	if (trace_pid != -1)
292 		kill(trace_pid, SIGKILL);
293 	return result;
294 }
295