xref: /spdk/test/app/fuzz/llvm_vfio_fuzz/llvm_vfio_fuzz.c (revision bef7abee6bd20debd5d579116c12a5c6266f1daf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation. All rights reserved.
3  */
4 #include "spdk/stdinc.h"
5 #include "spdk/conf.h"
6 #include "spdk/env.h"
7 #include "spdk/event.h"
8 #include "spdk/util.h"
9 #include "spdk/string.h"
10 #include "spdk/nvme_spec.h"
11 #include "spdk/nvme.h"
12 #include "spdk/likely.h"
13 #include "spdk/file.h"
14 #include "spdk/util.h"
15 
16 #include "spdk/vfio_user_pci.h"
17 #include <linux/vfio.h>
18 #include "spdk/vfio_user_spec.h"
19 
20 #define VFIO_MAXIMUM_SPARSE_MMAP_REGIONS	8
21 
22 typedef int (*fuzzer_fn)(const uint8_t *data, size_t size, struct vfio_device *dev);
23 struct fuzz_type {
24 	fuzzer_fn				fn;
25 	uint32_t				bytes_per_cmd;
26 };
27 
28 #define VFIO_USER_MAX_PAYLOAD_SIZE		(4096)
29 static uint8_t					payload[VFIO_USER_MAX_PAYLOAD_SIZE];
30 
31 static char					*g_ctrlr_path;
32 static char					*g_artifact_prefix;
33 static int32_t					g_time_in_sec = 10;
34 static char					*g_corpus_dir;
35 static uint8_t					*g_repro_data;
36 static size_t					g_repro_size;
37 static pthread_t				g_fuzz_td;
38 static pthread_t				g_reactor_td;
39 static struct fuzz_type				*g_fuzzer;
40 
41 enum IO_POLLER_STATE {
42 	IO_POLLER_STATE_IDLE,
43 	IO_POLLER_STATE_PROCESSING,
44 	IO_POLLER_STATE_TERMINATE_INIT,
45 	IO_POLLER_STATE_TERMINATE_WAIT,
46 	IO_POLLER_STATE_TERMINATE_DONE,
47 };
48 
49 struct io_thread {
50 	enum IO_POLLER_STATE			state;
51 	int					lba_num;
52 	char					*write_buf;
53 	char					*read_buf;
54 	size_t					buf_size;
55 	struct spdk_poller			*run_poller;
56 	struct spdk_thread			*thread;
57 	struct spdk_nvme_ctrlr			*io_ctrlr;
58 	pthread_t				io_td;
59 	pthread_t				term_td;
60 	struct spdk_nvme_ns			*io_ns;
61 	struct spdk_nvme_qpair			*io_qpair;
62 	char					*io_ctrlr_path;
63 } g_io_thread;
64 
65 static int
66 fuzz_vfio_user_version(const uint8_t *data, size_t size, struct vfio_device *dev)
67 {
68 	struct vfio_user_version *version = (struct vfio_user_version *)payload;
69 
70 	version->major = ((uint16_t)data[0] << 8) + (uint16_t)data[1];
71 	version->minor = ((uint16_t)data[2] << 8) + (uint16_t)data[3];
72 
73 	return spdk_vfio_user_dev_send_request(dev, VFIO_USER_VERSION, payload,
74 					       sizeof(struct vfio_user_version),
75 					       sizeof(payload), NULL, 0);
76 }
77 
78 static int
79 fuzz_vfio_user_region_rw(const uint8_t *data, size_t size, struct vfio_device *dev)
80 {
81 	uint8_t buf[4];
82 	uint64_t offset = 0;
83 
84 	offset = ((uint64_t)data[0] << 8) + (uint64_t)data[1];
85 	offset = (SPDK_ALIGN_FLOOR(offset, 4)) % 4096;
86 	memcpy(buf, &data[2], sizeof(buf));
87 
88 	/* writes to BAR0 depending on the register, therefore the return value is never checked */
89 	spdk_vfio_user_pci_bar_access(dev, VFIO_PCI_BAR0_REGION_INDEX, offset, sizeof(buf),
90 				      &buf, true);
91 	return spdk_vfio_user_pci_bar_access(dev, VFIO_PCI_BAR0_REGION_INDEX, offset, sizeof(buf),
92 					     &buf, false);
93 }
94 
95 static struct fuzz_type g_fuzzers[] = {
96 	{ .fn = fuzz_vfio_user_region_rw,			.bytes_per_cmd = 6},
97 	{ .fn = fuzz_vfio_user_version,				.bytes_per_cmd = 4},
98 	{ .fn = NULL,						.bytes_per_cmd = 0}
99 };
100 
101 #define NUM_FUZZERS (SPDK_COUNTOF(g_fuzzers) - 1)
102 
103 static int
104 TestOneInput(const uint8_t *data, size_t size)
105 {
106 	struct vfio_device *dev = NULL;
107 	char ctrlr_path[PATH_MAX];
108 	int ret = 0;
109 
110 	if (size < g_fuzzer->bytes_per_cmd) {
111 		return -1;
112 	}
113 
114 	snprintf(ctrlr_path, sizeof(ctrlr_path), "%s/cntrl", g_ctrlr_path);
115 	ret = access(ctrlr_path, F_OK);
116 	if (ret != 0) {
117 		fprintf(stderr, "Access path %s failed\n", ctrlr_path);
118 		spdk_app_stop(-1);
119 		return -1;
120 	}
121 
122 	dev = spdk_vfio_user_setup(ctrlr_path);
123 	if (dev == NULL) {
124 		fprintf(stderr, "spdk_vfio_user_setup() failed for controller path '%s'\n",
125 			ctrlr_path);
126 		spdk_app_stop(-1);
127 		return -1;
128 	}
129 
130 	/* run cmds here */
131 	if (g_fuzzer->fn != NULL) {
132 		g_fuzzer->fn(data, size, dev);
133 	}
134 
135 	spdk_vfio_user_release(dev);
136 	return 0;
137 }
138 
139 int LLVMFuzzerRunDriver(int *argc, char ***argv, int (*UserCb)(const uint8_t *Data, size_t Size));
140 
141 static void
142 io_terminate(void *ctx)
143 {
144 	((struct io_thread *)ctx)->state = IO_POLLER_STATE_TERMINATE_INIT;
145 }
146 
147 static void
148 exit_handler(void)
149 {
150 	if (g_io_thread.io_ctrlr_path && g_io_thread.thread) {
151 		spdk_thread_send_msg(g_io_thread.thread, io_terminate, &g_io_thread);
152 
153 	} else if (spdk_thread_get_app_thread()) {
154 		spdk_app_stop(0);
155 	}
156 
157 	pthread_join(g_reactor_td, NULL);
158 }
159 
160 static void *
161 start_fuzzer(void *ctx)
162 {
163 	char *_argv[] = {
164 		"spdk",
165 		"-len_control=0",
166 		/* TODO: temporarily disable leak detection due to issues
167 		 * with ASAN and DPDK, see #2455 and #2992.
168 		 */
169 		"-detect_leaks=0",
170 		NULL,
171 		NULL,
172 		NULL,
173 		NULL
174 	};
175 	char time_str[128];
176 	char prefix[PATH_MAX];
177 	char len_str[128];
178 	char **argv = _argv;
179 	int argc = SPDK_COUNTOF(_argv);
180 	uint32_t len = 0;
181 
182 	spdk_unaffinitize_thread();
183 	snprintf(prefix, sizeof(prefix), "-artifact_prefix=%s", g_artifact_prefix);
184 	argv[argc - 4] = prefix;
185 	len = 10 * g_fuzzer->bytes_per_cmd;
186 	snprintf(len_str, sizeof(len_str), "-max_len=%d", len);
187 	argv[argc - 3] = len_str;
188 	snprintf(time_str, sizeof(time_str), "-max_total_time=%d", g_time_in_sec);
189 	argv[argc - 2] = time_str;
190 	argv[argc - 1] = g_corpus_dir;
191 
192 	atexit(exit_handler);
193 
194 	free(g_artifact_prefix);
195 
196 	if (g_repro_data) {
197 		printf("Running single test based on reproduction data file.\n");
198 		TestOneInput(g_repro_data, g_repro_size);
199 		printf("Done.\n");
200 	} else {
201 		LLVMFuzzerRunDriver(&argc, &argv, TestOneInput);
202 		/* TODO: in the normal case, LLVMFuzzerRunDriver never returns - it calls exit()
203 		 * directly and we never get here.  But this behavior isn't really documented
204 		 * anywhere by LLVM.
205 		 */
206 	}
207 
208 	return NULL;
209 }
210 
211 static void
212 read_complete(void *arg, const struct spdk_nvme_cpl *completion)
213 {
214 	int sectors_num = 0;
215 	struct io_thread *io = (struct io_thread *)arg;
216 
217 	if (spdk_nvme_cpl_is_error(completion)) {
218 		spdk_nvme_qpair_print_completion(io->io_qpair, (struct spdk_nvme_cpl *)completion);
219 		fprintf(stderr, "I/O read error status: %s\n",
220 			spdk_nvme_cpl_get_status_string(&completion->status));
221 		io->state = IO_POLLER_STATE_TERMINATE_WAIT;
222 		pthread_kill(g_fuzz_td, SIGSEGV);
223 		return;
224 	}
225 
226 	if (memcmp(io->read_buf, io->write_buf, io->buf_size)) {
227 		fprintf(stderr, "I/O corrupt, value not the same\n");
228 		io->state = IO_POLLER_STATE_TERMINATE_WAIT;
229 		pthread_kill(g_fuzz_td, SIGSEGV);
230 		return;
231 	}
232 
233 	sectors_num =  spdk_nvme_ns_get_num_sectors(io->io_ns);
234 	io->lba_num = (io->lba_num + 1) % sectors_num;
235 	if (io->state != IO_POLLER_STATE_TERMINATE_INIT) {
236 		io->state = IO_POLLER_STATE_IDLE;
237 	}
238 }
239 
240 static void
241 write_complete(void *arg, const struct spdk_nvme_cpl *completion)
242 {
243 	int rc = 0;
244 	struct io_thread *io = (struct io_thread *)arg;
245 
246 	if (spdk_nvme_cpl_is_error(completion)) {
247 		spdk_nvme_qpair_print_completion(io->io_qpair,
248 						 (struct spdk_nvme_cpl *)completion);
249 		fprintf(stderr, "I/O write error status: %s\n",
250 			spdk_nvme_cpl_get_status_string(&completion->status));
251 		io->state = IO_POLLER_STATE_TERMINATE_WAIT;
252 		pthread_kill(g_fuzz_td, SIGSEGV);
253 		return;
254 	}
255 	rc = spdk_nvme_ns_cmd_read(io->io_ns, io->io_qpair,
256 				   io->read_buf, io->lba_num, 1,
257 				   read_complete, io, 0);
258 	if (rc != 0) {
259 		fprintf(stderr, "starting read I/O failed\n");
260 		io->state = IO_POLLER_STATE_TERMINATE_WAIT;
261 		pthread_kill(g_fuzz_td, SIGSEGV);
262 	}
263 }
264 
265 static void *
266 terminate_io_thread(void *ctx)
267 {
268 	struct io_thread *io = (struct io_thread *)ctx;
269 
270 	spdk_nvme_ctrlr_free_io_qpair(io->io_qpair);
271 	spdk_nvme_detach(io->io_ctrlr);
272 	spdk_free(io->write_buf);
273 	spdk_free(io->read_buf);
274 
275 	io->state = IO_POLLER_STATE_TERMINATE_DONE;
276 
277 	return NULL;
278 }
279 
280 static int
281 io_poller(void *ctx)
282 {
283 	int ret = 0;
284 	struct io_thread *io = (struct io_thread *)ctx;
285 	size_t i;
286 	unsigned int seed = 0;
287 	int *write_buf = (int *)io->write_buf;
288 
289 	switch (io->state) {
290 	case IO_POLLER_STATE_IDLE:
291 		break;
292 	case IO_POLLER_STATE_PROCESSING:
293 		spdk_nvme_qpair_process_completions(io->io_qpair, 0);
294 		return SPDK_POLLER_BUSY;
295 	case IO_POLLER_STATE_TERMINATE_INIT:
296 		if (spdk_nvme_qpair_get_num_outstanding_reqs(io->io_qpair) > 0) {
297 			spdk_nvme_qpair_process_completions(io->io_qpair, 0);
298 			return SPDK_POLLER_BUSY;
299 		}
300 
301 		io->state = IO_POLLER_STATE_TERMINATE_WAIT;
302 		ret = pthread_create(&io->term_td, NULL, terminate_io_thread, ctx);
303 		if (ret != 0) {
304 			abort();
305 		}
306 		return SPDK_POLLER_BUSY;
307 	case IO_POLLER_STATE_TERMINATE_WAIT:
308 		return SPDK_POLLER_BUSY;
309 	case IO_POLLER_STATE_TERMINATE_DONE:
310 		spdk_poller_unregister(&io->run_poller);
311 		spdk_thread_exit(spdk_get_thread());
312 		spdk_app_stop(0);
313 		return SPDK_POLLER_IDLE;
314 	default:
315 		break;
316 	}
317 
318 	io->state = IO_POLLER_STATE_PROCESSING;
319 
320 	/* Compiler should optimize the "/ sizeof(int)" into a right shift. */
321 	for (i = 0; i < io->buf_size / sizeof(int); i++) {
322 		write_buf[i] = rand_r(&seed);
323 	}
324 
325 	ret = spdk_nvme_ns_cmd_write(io->io_ns, io->io_qpair,
326 				     io->write_buf, io->lba_num, 1,
327 				     write_complete, io, 0);
328 	if (ret < 0) {
329 		fprintf(stderr, "starting write I/O failed\n");
330 		pthread_kill(g_fuzz_td, SIGSEGV);
331 		return SPDK_POLLER_IDLE;
332 	}
333 
334 	return SPDK_POLLER_IDLE;
335 }
336 
337 static void
338 start_io_poller(void *ctx)
339 {
340 	struct io_thread *io = (struct io_thread *)ctx;
341 
342 	io->run_poller = SPDK_POLLER_REGISTER(io_poller, ctx, 0);
343 	if (io->run_poller == NULL) {
344 		fprintf(stderr, "Failed to register a poller for IO.\n");
345 		spdk_app_stop(-1);
346 		pthread_kill(g_fuzz_td, SIGSEGV);
347 	}
348 }
349 
350 static void *
351 init_io(void *ctx)
352 {
353 	struct spdk_nvme_transport_id trid = {};
354 	int nsid = 0;
355 
356 	snprintf(trid.traddr, sizeof(trid.traddr), "%s", g_io_thread.io_ctrlr_path);
357 
358 	trid.trtype = SPDK_NVME_TRANSPORT_VFIOUSER;
359 	g_io_thread.io_ctrlr = spdk_nvme_connect(&trid, NULL, 0);
360 	if (g_io_thread.io_ctrlr == NULL) {
361 		fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n",
362 			trid.traddr);
363 		spdk_app_stop(-1);
364 		pthread_kill(g_fuzz_td, SIGSEGV);
365 		return NULL;
366 	}
367 
368 	g_io_thread.io_qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_io_thread.io_ctrlr, NULL, 0);
369 	if (g_io_thread.io_qpair == NULL) {
370 		spdk_nvme_detach(g_io_thread.io_ctrlr);
371 		fprintf(stderr, "spdk_nvme_ctrlr_alloc_io_qpair failed\n");
372 		spdk_app_stop(-1);
373 		pthread_kill(g_fuzz_td, SIGSEGV);
374 		return NULL;
375 	}
376 
377 	if (spdk_nvme_ctrlr_get_num_ns(g_io_thread.io_ctrlr) == 0) {
378 		fprintf(stderr, "no namespaces for IO\n");
379 		spdk_app_stop(-1);
380 		pthread_kill(g_fuzz_td, SIGSEGV);
381 		return NULL;
382 	}
383 
384 	nsid = spdk_nvme_ctrlr_get_first_active_ns(g_io_thread.io_ctrlr);
385 	g_io_thread.io_ns = spdk_nvme_ctrlr_get_ns(g_io_thread.io_ctrlr, nsid);
386 	if (!g_io_thread.io_ns) {
387 		fprintf(stderr, "no io_ns for IO\n");
388 		spdk_app_stop(-1);
389 		pthread_kill(g_fuzz_td, SIGSEGV);
390 		return NULL;
391 	}
392 
393 	g_io_thread.buf_size = spdk_nvme_ns_get_sector_size(g_io_thread.io_ns);
394 
395 	g_io_thread.read_buf = spdk_zmalloc(g_io_thread.buf_size, 0x1000, NULL,
396 					    SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
397 
398 	g_io_thread.write_buf = spdk_zmalloc(g_io_thread.buf_size, 0x1000, NULL,
399 					     SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
400 
401 	if (!g_io_thread.write_buf || !g_io_thread.read_buf) {
402 		fprintf(stderr, "cannot allocated memory for io buffers\n");
403 		spdk_app_stop(-1);
404 		pthread_kill(g_fuzz_td, SIGSEGV);
405 		return NULL;
406 	}
407 
408 	g_io_thread.thread = spdk_thread_create("io_thread", NULL);
409 	if (g_io_thread.thread == NULL) {
410 		fprintf(stderr, "cannot create io thread\n");
411 		spdk_app_stop(-1);
412 		pthread_kill(g_fuzz_td, SIGSEGV);
413 		return NULL;
414 	}
415 
416 	spdk_thread_send_msg(g_io_thread.thread, start_io_poller, &g_io_thread);
417 
418 	return NULL;
419 }
420 
421 static void
422 begin_fuzz(void *ctx)
423 {
424 	int rc = 0;
425 
426 	g_reactor_td = pthread_self();
427 
428 	rc = pthread_create(&g_fuzz_td, NULL, start_fuzzer, NULL);
429 	if (rc != 0) {
430 		spdk_app_stop(-1);
431 		return;
432 	}
433 
434 	/* posix thread is use to avoid deadlock during spdk_nvme_connect
435 	 * vfio-user version negotiation may block when waiting for response
436 	 */
437 	if (g_io_thread.io_ctrlr_path) {
438 		rc = pthread_create(&g_io_thread.io_td, NULL, init_io, NULL);
439 		if (rc != 0) {
440 			spdk_app_stop(-1);
441 			pthread_kill(g_fuzz_td, SIGSEGV);
442 		}
443 	}
444 }
445 
446 static void
447 vfio_fuzz_usage(void)
448 {
449 	fprintf(stderr, " -D                        Path of corpus directory.\n");
450 	fprintf(stderr, " -F                        Path for ctrlr that should be fuzzed.\n");
451 	fprintf(stderr, " -N                        Name of reproduction data file.\n");
452 	fprintf(stderr, " -P                        Provide a prefix to use when saving artifacts.\n");
453 	fprintf(stderr, " -t                        Time to run fuzz tests (in seconds). Default: 10\n");
454 	fprintf(stderr, " -Y                        Path of addition controller to perform io.\n");
455 	fprintf(stderr, " -Z                        Fuzzer to run (0 to %lu)\n", NUM_FUZZERS - 1);
456 }
457 
458 static int
459 vfio_fuzz_parse(int ch, char *arg)
460 {
461 	long long tmp = 0;
462 	FILE *repro_file = NULL;
463 
464 	switch (ch) {
465 	case 'D':
466 		g_corpus_dir = strdup(optarg);
467 		if (!g_corpus_dir) {
468 			fprintf(stderr, "cannot strdup: %s\n", optarg);
469 			return -ENOMEM;
470 		}
471 		break;
472 	case 'F':
473 		g_ctrlr_path = strdup(optarg);
474 		if (!g_ctrlr_path) {
475 			fprintf(stderr, "cannot strdup: %s\n", optarg);
476 			return -ENOMEM;
477 		}
478 		break;
479 	case 'N':
480 		repro_file = fopen(optarg, "r");
481 		if (repro_file == NULL) {
482 			fprintf(stderr, "could not open %s: %s\n", optarg, spdk_strerror(errno));
483 			return -1;
484 		}
485 		g_repro_data = spdk_posix_file_load(repro_file, &g_repro_size);
486 		if (g_repro_data == NULL) {
487 			fprintf(stderr, "could not load data for file %s\n", optarg);
488 			return -1;
489 		}
490 		break;
491 	case 'P':
492 		g_artifact_prefix = strdup(optarg);
493 		if (!g_artifact_prefix) {
494 			fprintf(stderr, "cannot strdup: %s\n", optarg);
495 			return -ENOMEM;
496 		}
497 		break;
498 	case 'Y':
499 		g_io_thread.io_ctrlr_path = strdup(optarg);
500 		if (!g_io_thread.io_ctrlr_path) {
501 			fprintf(stderr, "cannot strdup: %s\n", optarg);
502 			return -ENOMEM;
503 		}
504 		break;
505 	case 't':
506 	case 'Z':
507 		tmp = spdk_strtoll(optarg, 10);
508 		if (tmp < 0 || tmp >= INT_MAX) {
509 			fprintf(stderr, "Invalid value '%s' for option -%c.\n", optarg, ch);
510 			return -EINVAL;
511 		}
512 		switch (ch) {
513 		case 't':
514 			g_time_in_sec = tmp;
515 			break;
516 		case 'Z':
517 			if ((unsigned long)tmp >= NUM_FUZZERS) {
518 				fprintf(stderr, "Invalid fuzz type %lld (max %lu)\n", tmp, NUM_FUZZERS - 1);
519 				return -EINVAL;
520 			}
521 			g_fuzzer = &g_fuzzers[tmp];
522 			break;
523 		}
524 		break;
525 	case '?':
526 	default:
527 		return -EINVAL;
528 	}
529 	return 0;
530 }
531 
532 static void
533 fuzz_shutdown(void)
534 {
535 	/* If the user terminates the fuzzer prematurely, it is likely due
536 	 * to an input hang.  So raise a SIGSEGV signal which will cause the
537 	 * fuzzer to generate a crash file for the last input.
538 	 *
539 	 * Note that the fuzzer will always generate a crash file, even if
540 	 * we get our TestOneInput() function (which is called by the fuzzer)
541 	 * to pthread_exit().  So just doing the SIGSEGV here in all cases is
542 	 * simpler than trying to differentiate between hung inputs and
543 	 * an impatient user.
544 	 */
545 	pthread_kill(g_fuzz_td, SIGSEGV);
546 }
547 
548 int
549 main(int argc, char **argv)
550 {
551 	struct spdk_app_opts opts = {};
552 	int rc = 0;
553 
554 	spdk_app_opts_init(&opts, sizeof(opts));
555 	opts.name = "vfio_fuzz";
556 	opts.shutdown_cb = fuzz_shutdown;
557 
558 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "D:F:N:P:t:Y:Z:", NULL, vfio_fuzz_parse,
559 				      vfio_fuzz_usage) != SPDK_APP_PARSE_ARGS_SUCCESS)) {
560 		return rc;
561 	}
562 
563 	if (!g_corpus_dir) {
564 		fprintf(stderr, "Must specify corpus dir with -D option\n");
565 		return -1;
566 	}
567 
568 	if (!g_ctrlr_path) {
569 		fprintf(stderr, "Must specify ctrlr path with -F option\n");
570 		return -1;
571 	}
572 
573 	if (!g_fuzzer) {
574 		fprintf(stderr, "Must specify fuzzer with -Z option\n");
575 		return -1;
576 	}
577 
578 	rc = spdk_app_start(&opts, begin_fuzz, NULL);
579 
580 	spdk_app_fini();
581 	return rc;
582 }
583