Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libfido2/fuzz/libfuzzer.c
39586 views
1
/*
2
* Copyright (c) 2019-2022 Yubico AB. All rights reserved.
3
* Use of this source code is governed by a BSD-style
4
* license that can be found in the LICENSE file.
5
* SPDX-License-Identifier: BSD-2-Clause
6
*/
7
8
#include <openssl/sha.h>
9
10
#include <err.h>
11
#include <fcntl.h>
12
#include <stdbool.h>
13
#include <stdint.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <unistd.h>
18
19
#include "mutator_aux.h"
20
21
extern int fuzz_save_corpus;
22
23
static bool debug;
24
static unsigned int flags = MUTATE_ALL;
25
static unsigned long long test_fail;
26
static unsigned long long test_total;
27
static unsigned long long mutate_fail;
28
static unsigned long long mutate_total;
29
30
int LLVMFuzzerInitialize(int *, char ***);
31
int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
32
size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
33
34
static int
35
save_seed(const char *opt)
36
{
37
const char *path;
38
int fd = -1, status = 1;
39
void *buf = NULL;
40
const size_t buflen = MAXCORPUS;
41
size_t n;
42
struct param *p = NULL;
43
44
if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
45
warnx("usage: --fido-save-seed=<path>");
46
goto fail;
47
}
48
49
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
50
warn("open %s", path);
51
goto fail;
52
}
53
54
if ((buf = malloc(buflen)) == NULL) {
55
warn("malloc");
56
goto fail;
57
}
58
59
n = pack_dummy(buf, buflen);
60
61
if ((p = unpack(buf, n)) == NULL) {
62
warnx("unpack");
63
goto fail;
64
}
65
66
if (write(fd, buf, n) != (ssize_t)n) {
67
warn("write %s", path);
68
goto fail;
69
}
70
71
status = 0;
72
fail:
73
if (fd != -1)
74
close(fd);
75
free(buf);
76
free(p);
77
78
return status;
79
}
80
81
static int
82
save_corpus(const struct param *p)
83
{
84
uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH];
85
size_t blob_len;
86
char path[PATH_MAX];
87
int r, fd;
88
89
if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
90
blob_len > sizeof(blob)) {
91
warnx("pack");
92
return -1;
93
}
94
95
if (SHA256(blob, blob_len, dgst) != dgst) {
96
warnx("sha256");
97
return -1;
98
}
99
100
if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x"
101
"%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4],
102
dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) {
103
warnx("snprintf");
104
return -1;
105
}
106
107
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
108
warn("open %s", path);
109
return -1;
110
}
111
112
if (write(fd, blob, blob_len) != (ssize_t)blob_len) {
113
warn("write");
114
r = -1;
115
} else {
116
warnx("wrote %s", path);
117
r = 0;
118
}
119
120
close(fd);
121
122
return r;
123
}
124
125
static void
126
parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
127
{
128
const char *f;
129
130
if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
131
errx(1, "usage: --fido-mutate=<flag>");
132
133
if (strcmp(f, "seed") == 0)
134
*mutate_flags |= MUTATE_SEED;
135
else if (strcmp(f, "param") == 0)
136
*mutate_flags |= MUTATE_PARAM;
137
else if (strcmp(f, "wiredata") == 0)
138
*mutate_flags |= MUTATE_WIREDATA;
139
else
140
errx(1, "--fido-mutate: unknown flag '%s'", f);
141
}
142
143
int
144
LLVMFuzzerInitialize(int *argc, char ***argv)
145
{
146
unsigned int mutate_flags = 0;
147
148
for (int i = 0; i < *argc; i++)
149
if (strcmp((*argv)[i], "--fido-debug") == 0) {
150
debug = 1;
151
} else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
152
exit(save_seed((*argv)[i]));
153
} else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
154
parse_mutate_flags((*argv)[i], &mutate_flags);
155
}
156
157
if (mutate_flags)
158
flags = mutate_flags;
159
160
return 0;
161
}
162
163
int
164
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
165
{
166
struct param *p;
167
168
if (size > MAXCORPUS)
169
return 0;
170
171
if (++test_total % 100000 == 0 && debug) {
172
double r = (double)test_fail/(double)test_total * 100.0;
173
fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
174
test_fail, test_total, r);
175
}
176
177
if ((p = unpack(data, size)) == NULL)
178
test_fail++;
179
else {
180
fuzz_save_corpus = 0;
181
test(p);
182
if (fuzz_save_corpus && save_corpus(p) < 0)
183
fprintf(stderr, "%s: failed to save corpus\n",
184
__func__);
185
free(p);
186
}
187
188
return 0;
189
}
190
191
size_t
192
LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
193
unsigned int seed) NO_MSAN
194
{
195
struct param *p;
196
uint8_t blob[MAXCORPUS];
197
size_t blob_len;
198
199
memset(&p, 0, sizeof(p));
200
201
#ifdef WITH_MSAN
202
__msan_unpoison(data, maxsize);
203
#endif
204
205
if (++mutate_total % 100000 == 0 && debug) {
206
double r = (double)mutate_fail/(double)mutate_total * 100.0;
207
fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
208
mutate_fail, mutate_total, r);
209
}
210
211
if ((p = unpack(data, size)) == NULL) {
212
mutate_fail++;
213
return pack_dummy(data, maxsize);
214
}
215
216
mutate(p, seed, flags);
217
218
if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
219
blob_len > sizeof(blob) || blob_len > maxsize) {
220
mutate_fail++;
221
free(p);
222
return 0;
223
}
224
225
free(p);
226
227
memcpy(data, blob, blob_len);
228
229
return blob_len;
230
}
231
232