mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 12:54:27 +00:00
2ccfa855b2
Some highlights from NEWS entries: ** Improved OpenSSL 3.0 compatibility. ** Support for hidraw(4) on FreeBSD; gh#597. ** Improved support for FIDO 2.1 authenticators. PR: 273596 Relnotes: Yes Sponsored by: The FreeBSD Foundation
231 lines
4.6 KiB
C
231 lines
4.6 KiB
C
/*
|
|
* Copyright (c) 2019-2022 Yubico AB. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style
|
|
* license that can be found in the LICENSE file.
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <openssl/sha.h>
|
|
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "mutator_aux.h"
|
|
|
|
extern int fuzz_save_corpus;
|
|
|
|
static bool debug;
|
|
static unsigned int flags = MUTATE_ALL;
|
|
static unsigned long long test_fail;
|
|
static unsigned long long test_total;
|
|
static unsigned long long mutate_fail;
|
|
static unsigned long long mutate_total;
|
|
|
|
int LLVMFuzzerInitialize(int *, char ***);
|
|
int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
|
|
size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
|
|
|
|
static int
|
|
save_seed(const char *opt)
|
|
{
|
|
const char *path;
|
|
int fd = -1, status = 1;
|
|
void *buf = NULL;
|
|
const size_t buflen = MAXCORPUS;
|
|
size_t n;
|
|
struct param *p = NULL;
|
|
|
|
if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
|
|
warnx("usage: --fido-save-seed=<path>");
|
|
goto fail;
|
|
}
|
|
|
|
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
|
|
warn("open %s", path);
|
|
goto fail;
|
|
}
|
|
|
|
if ((buf = malloc(buflen)) == NULL) {
|
|
warn("malloc");
|
|
goto fail;
|
|
}
|
|
|
|
n = pack_dummy(buf, buflen);
|
|
|
|
if ((p = unpack(buf, n)) == NULL) {
|
|
warnx("unpack");
|
|
goto fail;
|
|
}
|
|
|
|
if (write(fd, buf, n) != (ssize_t)n) {
|
|
warn("write %s", path);
|
|
goto fail;
|
|
}
|
|
|
|
status = 0;
|
|
fail:
|
|
if (fd != -1)
|
|
close(fd);
|
|
free(buf);
|
|
free(p);
|
|
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
save_corpus(const struct param *p)
|
|
{
|
|
uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH];
|
|
size_t blob_len;
|
|
char path[PATH_MAX];
|
|
int r, fd;
|
|
|
|
if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
|
|
blob_len > sizeof(blob)) {
|
|
warnx("pack");
|
|
return -1;
|
|
}
|
|
|
|
if (SHA256(blob, blob_len, dgst) != dgst) {
|
|
warnx("sha256");
|
|
return -1;
|
|
}
|
|
|
|
if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x"
|
|
"%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4],
|
|
dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) {
|
|
warnx("snprintf");
|
|
return -1;
|
|
}
|
|
|
|
if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
|
|
warn("open %s", path);
|
|
return -1;
|
|
}
|
|
|
|
if (write(fd, blob, blob_len) != (ssize_t)blob_len) {
|
|
warn("write");
|
|
r = -1;
|
|
} else {
|
|
warnx("wrote %s", path);
|
|
r = 0;
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void
|
|
parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
|
|
{
|
|
const char *f;
|
|
|
|
if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
|
|
errx(1, "usage: --fido-mutate=<flag>");
|
|
|
|
if (strcmp(f, "seed") == 0)
|
|
*mutate_flags |= MUTATE_SEED;
|
|
else if (strcmp(f, "param") == 0)
|
|
*mutate_flags |= MUTATE_PARAM;
|
|
else if (strcmp(f, "wiredata") == 0)
|
|
*mutate_flags |= MUTATE_WIREDATA;
|
|
else
|
|
errx(1, "--fido-mutate: unknown flag '%s'", f);
|
|
}
|
|
|
|
int
|
|
LLVMFuzzerInitialize(int *argc, char ***argv)
|
|
{
|
|
unsigned int mutate_flags = 0;
|
|
|
|
for (int i = 0; i < *argc; i++)
|
|
if (strcmp((*argv)[i], "--fido-debug") == 0) {
|
|
debug = 1;
|
|
} else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
|
|
exit(save_seed((*argv)[i]));
|
|
} else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
|
|
parse_mutate_flags((*argv)[i], &mutate_flags);
|
|
}
|
|
|
|
if (mutate_flags)
|
|
flags = mutate_flags;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
|
{
|
|
struct param *p;
|
|
|
|
if (size > MAXCORPUS)
|
|
return 0;
|
|
|
|
if (++test_total % 100000 == 0 && debug) {
|
|
double r = (double)test_fail/(double)test_total * 100.0;
|
|
fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
|
|
test_fail, test_total, r);
|
|
}
|
|
|
|
if ((p = unpack(data, size)) == NULL)
|
|
test_fail++;
|
|
else {
|
|
fuzz_save_corpus = 0;
|
|
test(p);
|
|
if (fuzz_save_corpus && save_corpus(p) < 0)
|
|
fprintf(stderr, "%s: failed to save corpus\n",
|
|
__func__);
|
|
free(p);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
size_t
|
|
LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
|
|
unsigned int seed) NO_MSAN
|
|
{
|
|
struct param *p;
|
|
uint8_t blob[MAXCORPUS];
|
|
size_t blob_len;
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
#ifdef WITH_MSAN
|
|
__msan_unpoison(data, maxsize);
|
|
#endif
|
|
|
|
if (++mutate_total % 100000 == 0 && debug) {
|
|
double r = (double)mutate_fail/(double)mutate_total * 100.0;
|
|
fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
|
|
mutate_fail, mutate_total, r);
|
|
}
|
|
|
|
if ((p = unpack(data, size)) == NULL) {
|
|
mutate_fail++;
|
|
return pack_dummy(data, maxsize);
|
|
}
|
|
|
|
mutate(p, seed, flags);
|
|
|
|
if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
|
|
blob_len > sizeof(blob) || blob_len > maxsize) {
|
|
mutate_fail++;
|
|
free(p);
|
|
return 0;
|
|
}
|
|
|
|
free(p);
|
|
|
|
memcpy(data, blob, blob_len);
|
|
|
|
return blob_len;
|
|
}
|