Home | History | Annotate | Line # | Download | only in fuzz
      1 /*
      2  * Copyright (c) 2020-2021 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 <stdint.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <stdio.h>
     13 
     14 #include "../openbsd-compat/openbsd-compat.h"
     15 #include "mutator_aux.h"
     16 #include "dummy.h"
     17 
     18 extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *);
     19 extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *);
     20 extern void set_udev_parameters(const char *, const struct blob *);
     21 
     22 struct param {
     23 	int seed;
     24 	char uevent[MAXSTR];
     25 	struct blob report_descriptor;
     26 	struct blob netlink_wiredata;
     27 };
     28 
     29 /*
     30  * Sample HID report descriptor from the FIDO HID interface of a YubiKey 5.
     31  */
     32 static const uint8_t dummy_report_descriptor[] = {
     33 	0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09,
     34 	0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08,
     35 	0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00,
     36 	0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91,
     37 	0x02, 0xc0
     38 };
     39 
     40 /*
     41  * Sample uevent file from a Yubico Security Key.
     42  */
     43 static const char dummy_uevent[] =
     44 	"DRIVER=hid-generic\n"
     45 	"HID_ID=0003:00001050:00000120\n"
     46 	"HID_NAME=Yubico Security Key by Yubico\n"
     47 	"HID_PHYS=usb-0000:00:14.0-3/input0\n"
     48 	"HID_UNIQ=\n"
     49 	"MODALIAS=hid:b0003g0001v00001050p00000120\n";
     50 
     51 struct param *
     52 unpack(const uint8_t *ptr, size_t len)
     53 {
     54 	cbor_item_t *item = NULL, **v;
     55 	struct cbor_load_result cbor;
     56 	struct param *p;
     57 	int ok = -1;
     58 
     59 	if ((p = calloc(1, sizeof(*p))) == NULL ||
     60 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
     61 	    cbor.read != len ||
     62 	    cbor_isa_array(item) == false ||
     63 	    cbor_array_is_definite(item) == false ||
     64 	    cbor_array_size(item) != 4 ||
     65 	    (v = cbor_array_handle(item)) == NULL)
     66 		goto fail;
     67 
     68 	if (unpack_int(v[0], &p->seed) < 0 ||
     69 	    unpack_string(v[1], p->uevent) < 0 ||
     70 	    unpack_blob(v[2], &p->report_descriptor) < 0 ||
     71 	    unpack_blob(v[3], &p->netlink_wiredata) < 0)
     72 		goto fail;
     73 
     74 	ok = 0;
     75 fail:
     76 	if (ok < 0) {
     77 		free(p);
     78 		p = NULL;
     79 	}
     80 
     81 	if (item)
     82 		cbor_decref(&item);
     83 
     84 	return p;
     85 }
     86 
     87 size_t
     88 pack(uint8_t *ptr, size_t len, const struct param *p)
     89 {
     90 	cbor_item_t *argv[4], *array = NULL;
     91 	size_t cbor_alloc_len, cbor_len = 0;
     92 	unsigned char *cbor = NULL;
     93 
     94 	memset(argv, 0, sizeof(argv));
     95 
     96 	if ((array = cbor_new_definite_array(4)) == NULL ||
     97 	    (argv[0] = pack_int(p->seed)) == NULL ||
     98 	    (argv[1] = pack_string(p->uevent)) == NULL ||
     99 	    (argv[2] = pack_blob(&p->report_descriptor)) == NULL ||
    100 	    (argv[3] = pack_blob(&p->netlink_wiredata)) == NULL)
    101 		goto fail;
    102 
    103 	for (size_t i = 0; i < 4; i++)
    104 		if (cbor_array_push(array, argv[i]) == false)
    105 			goto fail;
    106 
    107 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
    108 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
    109 		cbor_len = 0;
    110 		goto fail;
    111 	}
    112 
    113 	memcpy(ptr, cbor, cbor_len);
    114 fail:
    115 	for (size_t i = 0; i < 4; i++)
    116 		if (argv[i])
    117 			cbor_decref(&argv[i]);
    118 
    119 	if (array)
    120 		cbor_decref(&array);
    121 
    122 	free(cbor);
    123 
    124 	return cbor_len;
    125 }
    126 
    127 size_t
    128 pack_dummy(uint8_t *ptr, size_t len)
    129 {
    130 	struct param dummy;
    131 	uint8_t	blob[MAXCORPUS];
    132 	size_t blob_len;
    133 
    134 	memset(&dummy, 0, sizeof(dummy));
    135 
    136 	dummy.report_descriptor.len = sizeof(dummy_report_descriptor);
    137 	strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent));
    138 	memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor,
    139 	    dummy.report_descriptor.len);
    140 	dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata);
    141 	memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata,
    142 	    dummy.netlink_wiredata.len);
    143 
    144 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
    145 	if (blob_len > len)
    146 		blob_len = len;
    147 
    148 	memcpy(ptr, blob, blob_len);
    149 
    150 	return blob_len;
    151 }
    152 
    153 static void
    154 get_usage(const struct param *p)
    155 {
    156 	uint32_t usage_page = 0;
    157 
    158 	fido_hid_get_usage(p->report_descriptor.body, p->report_descriptor.len,
    159 	    &usage_page);
    160 	consume(&usage_page, sizeof(usage_page));
    161 }
    162 
    163 static void
    164 get_report_len(const struct param *p)
    165 {
    166 	size_t report_in_len = 0;
    167 	size_t report_out_len = 0;
    168 
    169 	fido_hid_get_report_len(p->report_descriptor.body,
    170 	    p->report_descriptor.len, &report_in_len, &report_out_len);
    171 	consume(&report_in_len, sizeof(report_in_len));
    172 	consume(&report_out_len, sizeof(report_out_len));
    173 }
    174 
    175 static void
    176 manifest(const struct param *p)
    177 {
    178 	size_t ndevs, nfound;
    179 	fido_dev_info_t *devlist = NULL, *devlist_set = NULL;
    180 	int16_t vendor_id, product_id;
    181 	fido_dev_io_t io;
    182 	fido_dev_transport_t t;
    183 
    184 	memset(&io, 0, sizeof(io));
    185 	memset(&t, 0, sizeof(t));
    186 	set_netlink_io_functions(fd_read, fd_write);
    187 	set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len);
    188 	set_udev_parameters(p->uevent, &p->report_descriptor);
    189 
    190 	ndevs = uniform_random(64);
    191 	if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
    192 	    (devlist_set = fido_dev_info_new(1)) == NULL ||
    193 	    fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK)
    194 		goto out;
    195 	for (size_t i = 0; i < nfound; i++) {
    196 		const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
    197 		consume_str(fido_dev_info_path(di));
    198 		consume_str(fido_dev_info_manufacturer_string(di));
    199 		consume_str(fido_dev_info_product_string(di));
    200 		vendor_id = fido_dev_info_vendor(di);
    201 		product_id = fido_dev_info_product(di);
    202 		consume(&vendor_id, sizeof(vendor_id));
    203 		consume(&product_id, sizeof(product_id));
    204 		fido_dev_info_set(devlist_set, 0, fido_dev_info_path(di),
    205 		    fido_dev_info_manufacturer_string(di),
    206 		    fido_dev_info_product_string(di), &io, &t);
    207 	}
    208 out:
    209 	fido_dev_info_free(&devlist, ndevs);
    210 	fido_dev_info_free(&devlist_set, 1);
    211 }
    212 
    213 void
    214 test(const struct param *p)
    215 {
    216 	prng_init((unsigned int)p->seed);
    217 	fuzz_clock_reset();
    218 	fido_init(FIDO_DEBUG);
    219 	fido_set_log_handler(consume_str);
    220 
    221 	get_usage(p);
    222 	get_report_len(p);
    223 	manifest(p);
    224 }
    225 
    226 void
    227 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
    228 {
    229 	if (flags & MUTATE_SEED)
    230 		p->seed = (int)seed;
    231 
    232 	if (flags & MUTATE_PARAM) {
    233 		mutate_blob(&p->report_descriptor);
    234 		mutate_string(p->uevent);
    235 	}
    236 
    237 	if (flags & MUTATE_WIREDATA)
    238 		mutate_blob(&p->netlink_wiredata);
    239 }
    240