xref: /freebsd/contrib/libder/tests/fuzz_parallel.c (revision 35c0a8c449fd2b7f75029ebed5e10852240f0865)
1 /*-
2  * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/param.h>
8 #include <sys/socket.h>
9 
10 #include <assert.h>
11 #include <pthread.h>
12 #include <signal.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 
19 #include <libder.h>
20 
21 #include "fuzzers.h"
22 
23 struct fuzz_frame {
24 	uint8_t		frame_threads;
25 };
26 
27 struct thread_input {
28 	const uint8_t	*data;
29 	size_t		 datasz;
30 };
31 
32 static void *
thread_main(void * cookie)33 thread_main(void *cookie)
34 {
35 	const struct thread_input *input = cookie;
36 	struct libder_ctx *ctx;
37 	struct libder_object *obj;
38 	const uint8_t *data = input->data;
39 	size_t readsz, sz = input->datasz;
40 
41 	ctx = libder_open();
42 	readsz = sz;
43 	obj = libder_read(ctx, data, &readsz);
44 	if (obj == NULL || readsz != sz)
45 		goto out;
46 
47 	if (obj != NULL) {
48 		uint8_t *buf = NULL;
49 		size_t bufsz = 0;
50 
51 		/*
52 		 * If we successfully read it, then it shouldn't
53 		 * overflow.  We're letting libder allocate the buffer,
54 		 * so we shouldn't be able to hit the 'too small' bit.
55 		 *
56 		 * I can't imagine what other errors might happen, so
57 		 * we'll just assert on it.
58 		 */
59 		buf = libder_write(ctx, obj, buf, &bufsz);
60 		if (buf == NULL)
61 			goto out;
62 
63 		assert(bufsz != 0);
64 
65 		free(buf);
66 	}
67 
68 out:
69 	libder_obj_free(obj);
70 	libder_close(ctx);
71 	return (NULL);
72 }
73 
74 int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t sz)75 LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
76 {
77 	const struct fuzz_frame *frame;
78 	pthread_t *threads;
79 	struct thread_input inp;
80 	size_t nthreads;
81 
82 	if (sz <= sizeof(*frame))
83 		return (-1);
84 
85 	frame = (const void *)data;
86 	data += sizeof(*frame);
87 	sz -= sizeof(*frame);
88 
89 	if (frame->frame_threads < 2)
90 		return (-1);
91 
92 	threads = malloc(sizeof(*threads) * frame->frame_threads);
93 	if (threads == NULL)
94 		return (-1);
95 
96 	inp.data = data;
97 	inp.datasz = sz;
98 
99 	for (nthreads = 0; nthreads < frame->frame_threads; nthreads++) {
100 		if (pthread_create(&threads[nthreads], NULL, thread_main,
101 		    &inp) != 0)
102 			break;
103 	}
104 
105 	for (uint8_t i = 0; i < nthreads; i++)
106 		pthread_join(threads[i], NULL);
107 
108 	free(threads);
109 
110 	return (0);
111 }
112