xref: /freebsd/contrib/libfido2/fuzz/fuzz_netlink.c (revision aa1a8ff2d6dbc51ef058f46f3db5a8bb77967145)
1 /*
2  * Copyright (c) 2020 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 struct param {
19 	int seed;
20 	int dev;
21 	struct blob wiredata;
22 };
23 
24 struct param *
25 unpack(const uint8_t *ptr, size_t len)
26 {
27 	cbor_item_t *item = NULL, **v;
28 	struct cbor_load_result cbor;
29 	struct param *p;
30 	int ok = -1;
31 
32 	if ((p = calloc(1, sizeof(*p))) == NULL ||
33 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
34 	    cbor.read != len ||
35 	    cbor_isa_array(item) == false ||
36 	    cbor_array_is_definite(item) == false ||
37 	    cbor_array_size(item) != 3 ||
38 	    (v = cbor_array_handle(item)) == NULL)
39 		goto fail;
40 
41 	if (unpack_int(v[0], &p->seed) < 0 ||
42 	    unpack_int(v[1], &p->dev) < 0 ||
43 	    unpack_blob(v[2], &p->wiredata) < 0)
44 		goto fail;
45 
46 	ok = 0;
47 fail:
48 	if (ok < 0) {
49 		free(p);
50 		p = NULL;
51 	}
52 
53 	if (item)
54 		cbor_decref(&item);
55 
56 	return p;
57 }
58 
59 size_t
60 pack(uint8_t *ptr, size_t len, const struct param *p)
61 {
62 	cbor_item_t *argv[3], *array = NULL;
63 	size_t cbor_alloc_len, cbor_len = 0;
64 	unsigned char *cbor = NULL;
65 
66 	memset(argv, 0, sizeof(argv));
67 
68 	if ((array = cbor_new_definite_array(3)) == NULL ||
69 	    (argv[0] = pack_int(p->seed)) == NULL ||
70 	    (argv[1] = pack_int(p->dev)) == NULL ||
71 	    (argv[2] = pack_blob(&p->wiredata)) == NULL)
72 		goto fail;
73 
74 	for (size_t i = 0; i < 3; i++)
75 		if (cbor_array_push(array, argv[i]) == false)
76 			goto fail;
77 
78 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
79 	    &cbor_alloc_len)) == 0 || cbor_len > len) {
80 		cbor_len = 0;
81 		goto fail;
82 	}
83 
84 	memcpy(ptr, cbor, cbor_len);
85 fail:
86 	for (size_t i = 0; i < 3; i++)
87 		if (argv[i])
88 			cbor_decref(&argv[i]);
89 
90 	if (array)
91 		cbor_decref(&array);
92 
93 	free(cbor);
94 
95 	return cbor_len;
96 }
97 
98 size_t
99 pack_dummy(uint8_t *ptr, size_t len)
100 {
101 	struct param dummy;
102 	uint8_t	blob[MAXCORPUS];
103 	size_t blob_len;
104 
105 	memset(&dummy, 0, sizeof(dummy));
106 
107 	dummy.wiredata.len = sizeof(dummy_netlink_wiredata);
108 	memcpy(&dummy.wiredata.body, &dummy_netlink_wiredata,
109 	    dummy.wiredata.len);
110 
111 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
112 
113 	if (blob_len > len) {
114 		memcpy(ptr, blob, len);
115 		return len;
116 	}
117 
118 	memcpy(ptr, blob, blob_len);
119 
120 	return blob_len;
121 }
122 
123 void
124 test(const struct param *p)
125 {
126 	fido_nl_t *nl;
127 	uint32_t target;
128 
129 	prng_init((unsigned int)p->seed);
130 	fuzz_clock_reset();
131 	fido_init(FIDO_DEBUG);
132 	fido_set_log_handler(consume_str);
133 
134 	set_netlink_io_functions(fd_read, fd_write);
135 	set_wire_data(p->wiredata.body, p->wiredata.len);
136 
137 	if ((nl = fido_nl_new()) == NULL)
138 		return;
139 
140 	consume(&nl->fd, sizeof(nl->fd));
141 	consume(&nl->nfc_type, sizeof(nl->nfc_type));
142 	consume(&nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp));
143 	consume(&nl->saddr, sizeof(nl->saddr));
144 
145 	fido_nl_power_nfc(nl, (uint32_t)p->dev);
146 
147 	if (fido_nl_get_nfc_target(nl, (uint32_t)p->dev, &target) == 0)
148 		consume(&target, sizeof(target));
149 
150 	fido_nl_free(&nl);
151 }
152 
153 void
154 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
155 {
156 	if (flags & MUTATE_SEED)
157 		p->seed = (int)seed;
158 
159 	if (flags & MUTATE_PARAM)
160 		mutate_int(&p->dev);
161 
162 	if (flags & MUTATE_WIREDATA)
163 		mutate_blob(&p->wiredata);
164 }
165