summaryrefslogtreecommitdiff
path: root/fuzz/libfuzzer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz/libfuzzer.c')
-rw-r--r--fuzz/libfuzzer.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/fuzz/libfuzzer.c b/fuzz/libfuzzer.c
new file mode 100644
index 0000000..ac9c798
--- /dev/null
+++ b/fuzz/libfuzzer.c
@@ -0,0 +1,174 @@
1/*
2 * Copyright (c) 2019 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 */
6
7#include <err.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include "mutator_aux.h"
17
18static bool debug;
19static unsigned int flags = MUTATE_ALL;
20static unsigned long long test_fail;
21static unsigned long long test_total;
22static unsigned long long mutate_fail;
23static unsigned long long mutate_total;
24
25int LLVMFuzzerInitialize(int *, char ***);
26int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
27size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
28
29static int
30save_seed(const char *opt)
31{
32 const char *path;
33 int fd = -1, status = 1;
34 void *buf = NULL;
35 const size_t buflen = 4096;
36 size_t n;
37 struct param *p = NULL;
38
39 if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
40 warnx("usage: --fido-save-seed=<path>");
41 goto fail;
42 }
43
44 if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
45 warn("open %s", path);
46 goto fail;
47 }
48
49 if ((buf = malloc(buflen)) == NULL) {
50 warn("malloc");
51 goto fail;
52 }
53
54 n = pack_dummy(buf, buflen);
55
56 if ((p = unpack(buf, n)) == NULL) {
57 warnx("unpack");
58 goto fail;
59 }
60
61 if (write(fd, buf, n) != (ssize_t)n) {
62 warn("write %s", path);
63 goto fail;
64 }
65
66 status = 0;
67fail:
68 if (fd != -1)
69 close(fd);
70 free(buf);
71 free(p);
72
73 return status;
74}
75
76static void
77parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
78{
79 const char *f;
80
81 if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
82 errx(1, "usage: --fido-mutate=<flag>");
83
84 if (strcmp(f, "seed") == 0)
85 *mutate_flags |= MUTATE_SEED;
86 else if (strcmp(f, "param") == 0)
87 *mutate_flags |= MUTATE_PARAM;
88 else if (strcmp(f, "wiredata") == 0)
89 *mutate_flags |= MUTATE_WIREDATA;
90 else
91 errx(1, "--fido-mutate: unknown flag '%s'", f);
92}
93
94int
95LLVMFuzzerInitialize(int *argc, char ***argv)
96{
97 unsigned int mutate_flags = 0;
98
99 for (int i = 0; i < *argc; i++)
100 if (strcmp((*argv)[i], "--fido-debug") == 0) {
101 debug = 1;
102 } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
103 exit(save_seed((*argv)[i]));
104 } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
105 parse_mutate_flags((*argv)[i], &mutate_flags);
106 }
107
108 if (mutate_flags)
109 flags = mutate_flags;
110
111 return 0;
112}
113
114int
115LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
116{
117 struct param *p;
118
119 if (++test_total % 100000 == 0 && debug) {
120 double r = (double)test_fail/(double)test_total * 100.0;
121 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
122 test_fail, test_total, r);
123 }
124
125 if (size > 4096 || (p = unpack(data, size)) == NULL)
126 test_fail++;
127 else {
128 test(p);
129 free(p);
130 }
131
132 return 0;
133}
134
135size_t
136LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
137 unsigned int seed) NO_MSAN
138{
139 struct param *p;
140 uint8_t blob[4096];
141 size_t blob_len;
142
143 memset(&p, 0, sizeof(p));
144
145#ifdef WITH_MSAN
146 __msan_unpoison(data, maxsize);
147#endif
148
149 if (++mutate_total % 100000 == 0 && debug) {
150 double r = (double)mutate_fail/(double)mutate_total * 100.0;
151 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
152 mutate_fail, mutate_total, r);
153 }
154
155 if ((p = unpack(data, size)) == NULL) {
156 mutate_fail++;
157 return pack_dummy(data, maxsize);
158 }
159
160 mutate(p, seed, flags);
161
162 if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
163 blob_len > sizeof(blob) || blob_len > maxsize) {
164 mutate_fail++;
165 free(p);
166 return 0;
167 }
168
169 free(p);
170
171 memcpy(data, blob, blob_len);
172
173 return blob_len;
174}