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