Path: blob/main/contrib/libfido2/fuzz/libfuzzer.c
104817 views
/*1* Copyright (c) 2019-2022 Yubico AB. All rights reserved.2* Use of this source code is governed by a BSD-style3* license that can be found in the LICENSE file.4* SPDX-License-Identifier: BSD-2-Clause5*/67#include <openssl/sha.h>89#include <err.h>10#include <fcntl.h>11#include <stdbool.h>12#include <stdint.h>13#include <stdio.h>14#include <stdlib.h>15#include <string.h>16#include <unistd.h>1718#include "mutator_aux.h"1920extern int fuzz_save_corpus;2122static bool debug;23static unsigned int flags = MUTATE_ALL;24static unsigned long long test_fail;25static unsigned long long test_total;26static unsigned long long mutate_fail;27static unsigned long long mutate_total;2829int LLVMFuzzerInitialize(int *, char ***);30int LLVMFuzzerTestOneInput(const uint8_t *, size_t);31size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);3233static int34save_seed(const char *opt)35{36const char *path;37int fd = -1, status = 1;38void *buf = NULL;39const size_t buflen = MAXCORPUS;40size_t n;41struct param *p = NULL;4243if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {44warnx("usage: --fido-save-seed=<path>");45goto fail;46}4748if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {49warn("open %s", path);50goto fail;51}5253if ((buf = malloc(buflen)) == NULL) {54warn("malloc");55goto fail;56}5758n = pack_dummy(buf, buflen);5960if ((p = unpack(buf, n)) == NULL) {61warnx("unpack");62goto fail;63}6465if (write(fd, buf, n) != (ssize_t)n) {66warn("write %s", path);67goto fail;68}6970status = 0;71fail:72if (fd != -1)73close(fd);74free(buf);75free(p);7677return status;78}7980static int81save_corpus(const struct param *p)82{83uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH];84size_t blob_len;85char path[PATH_MAX];86int r, fd;8788if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||89blob_len > sizeof(blob)) {90warnx("pack");91return -1;92}9394if (SHA256(blob, blob_len, dgst) != dgst) {95warnx("sha256");96return -1;97}9899if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x"100"%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4],101dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) {102warnx("snprintf");103return -1;104}105106if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {107warn("open %s", path);108return -1;109}110111if (write(fd, blob, blob_len) != (ssize_t)blob_len) {112warn("write");113r = -1;114} else {115warnx("wrote %s", path);116r = 0;117}118119close(fd);120121return r;122}123124static void125parse_mutate_flags(const char *opt, unsigned int *mutate_flags)126{127const char *f;128129if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)130errx(1, "usage: --fido-mutate=<flag>");131132if (strcmp(f, "seed") == 0)133*mutate_flags |= MUTATE_SEED;134else if (strcmp(f, "param") == 0)135*mutate_flags |= MUTATE_PARAM;136else if (strcmp(f, "wiredata") == 0)137*mutate_flags |= MUTATE_WIREDATA;138else139errx(1, "--fido-mutate: unknown flag '%s'", f);140}141142int143LLVMFuzzerInitialize(int *argc, char ***argv)144{145unsigned int mutate_flags = 0;146147for (int i = 0; i < *argc; i++)148if (strcmp((*argv)[i], "--fido-debug") == 0) {149debug = 1;150} else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {151exit(save_seed((*argv)[i]));152} else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {153parse_mutate_flags((*argv)[i], &mutate_flags);154}155156if (mutate_flags)157flags = mutate_flags;158159return 0;160}161162int163LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)164{165struct param *p;166167if (size > MAXCORPUS)168return 0;169170if (++test_total % 100000 == 0 && debug) {171double r = (double)test_fail/(double)test_total * 100.0;172fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,173test_fail, test_total, r);174}175176if ((p = unpack(data, size)) == NULL)177test_fail++;178else {179fuzz_save_corpus = 0;180test(p);181if (fuzz_save_corpus && save_corpus(p) < 0)182fprintf(stderr, "%s: failed to save corpus\n",183__func__);184free(p);185}186187return 0;188}189190size_t191LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,192unsigned int seed) NO_MSAN193{194struct param *p;195uint8_t blob[MAXCORPUS];196size_t blob_len;197198memset(&p, 0, sizeof(p));199200#ifdef WITH_MSAN201__msan_unpoison(data, maxsize);202#endif203204if (++mutate_total % 100000 == 0 && debug) {205double r = (double)mutate_fail/(double)mutate_total * 100.0;206fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,207mutate_fail, mutate_total, r);208}209210if ((p = unpack(data, size)) == NULL) {211mutate_fail++;212return pack_dummy(data, maxsize);213}214215mutate(p, seed, flags);216217if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||218blob_len > sizeof(blob) || blob_len > maxsize) {219mutate_fail++;220free(p);221return 0;222}223224free(p);225226memcpy(data, blob, blob_len);227228return blob_len;229}230231232