10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
8*2ccfa855SEd Maste #include <openssl/sha.h>
9*2ccfa855SEd Maste
100afa8e06SEd Maste #include <err.h>
110afa8e06SEd Maste #include <fcntl.h>
120afa8e06SEd Maste #include <stdbool.h>
130afa8e06SEd Maste #include <stdint.h>
140afa8e06SEd Maste #include <stdio.h>
150afa8e06SEd Maste #include <stdlib.h>
160afa8e06SEd Maste #include <string.h>
170afa8e06SEd Maste #include <unistd.h>
180afa8e06SEd Maste
190afa8e06SEd Maste #include "mutator_aux.h"
200afa8e06SEd Maste
21*2ccfa855SEd Maste extern int fuzz_save_corpus;
22*2ccfa855SEd Maste
230afa8e06SEd Maste static bool debug;
240afa8e06SEd Maste static unsigned int flags = MUTATE_ALL;
250afa8e06SEd Maste static unsigned long long test_fail;
260afa8e06SEd Maste static unsigned long long test_total;
270afa8e06SEd Maste static unsigned long long mutate_fail;
280afa8e06SEd Maste static unsigned long long mutate_total;
290afa8e06SEd Maste
300afa8e06SEd Maste int LLVMFuzzerInitialize(int *, char ***);
310afa8e06SEd Maste int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
320afa8e06SEd Maste size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
330afa8e06SEd Maste
340afa8e06SEd Maste static int
save_seed(const char * opt)350afa8e06SEd Maste save_seed(const char *opt)
360afa8e06SEd Maste {
370afa8e06SEd Maste const char *path;
380afa8e06SEd Maste int fd = -1, status = 1;
390afa8e06SEd Maste void *buf = NULL;
40*2ccfa855SEd Maste const size_t buflen = MAXCORPUS;
410afa8e06SEd Maste size_t n;
420afa8e06SEd Maste struct param *p = NULL;
430afa8e06SEd Maste
440afa8e06SEd Maste if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
450afa8e06SEd Maste warnx("usage: --fido-save-seed=<path>");
460afa8e06SEd Maste goto fail;
470afa8e06SEd Maste }
480afa8e06SEd Maste
490afa8e06SEd Maste if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
500afa8e06SEd Maste warn("open %s", path);
510afa8e06SEd Maste goto fail;
520afa8e06SEd Maste }
530afa8e06SEd Maste
540afa8e06SEd Maste if ((buf = malloc(buflen)) == NULL) {
550afa8e06SEd Maste warn("malloc");
560afa8e06SEd Maste goto fail;
570afa8e06SEd Maste }
580afa8e06SEd Maste
590afa8e06SEd Maste n = pack_dummy(buf, buflen);
600afa8e06SEd Maste
610afa8e06SEd Maste if ((p = unpack(buf, n)) == NULL) {
620afa8e06SEd Maste warnx("unpack");
630afa8e06SEd Maste goto fail;
640afa8e06SEd Maste }
650afa8e06SEd Maste
660afa8e06SEd Maste if (write(fd, buf, n) != (ssize_t)n) {
670afa8e06SEd Maste warn("write %s", path);
680afa8e06SEd Maste goto fail;
690afa8e06SEd Maste }
700afa8e06SEd Maste
710afa8e06SEd Maste status = 0;
720afa8e06SEd Maste fail:
730afa8e06SEd Maste if (fd != -1)
740afa8e06SEd Maste close(fd);
750afa8e06SEd Maste free(buf);
760afa8e06SEd Maste free(p);
770afa8e06SEd Maste
780afa8e06SEd Maste return status;
790afa8e06SEd Maste }
800afa8e06SEd Maste
81*2ccfa855SEd Maste static int
save_corpus(const struct param * p)82*2ccfa855SEd Maste save_corpus(const struct param *p)
83*2ccfa855SEd Maste {
84*2ccfa855SEd Maste uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH];
85*2ccfa855SEd Maste size_t blob_len;
86*2ccfa855SEd Maste char path[PATH_MAX];
87*2ccfa855SEd Maste int r, fd;
88*2ccfa855SEd Maste
89*2ccfa855SEd Maste if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
90*2ccfa855SEd Maste blob_len > sizeof(blob)) {
91*2ccfa855SEd Maste warnx("pack");
92*2ccfa855SEd Maste return -1;
93*2ccfa855SEd Maste }
94*2ccfa855SEd Maste
95*2ccfa855SEd Maste if (SHA256(blob, blob_len, dgst) != dgst) {
96*2ccfa855SEd Maste warnx("sha256");
97*2ccfa855SEd Maste return -1;
98*2ccfa855SEd Maste }
99*2ccfa855SEd Maste
100*2ccfa855SEd Maste if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x"
101*2ccfa855SEd Maste "%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4],
102*2ccfa855SEd Maste dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) {
103*2ccfa855SEd Maste warnx("snprintf");
104*2ccfa855SEd Maste return -1;
105*2ccfa855SEd Maste }
106*2ccfa855SEd Maste
107*2ccfa855SEd Maste if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
108*2ccfa855SEd Maste warn("open %s", path);
109*2ccfa855SEd Maste return -1;
110*2ccfa855SEd Maste }
111*2ccfa855SEd Maste
112*2ccfa855SEd Maste if (write(fd, blob, blob_len) != (ssize_t)blob_len) {
113*2ccfa855SEd Maste warn("write");
114*2ccfa855SEd Maste r = -1;
115*2ccfa855SEd Maste } else {
116*2ccfa855SEd Maste warnx("wrote %s", path);
117*2ccfa855SEd Maste r = 0;
118*2ccfa855SEd Maste }
119*2ccfa855SEd Maste
120*2ccfa855SEd Maste close(fd);
121*2ccfa855SEd Maste
122*2ccfa855SEd Maste return r;
123*2ccfa855SEd Maste }
124*2ccfa855SEd Maste
1250afa8e06SEd Maste static void
parse_mutate_flags(const char * opt,unsigned int * mutate_flags)1260afa8e06SEd Maste parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
1270afa8e06SEd Maste {
1280afa8e06SEd Maste const char *f;
1290afa8e06SEd Maste
1300afa8e06SEd Maste if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
1310afa8e06SEd Maste errx(1, "usage: --fido-mutate=<flag>");
1320afa8e06SEd Maste
1330afa8e06SEd Maste if (strcmp(f, "seed") == 0)
1340afa8e06SEd Maste *mutate_flags |= MUTATE_SEED;
1350afa8e06SEd Maste else if (strcmp(f, "param") == 0)
1360afa8e06SEd Maste *mutate_flags |= MUTATE_PARAM;
1370afa8e06SEd Maste else if (strcmp(f, "wiredata") == 0)
1380afa8e06SEd Maste *mutate_flags |= MUTATE_WIREDATA;
1390afa8e06SEd Maste else
1400afa8e06SEd Maste errx(1, "--fido-mutate: unknown flag '%s'", f);
1410afa8e06SEd Maste }
1420afa8e06SEd Maste
1430afa8e06SEd Maste int
LLVMFuzzerInitialize(int * argc,char *** argv)1440afa8e06SEd Maste LLVMFuzzerInitialize(int *argc, char ***argv)
1450afa8e06SEd Maste {
1460afa8e06SEd Maste unsigned int mutate_flags = 0;
1470afa8e06SEd Maste
1480afa8e06SEd Maste for (int i = 0; i < *argc; i++)
1490afa8e06SEd Maste if (strcmp((*argv)[i], "--fido-debug") == 0) {
1500afa8e06SEd Maste debug = 1;
1510afa8e06SEd Maste } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
1520afa8e06SEd Maste exit(save_seed((*argv)[i]));
1530afa8e06SEd Maste } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
1540afa8e06SEd Maste parse_mutate_flags((*argv)[i], &mutate_flags);
1550afa8e06SEd Maste }
1560afa8e06SEd Maste
1570afa8e06SEd Maste if (mutate_flags)
1580afa8e06SEd Maste flags = mutate_flags;
1590afa8e06SEd Maste
1600afa8e06SEd Maste return 0;
1610afa8e06SEd Maste }
1620afa8e06SEd Maste
1630afa8e06SEd Maste int
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)1640afa8e06SEd Maste LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
1650afa8e06SEd Maste {
1660afa8e06SEd Maste struct param *p;
1670afa8e06SEd Maste
168*2ccfa855SEd Maste if (size > MAXCORPUS)
1690afa8e06SEd Maste return 0;
1700afa8e06SEd Maste
1710afa8e06SEd Maste if (++test_total % 100000 == 0 && debug) {
1720afa8e06SEd Maste double r = (double)test_fail/(double)test_total * 100.0;
1730afa8e06SEd Maste fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
1740afa8e06SEd Maste test_fail, test_total, r);
1750afa8e06SEd Maste }
1760afa8e06SEd Maste
1770afa8e06SEd Maste if ((p = unpack(data, size)) == NULL)
1780afa8e06SEd Maste test_fail++;
1790afa8e06SEd Maste else {
180*2ccfa855SEd Maste fuzz_save_corpus = 0;
1810afa8e06SEd Maste test(p);
182*2ccfa855SEd Maste if (fuzz_save_corpus && save_corpus(p) < 0)
183*2ccfa855SEd Maste fprintf(stderr, "%s: failed to save corpus\n",
184*2ccfa855SEd Maste __func__);
1850afa8e06SEd Maste free(p);
1860afa8e06SEd Maste }
1870afa8e06SEd Maste
1880afa8e06SEd Maste return 0;
1890afa8e06SEd Maste }
1900afa8e06SEd Maste
1910afa8e06SEd Maste size_t
LLVMFuzzerCustomMutator(uint8_t * data,size_t size,size_t maxsize,unsigned int seed)1920afa8e06SEd Maste LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
1930afa8e06SEd Maste unsigned int seed) NO_MSAN
1940afa8e06SEd Maste {
1950afa8e06SEd Maste struct param *p;
196*2ccfa855SEd Maste uint8_t blob[MAXCORPUS];
1970afa8e06SEd Maste size_t blob_len;
1980afa8e06SEd Maste
1990afa8e06SEd Maste memset(&p, 0, sizeof(p));
2000afa8e06SEd Maste
2010afa8e06SEd Maste #ifdef WITH_MSAN
2020afa8e06SEd Maste __msan_unpoison(data, maxsize);
2030afa8e06SEd Maste #endif
2040afa8e06SEd Maste
2050afa8e06SEd Maste if (++mutate_total % 100000 == 0 && debug) {
2060afa8e06SEd Maste double r = (double)mutate_fail/(double)mutate_total * 100.0;
2070afa8e06SEd Maste fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
2080afa8e06SEd Maste mutate_fail, mutate_total, r);
2090afa8e06SEd Maste }
2100afa8e06SEd Maste
2110afa8e06SEd Maste if ((p = unpack(data, size)) == NULL) {
2120afa8e06SEd Maste mutate_fail++;
2130afa8e06SEd Maste return pack_dummy(data, maxsize);
2140afa8e06SEd Maste }
2150afa8e06SEd Maste
2160afa8e06SEd Maste mutate(p, seed, flags);
2170afa8e06SEd Maste
2180afa8e06SEd Maste if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
2190afa8e06SEd Maste blob_len > sizeof(blob) || blob_len > maxsize) {
2200afa8e06SEd Maste mutate_fail++;
2210afa8e06SEd Maste free(p);
2220afa8e06SEd Maste return 0;
2230afa8e06SEd Maste }
2240afa8e06SEd Maste
2250afa8e06SEd Maste free(p);
2260afa8e06SEd Maste
2270afa8e06SEd Maste memcpy(data, blob, blob_len);
2280afa8e06SEd Maste
2290afa8e06SEd Maste return blob_len;
2300afa8e06SEd Maste }
231