1*35c0a8c4SKyle Evans /*-
2*35c0a8c4SKyle Evans * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org>
3*35c0a8c4SKyle Evans *
4*35c0a8c4SKyle Evans * SPDX-License-Identifier: BSD-2-Clause
5*35c0a8c4SKyle Evans */
6*35c0a8c4SKyle Evans
7*35c0a8c4SKyle Evans #include <sys/param.h>
8*35c0a8c4SKyle Evans #include <sys/socket.h>
9*35c0a8c4SKyle Evans
10*35c0a8c4SKyle Evans #include <assert.h>
11*35c0a8c4SKyle Evans #include <pthread.h>
12*35c0a8c4SKyle Evans #include <signal.h>
13*35c0a8c4SKyle Evans #include <stdbool.h>
14*35c0a8c4SKyle Evans #include <stdio.h>
15*35c0a8c4SKyle Evans #include <unistd.h>
16*35c0a8c4SKyle Evans
17*35c0a8c4SKyle Evans #include <libder.h>
18*35c0a8c4SKyle Evans
19*35c0a8c4SKyle Evans #include "fuzzers.h"
20*35c0a8c4SKyle Evans
21*35c0a8c4SKyle Evans struct supply_data {
22*35c0a8c4SKyle Evans const uint8_t *data;
23*35c0a8c4SKyle Evans volatile size_t datasz;
24*35c0a8c4SKyle Evans int socket;
25*35c0a8c4SKyle Evans };
26*35c0a8c4SKyle Evans
27*35c0a8c4SKyle Evans static void *
supply_thread(void * data)28*35c0a8c4SKyle Evans supply_thread(void *data)
29*35c0a8c4SKyle Evans {
30*35c0a8c4SKyle Evans struct supply_data *sdata = data;
31*35c0a8c4SKyle Evans size_t sz = sdata->datasz;
32*35c0a8c4SKyle Evans ssize_t writesz;
33*35c0a8c4SKyle Evans
34*35c0a8c4SKyle Evans do {
35*35c0a8c4SKyle Evans writesz = write(sdata->socket, sdata->data, sz);
36*35c0a8c4SKyle Evans
37*35c0a8c4SKyle Evans data += writesz;
38*35c0a8c4SKyle Evans sz -= writesz;
39*35c0a8c4SKyle Evans } while (sz != 0 && writesz > 0);
40*35c0a8c4SKyle Evans
41*35c0a8c4SKyle Evans sdata->datasz = sz;
42*35c0a8c4SKyle Evans shutdown(sdata->socket, SHUT_RDWR);
43*35c0a8c4SKyle Evans close(sdata->socket);
44*35c0a8c4SKyle Evans
45*35c0a8c4SKyle Evans return (NULL);
46*35c0a8c4SKyle Evans }
47*35c0a8c4SKyle Evans
48*35c0a8c4SKyle Evans static int
fuzz_fd(const struct fuzz_params * fparams,const uint8_t * data,size_t sz)49*35c0a8c4SKyle Evans fuzz_fd(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)
50*35c0a8c4SKyle Evans {
51*35c0a8c4SKyle Evans struct supply_data sdata;
52*35c0a8c4SKyle Evans struct libder_ctx *ctx;
53*35c0a8c4SKyle Evans struct libder_object *obj;
54*35c0a8c4SKyle Evans size_t totalsz;
55*35c0a8c4SKyle Evans int sockets[2];
56*35c0a8c4SKyle Evans pid_t pid;
57*35c0a8c4SKyle Evans int ret;
58*35c0a8c4SKyle Evans
59*35c0a8c4SKyle Evans ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0,
60*35c0a8c4SKyle Evans &sockets[0]);
61*35c0a8c4SKyle Evans if (ret == -1)
62*35c0a8c4SKyle Evans return (-1);
63*35c0a8c4SKyle Evans
64*35c0a8c4SKyle Evans sdata.data = data;
65*35c0a8c4SKyle Evans sdata.datasz = sz;
66*35c0a8c4SKyle Evans sdata.socket = sockets[1];
67*35c0a8c4SKyle Evans signal(SIGCHLD, SIG_IGN);
68*35c0a8c4SKyle Evans pid = fork();
69*35c0a8c4SKyle Evans if (pid == -1) {
70*35c0a8c4SKyle Evans close(sockets[0]);
71*35c0a8c4SKyle Evans close(sockets[1]);
72*35c0a8c4SKyle Evans return (-1);
73*35c0a8c4SKyle Evans }
74*35c0a8c4SKyle Evans
75*35c0a8c4SKyle Evans if (pid == 0) {
76*35c0a8c4SKyle Evans close(sockets[0]);
77*35c0a8c4SKyle Evans supply_thread(&sdata);
78*35c0a8c4SKyle Evans _exit(0);
79*35c0a8c4SKyle Evans } else {
80*35c0a8c4SKyle Evans close(sockets[1]);
81*35c0a8c4SKyle Evans }
82*35c0a8c4SKyle Evans
83*35c0a8c4SKyle Evans totalsz = 0;
84*35c0a8c4SKyle Evans ret = 0;
85*35c0a8c4SKyle Evans ctx = libder_open();
86*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict);
87*35c0a8c4SKyle Evans while (totalsz < sz) {
88*35c0a8c4SKyle Evans size_t readsz = 0;
89*35c0a8c4SKyle Evans
90*35c0a8c4SKyle Evans obj = libder_read_fd(ctx, sockets[0], &readsz);
91*35c0a8c4SKyle Evans libder_obj_free(obj);
92*35c0a8c4SKyle Evans
93*35c0a8c4SKyle Evans /*
94*35c0a8c4SKyle Evans * Even invalid reads should consume at least one byte.
95*35c0a8c4SKyle Evans */
96*35c0a8c4SKyle Evans assert(readsz != 0);
97*35c0a8c4SKyle Evans
98*35c0a8c4SKyle Evans totalsz += readsz;
99*35c0a8c4SKyle Evans if (readsz == 0)
100*35c0a8c4SKyle Evans break;
101*35c0a8c4SKyle Evans }
102*35c0a8c4SKyle Evans
103*35c0a8c4SKyle Evans assert(totalsz == sz);
104*35c0a8c4SKyle Evans libder_close(ctx);
105*35c0a8c4SKyle Evans close(sockets[0]);
106*35c0a8c4SKyle Evans
107*35c0a8c4SKyle Evans return (ret);
108*35c0a8c4SKyle Evans }
109*35c0a8c4SKyle Evans
110*35c0a8c4SKyle Evans static int
fuzz_file(const struct fuzz_params * fparams,const uint8_t * data,size_t sz)111*35c0a8c4SKyle Evans fuzz_file(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)
112*35c0a8c4SKyle Evans {
113*35c0a8c4SKyle Evans FILE *fp;
114*35c0a8c4SKyle Evans struct libder_ctx *ctx;
115*35c0a8c4SKyle Evans struct libder_object *obj;
116*35c0a8c4SKyle Evans size_t totalsz;
117*35c0a8c4SKyle Evans int ret;
118*35c0a8c4SKyle Evans
119*35c0a8c4SKyle Evans if (fparams->buftype >= BUFFER_END)
120*35c0a8c4SKyle Evans return (-1);
121*35c0a8c4SKyle Evans
122*35c0a8c4SKyle Evans fp = fmemopen(__DECONST(void *, data), sz, "rb");
123*35c0a8c4SKyle Evans assert(fp != NULL);
124*35c0a8c4SKyle Evans
125*35c0a8c4SKyle Evans switch (fparams->buftype) {
126*35c0a8c4SKyle Evans case BUFFER_NONE:
127*35c0a8c4SKyle Evans setvbuf(fp, NULL, 0, _IONBF);
128*35c0a8c4SKyle Evans break;
129*35c0a8c4SKyle Evans case BUFFER_FULL:
130*35c0a8c4SKyle Evans setvbuf(fp, NULL, 0, _IOFBF);
131*35c0a8c4SKyle Evans break;
132*35c0a8c4SKyle Evans case BUFFER_END:
133*35c0a8c4SKyle Evans assert(0);
134*35c0a8c4SKyle Evans }
135*35c0a8c4SKyle Evans
136*35c0a8c4SKyle Evans totalsz = 0;
137*35c0a8c4SKyle Evans ret = 0;
138*35c0a8c4SKyle Evans ctx = libder_open();
139*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict);
140*35c0a8c4SKyle Evans while (!feof(fp)) {
141*35c0a8c4SKyle Evans size_t readsz = 0;
142*35c0a8c4SKyle Evans
143*35c0a8c4SKyle Evans obj = libder_read_file(ctx, fp, &readsz);
144*35c0a8c4SKyle Evans libder_obj_free(obj);
145*35c0a8c4SKyle Evans
146*35c0a8c4SKyle Evans if (obj == NULL)
147*35c0a8c4SKyle Evans assert(readsz != 0 || feof(fp));
148*35c0a8c4SKyle Evans else
149*35c0a8c4SKyle Evans assert(readsz != 0);
150*35c0a8c4SKyle Evans
151*35c0a8c4SKyle Evans totalsz += readsz;
152*35c0a8c4SKyle Evans }
153*35c0a8c4SKyle Evans
154*35c0a8c4SKyle Evans assert(totalsz == sz);
155*35c0a8c4SKyle Evans libder_close(ctx);
156*35c0a8c4SKyle Evans fclose(fp);
157*35c0a8c4SKyle Evans
158*35c0a8c4SKyle Evans return (ret);
159*35c0a8c4SKyle Evans }
160*35c0a8c4SKyle Evans
161*35c0a8c4SKyle Evans static int
fuzz_plain(const struct fuzz_params * fparams,const uint8_t * data,size_t sz)162*35c0a8c4SKyle Evans fuzz_plain(const struct fuzz_params *fparams, const uint8_t *data, size_t sz)
163*35c0a8c4SKyle Evans {
164*35c0a8c4SKyle Evans struct libder_ctx *ctx;
165*35c0a8c4SKyle Evans struct libder_object *obj;
166*35c0a8c4SKyle Evans int ret;
167*35c0a8c4SKyle Evans
168*35c0a8c4SKyle Evans if (sz == 0)
169*35c0a8c4SKyle Evans return (-1);
170*35c0a8c4SKyle Evans
171*35c0a8c4SKyle Evans ret = 0;
172*35c0a8c4SKyle Evans ctx = libder_open();
173*35c0a8c4SKyle Evans libder_set_strict(ctx, !!fparams->strict);
174*35c0a8c4SKyle Evans do {
175*35c0a8c4SKyle Evans size_t readsz;
176*35c0a8c4SKyle Evans
177*35c0a8c4SKyle Evans readsz = sz;
178*35c0a8c4SKyle Evans obj = libder_read(ctx, data, &readsz);
179*35c0a8c4SKyle Evans libder_obj_free(obj);
180*35c0a8c4SKyle Evans
181*35c0a8c4SKyle Evans if (obj == NULL)
182*35c0a8c4SKyle Evans assert(readsz != 0 || readsz == sz);
183*35c0a8c4SKyle Evans else
184*35c0a8c4SKyle Evans assert(readsz != 0);
185*35c0a8c4SKyle Evans
186*35c0a8c4SKyle Evans /*
187*35c0a8c4SKyle Evans * If we hit an entirely invalid segment of the buffer, we'll
188*35c0a8c4SKyle Evans * just skip a byte and try again.
189*35c0a8c4SKyle Evans */
190*35c0a8c4SKyle Evans data += MAX(1, readsz);
191*35c0a8c4SKyle Evans sz -= MAX(1, readsz);
192*35c0a8c4SKyle Evans } while (sz != 0);
193*35c0a8c4SKyle Evans
194*35c0a8c4SKyle Evans libder_close(ctx);
195*35c0a8c4SKyle Evans
196*35c0a8c4SKyle Evans return (ret);
197*35c0a8c4SKyle Evans };
198*35c0a8c4SKyle Evans
199*35c0a8c4SKyle Evans static bool
validate_padding(const struct fuzz_params * fparams)200*35c0a8c4SKyle Evans validate_padding(const struct fuzz_params *fparams)
201*35c0a8c4SKyle Evans {
202*35c0a8c4SKyle Evans const uint8_t *end = (const void *)(fparams + 1);
203*35c0a8c4SKyle Evans const uint8_t *pad = (const uint8_t *)&fparams->PARAM_PAD_START;
204*35c0a8c4SKyle Evans
205*35c0a8c4SKyle Evans while (pad < end) {
206*35c0a8c4SKyle Evans if (*pad++ != 0)
207*35c0a8c4SKyle Evans return (false);
208*35c0a8c4SKyle Evans }
209*35c0a8c4SKyle Evans
210*35c0a8c4SKyle Evans return (true);
211*35c0a8c4SKyle Evans }
212*35c0a8c4SKyle Evans
213*35c0a8c4SKyle Evans int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t sz)214*35c0a8c4SKyle Evans LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz)
215*35c0a8c4SKyle Evans {
216*35c0a8c4SKyle Evans const struct fuzz_params *fparams;
217*35c0a8c4SKyle Evans
218*35c0a8c4SKyle Evans if (sz <= sizeof(*fparams))
219*35c0a8c4SKyle Evans return (-1);
220*35c0a8c4SKyle Evans
221*35c0a8c4SKyle Evans fparams = (const void *)data;
222*35c0a8c4SKyle Evans if (fparams->type >= STREAM_END)
223*35c0a8c4SKyle Evans return (-1);
224*35c0a8c4SKyle Evans
225*35c0a8c4SKyle Evans if (!validate_padding(fparams))
226*35c0a8c4SKyle Evans return (-1);
227*35c0a8c4SKyle Evans
228*35c0a8c4SKyle Evans data += sizeof(*fparams);
229*35c0a8c4SKyle Evans sz -= sizeof(*fparams);
230*35c0a8c4SKyle Evans
231*35c0a8c4SKyle Evans if (fparams->type != STREAM_FILE && fparams->buftype != BUFFER_NONE)
232*35c0a8c4SKyle Evans return (-1);
233*35c0a8c4SKyle Evans
234*35c0a8c4SKyle Evans switch (fparams->type) {
235*35c0a8c4SKyle Evans case STREAM_FD:
236*35c0a8c4SKyle Evans return (fuzz_fd(fparams, data, sz));
237*35c0a8c4SKyle Evans case STREAM_FILE:
238*35c0a8c4SKyle Evans return (fuzz_file(fparams, data, sz));
239*35c0a8c4SKyle Evans case STREAM_PLAIN:
240*35c0a8c4SKyle Evans return (fuzz_plain(fparams, data, sz));
241*35c0a8c4SKyle Evans case STREAM_END:
242*35c0a8c4SKyle Evans assert(0);
243*35c0a8c4SKyle Evans }
244*35c0a8c4SKyle Evans
245*35c0a8c4SKyle Evans __builtin_trap();
246*35c0a8c4SKyle Evans }
247