xref: /freebsd/contrib/libfido2/fuzz/libfuzzer.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
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