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