xref: /freebsd/contrib/libfido2/fuzz/fuzz_netlink.c (revision ebacd8013fe5f7fdf9f6a5b286f6680dd2891036)
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  */
6 
7 #include <assert.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 
13 #include "../openbsd-compat/openbsd-compat.h"
14 #include "mutator_aux.h"
15 
16 struct param {
17 	int seed;
18 	int dev;
19 	struct blob wiredata;
20 };
21 
22 /*
23  * Sample netlink messages. These are unlikely to get the harness very far in
24  * terms of coverage, but serve to give libFuzzer a sense of the underlying
25  * structure.
26  */
27 static const uint8_t sample_netlink_wiredata[] = {
28 	0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
29 	0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
30 	0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
31 	0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00,
32 	0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
33 	0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00,
34 	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00,
35 	0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00,
36 	0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
37 	0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
38 	0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
39 	0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
40 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
41 	0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00,
42 	0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
43 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00,
44 	0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00,
45 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
46 	0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00,
47 	0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
48 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00,
49 	0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
50 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
51 	0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00,
52 	0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
53 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00,
54 	0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
55 	0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00,
56 	0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00,
57 	0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
58 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00,
59 	0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00,
60 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
61 	0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00,
62 	0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
63 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00,
64 	0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00,
65 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
66 	0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00,
67 	0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
68 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00,
69 	0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,
70 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
71 	0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00,
72 	0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
73 	0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00,
74 	0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00,
75 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
76 	0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00,
77 	0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
78 	0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,
79 	0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00,
80 	0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
81 	0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00,
82 	0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
83 	0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00,
84 	0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00,
85 	0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00,
86 	0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00,
87 	0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01,
88 	0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
89 	0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
90 	0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
91 	0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
92 	0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
93 	0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 	0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00,
95 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 	0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
97 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 	0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
99 	0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
100 	0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
101 	0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00,
102 	0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
103 	0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
104 	0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00,
105 	0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00,
106 	0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
107 	0x93, 0xb9, 0x25, 0x00
108 };
109 
110 struct param *
111 unpack(const uint8_t *ptr, size_t len)
112 {
113 	cbor_item_t *item = NULL, **v;
114 	struct cbor_load_result cbor;
115 	struct param *p;
116 	int ok = -1;
117 
118 	if ((p = calloc(1, sizeof(*p))) == NULL ||
119 	    (item = cbor_load(ptr, len, &cbor)) == NULL ||
120 	    cbor.read != len ||
121 	    cbor_isa_array(item) == false ||
122 	    cbor_array_is_definite(item) == false ||
123 	    cbor_array_size(item) != 3 ||
124 	    (v = cbor_array_handle(item)) == NULL)
125 		goto fail;
126 
127 	if (unpack_int(v[0], &p->seed) < 0 ||
128 	    unpack_int(v[1], &p->dev) < 0 ||
129 	    unpack_blob(v[2], &p->wiredata) < 0)
130 		goto fail;
131 
132 	ok = 0;
133 fail:
134 	if (ok < 0) {
135 		free(p);
136 		p = NULL;
137 	}
138 
139 	if (item)
140 		cbor_decref(&item);
141 
142 	return p;
143 }
144 
145 size_t
146 pack(uint8_t *ptr, size_t len, const struct param *p)
147 {
148 	cbor_item_t *argv[3], *array = NULL;
149 	size_t cbor_alloc_len, cbor_len = 0;
150 	unsigned char *cbor = NULL;
151 
152 	memset(argv, 0, sizeof(argv));
153 
154 	if ((array = cbor_new_definite_array(3)) == NULL ||
155 	    (argv[0] = pack_int(p->seed)) == NULL ||
156 	    (argv[1] = pack_int(p->dev)) == NULL ||
157 	    (argv[2] = pack_blob(&p->wiredata)) == NULL)
158 		goto fail;
159 
160 	for (size_t i = 0; i < 3; i++)
161 		if (cbor_array_push(array, argv[i]) == false)
162 			goto fail;
163 
164 	if ((cbor_len = cbor_serialize_alloc(array, &cbor,
165 	    &cbor_alloc_len)) > len) {
166 		cbor_len = 0;
167 		goto fail;
168 	}
169 
170 	memcpy(ptr, cbor, cbor_len);
171 fail:
172 	for (size_t i = 0; i < 3; i++)
173 		if (argv[i])
174 			cbor_decref(&argv[i]);
175 
176 	if (array)
177 		cbor_decref(&array);
178 
179 	free(cbor);
180 
181 	return cbor_len;
182 }
183 
184 size_t
185 pack_dummy(uint8_t *ptr, size_t len)
186 {
187 	struct param dummy;
188 	uint8_t	blob[4096];
189 	size_t blob_len;
190 
191 	memset(&dummy, 0, sizeof(dummy));
192 
193 	dummy.wiredata.len = sizeof(sample_netlink_wiredata);
194 	memcpy(&dummy.wiredata.body, &sample_netlink_wiredata,
195 	    dummy.wiredata.len);
196 
197 	assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
198 
199 	if (blob_len > len) {
200 		memcpy(ptr, blob, len);
201 		return len;
202 	}
203 
204 	memcpy(ptr, blob, blob_len);
205 
206 	return blob_len;
207 }
208 
209 void
210 test(const struct param *p)
211 {
212 	fido_nl_t *nl;
213 	uint32_t target;
214 
215 	prng_init((unsigned int)p->seed);
216 	fido_init(FIDO_DEBUG);
217 	fido_set_log_handler(consume_str);
218 
219 	set_netlink_io_functions(fd_read, fd_write);
220 	set_wire_data(p->wiredata.body, p->wiredata.len);
221 
222 	if ((nl = fido_nl_new()) == NULL)
223 		return;
224 
225 	consume(&nl->fd, sizeof(nl->fd));
226 	consume(&nl->nfc_type, sizeof(nl->nfc_type));
227 	consume(&nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp));
228 	consume(&nl->saddr, sizeof(nl->saddr));
229 
230 	fido_nl_power_nfc(nl, (uint32_t)p->dev);
231 
232 	if (fido_nl_get_nfc_target(nl, (uint32_t)p->dev, &target) == 0)
233 		consume(&target, sizeof(target));
234 
235 	fido_nl_free(&nl);
236 }
237 
238 void
239 mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
240 {
241 	if (flags & MUTATE_SEED)
242 		p->seed = (int)seed;
243 
244 	if (flags & MUTATE_PARAM)
245 		mutate_int(&p->dev);
246 
247 	if (flags & MUTATE_WIREDATA)
248 		mutate_blob(&p->wiredata);
249 }
250