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 <assert.h> 8 #include <cbor.h> 9 #include <errno.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include "mutator_aux.h" 17 18 #define HID_DEV_HANDLE 0x68696421 19 #define NFC_DEV_HANDLE 0x6e666321 20 21 int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); 22 int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); 23 size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); 24 25 static const uint8_t *wire_data_ptr = NULL; 26 static size_t wire_data_len = 0; 27 28 void 29 consume(const void *body, size_t len) 30 { 31 const volatile uint8_t *ptr = body; 32 volatile uint8_t x = 0; 33 34 #ifdef WITH_MSAN 35 __msan_check_mem_is_initialized(body, len); 36 #endif 37 38 while (len--) 39 x ^= *ptr++; 40 } 41 42 void 43 consume_str(const char *str) 44 { 45 if (str != NULL) 46 consume(str, strlen(str) + 1); 47 } 48 49 int 50 unpack_int(cbor_item_t *item, int *v) 51 { 52 if (cbor_is_int(item) == false || 53 cbor_int_get_width(item) != CBOR_INT_64) 54 return -1; 55 56 if (cbor_isa_uint(item)) 57 *v = (int)cbor_get_uint64(item); 58 else 59 *v = (int)(-cbor_get_uint64(item) - 1); 60 61 return 0; 62 } 63 64 int 65 unpack_string(cbor_item_t *item, char *v) 66 { 67 size_t len; 68 69 if (cbor_isa_bytestring(item) == false || 70 (len = cbor_bytestring_length(item)) >= MAXSTR) 71 return -1; 72 73 memcpy(v, cbor_bytestring_handle(item), len); 74 v[len] = '\0'; 75 76 return 0; 77 } 78 79 int 80 unpack_byte(cbor_item_t *item, uint8_t *v) 81 { 82 if (cbor_isa_uint(item) == false || 83 cbor_int_get_width(item) != CBOR_INT_8) 84 return -1; 85 86 *v = cbor_get_uint8(item); 87 88 return 0; 89 } 90 91 int 92 unpack_blob(cbor_item_t *item, struct blob *v) 93 { 94 if (cbor_isa_bytestring(item) == false || 95 (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) 96 return -1; 97 98 memcpy(v->body, cbor_bytestring_handle(item), v->len); 99 100 return 0; 101 } 102 103 cbor_item_t * 104 pack_int(int v) NO_MSAN 105 { 106 if (v < 0) 107 return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); 108 else 109 return cbor_build_uint64((uint64_t)v); 110 } 111 112 cbor_item_t * 113 pack_string(const char *v) NO_MSAN 114 { 115 if (strlen(v) >= MAXSTR) 116 return NULL; 117 118 return cbor_build_bytestring((const unsigned char *)v, strlen(v)); 119 } 120 121 cbor_item_t * 122 pack_byte(uint8_t v) NO_MSAN 123 { 124 return cbor_build_uint8(v); 125 } 126 127 cbor_item_t * 128 pack_blob(const struct blob *v) NO_MSAN 129 { 130 return cbor_build_bytestring(v->body, v->len); 131 } 132 133 void 134 mutate_byte(uint8_t *b) 135 { 136 LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); 137 } 138 139 void 140 mutate_int(int *i) 141 { 142 LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); 143 } 144 145 void 146 mutate_blob(struct blob *blob) 147 { 148 blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, 149 sizeof(blob->body)); 150 } 151 152 void 153 mutate_string(char *s) 154 { 155 size_t n; 156 157 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); 158 s[n] = '\0'; 159 } 160 161 /* XXX should fail, but doesn't */ 162 static int 163 buf_read(unsigned char *ptr, size_t len, int ms) 164 { 165 size_t n; 166 167 (void)ms; 168 169 if (wire_data_len < len) 170 n = wire_data_len; 171 else 172 n = len; 173 174 memcpy(ptr, wire_data_ptr, n); 175 176 wire_data_ptr += n; 177 wire_data_len -= n; 178 179 return (int)n; 180 } 181 182 static int 183 buf_write(const unsigned char *ptr, size_t len) 184 { 185 consume(ptr, len); 186 187 if (uniform_random(400) < 1) { 188 errno = EIO; 189 return -1; 190 } 191 192 return (int)len; 193 } 194 195 static void * 196 hid_open(const char *path) 197 { 198 (void)path; 199 200 return (void *)HID_DEV_HANDLE; 201 } 202 203 static void 204 hid_close(void *handle) 205 { 206 assert(handle == (void *)HID_DEV_HANDLE); 207 } 208 209 static int 210 hid_read(void *handle, unsigned char *ptr, size_t len, int ms) 211 { 212 assert(handle == (void *)HID_DEV_HANDLE); 213 assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); 214 215 return buf_read(ptr, len, ms); 216 } 217 218 static int 219 hid_write(void *handle, const unsigned char *ptr, size_t len) 220 { 221 assert(handle == (void *)HID_DEV_HANDLE); 222 assert(len >= CTAP_MIN_REPORT_LEN + 1 && 223 len <= CTAP_MAX_REPORT_LEN + 1); 224 225 return buf_write(ptr, len); 226 } 227 228 static void * 229 nfc_open(const char *path) 230 { 231 (void)path; 232 233 return (void *)NFC_DEV_HANDLE; 234 } 235 236 static void 237 nfc_close(void *handle) 238 { 239 assert(handle == (void *)NFC_DEV_HANDLE); 240 } 241 242 static int 243 nfc_read(void *handle, unsigned char *ptr, size_t len, int ms) 244 { 245 assert(handle == (void *)NFC_DEV_HANDLE); 246 assert(len > 0 && len <= 256 + 2); 247 248 return buf_read(ptr, len, ms); 249 } 250 251 static int 252 nfc_write(void *handle, const unsigned char *ptr, size_t len) 253 { 254 assert(handle == (void *)NFC_DEV_HANDLE); 255 assert(len > 0 && len <= 256 + 2); 256 257 return buf_write(ptr, len); 258 } 259 260 ssize_t 261 fd_read(int fd, void *ptr, size_t len) 262 { 263 assert(fd != -1); 264 265 return buf_read(ptr, len, -1); 266 } 267 268 ssize_t 269 fd_write(int fd, const void *ptr, size_t len) 270 { 271 assert(fd != -1); 272 273 return buf_write(ptr, len); 274 } 275 276 fido_dev_t * 277 open_dev(int nfc) 278 { 279 fido_dev_t *dev; 280 fido_dev_io_t io; 281 fido_dev_transport_t t; 282 283 memset(&io, 0, sizeof(io)); 284 memset(&t, 0, sizeof(t)); 285 286 if ((dev = fido_dev_new()) == NULL) 287 return NULL; 288 289 if (nfc) { 290 io.open = nfc_open; 291 io.close = nfc_close; 292 io.read = nfc_read; 293 io.write = nfc_write; 294 } else { 295 io.open = hid_open; 296 io.close = hid_close; 297 io.read = hid_read; 298 io.write = hid_write; 299 } 300 301 if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) 302 goto fail; 303 304 if (nfc) { 305 t.rx = fido_nfc_rx; 306 t.tx = fido_nfc_tx; 307 if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK) 308 goto fail; 309 } 310 311 if (fido_dev_open(dev, "nodev") != FIDO_OK) 312 goto fail; 313 314 return dev; 315 fail: 316 fido_dev_free(&dev); 317 318 return NULL; 319 } 320 321 void 322 set_wire_data(const uint8_t *ptr, size_t len) 323 { 324 wire_data_ptr = ptr; 325 wire_data_len = len; 326 } 327