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 18 static bool debug; 19 static unsigned int flags = MUTATE_ALL; 20 static unsigned long long test_fail; 21 static unsigned long long test_total; 22 static unsigned long long mutate_fail; 23 static unsigned long long mutate_total; 24 25 int LLVMFuzzerInitialize(int *, char ***); 26 int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 27 size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 28 29 static int 30 save_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; 67 fail: 68 if (fd != -1) 69 close(fd); 70 free(buf); 71 free(p); 72 73 return status; 74 } 75 76 static void 77 parse_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 94 int 95 LLVMFuzzerInitialize(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 114 int 115 LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 116 { 117 struct param *p; 118 119 if (size > 4096) 120 return 0; 121 122 if (++test_total % 100000 == 0 && debug) { 123 double r = (double)test_fail/(double)test_total * 100.0; 124 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, 125 test_fail, test_total, r); 126 } 127 128 if ((p = unpack(data, size)) == NULL) 129 test_fail++; 130 else { 131 test(p); 132 free(p); 133 } 134 135 return 0; 136 } 137 138 size_t 139 LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 140 unsigned int seed) NO_MSAN 141 { 142 struct param *p; 143 uint8_t blob[4096]; 144 size_t blob_len; 145 146 memset(&p, 0, sizeof(p)); 147 148 #ifdef WITH_MSAN 149 __msan_unpoison(data, maxsize); 150 #endif 151 152 if (++mutate_total % 100000 == 0 && debug) { 153 double r = (double)mutate_fail/(double)mutate_total * 100.0; 154 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, 155 mutate_fail, mutate_total, r); 156 } 157 158 if ((p = unpack(data, size)) == NULL) { 159 mutate_fail++; 160 return pack_dummy(data, maxsize); 161 } 162 163 mutate(p, seed, flags); 164 165 if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || 166 blob_len > sizeof(blob) || blob_len > maxsize) { 167 mutate_fail++; 168 free(p); 169 return 0; 170 } 171 172 free(p); 173 174 memcpy(data, blob, blob_len); 175 176 return blob_len; 177 } 178