xref: /freebsd/contrib/libfido2/fuzz/mutator_aux.c (revision febb0da5bf4bc99828ebede7abcb039514ac367a)
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
consume(const void * body,size_t len)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
consume_str(const char * str)44 consume_str(const char *str)
45 {
46 	if (str != NULL)
47 		consume(str, strlen(str) + 1);
48 }
49 
50 int
unpack_int(cbor_item_t * item,int * v)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
unpack_string(cbor_item_t * item,char * v)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
unpack_byte(cbor_item_t * item,uint8_t * v)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
unpack_blob(cbor_item_t * item,struct blob * v)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 *
pack_int(int v)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 *
pack_string(const char * v)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 *
pack_byte(uint8_t v)123 pack_byte(uint8_t v) NO_MSAN
124 {
125 	return cbor_build_uint8(v);
126 }
127 
128 cbor_item_t *
pack_blob(const struct blob * v)129 pack_blob(const struct blob *v) NO_MSAN
130 {
131 	return cbor_build_bytestring(v->body, v->len);
132 }
133 
134 void
mutate_byte(uint8_t * b)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
mutate_int(int * i)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
mutate_blob(struct blob * blob)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
mutate_string(char * s)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
buf_read(unsigned char * ptr,size_t len,int ms)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
buf_write(const unsigned char * ptr,size_t len)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 *
hid_open(const char * path)207 hid_open(const char *path)
208 {
209 	(void)path;
210 
211 	return (void *)HID_DEV_HANDLE;
212 }
213 
214 static void
hid_close(void * handle)215 hid_close(void *handle)
216 {
217 	assert(handle == (void *)HID_DEV_HANDLE);
218 }
219 
220 static int
hid_read(void * handle,unsigned char * ptr,size_t len,int ms)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
hid_write(void * handle,const unsigned char * ptr,size_t len)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 *
nfc_open(const char * path)240 nfc_open(const char *path)
241 {
242 	(void)path;
243 
244 	return (void *)NFC_DEV_HANDLE;
245 }
246 
247 static void
nfc_close(void * handle)248 nfc_close(void *handle)
249 {
250 	assert(handle == (void *)NFC_DEV_HANDLE);
251 }
252 
253 int
nfc_read(void * handle,unsigned char * ptr,size_t len,int ms)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
nfc_write(void * handle,const unsigned char * ptr,size_t len)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
fd_read(int fd,void * ptr,size_t len)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
fd_write(int fd,const void * ptr,size_t len)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 *
open_dev(int nfc)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
set_wire_data(const uint8_t * ptr,size_t len)334 set_wire_data(const uint8_t *ptr, size_t len)
335 {
336 	wire_data_ptr = ptr;
337 	wire_data_len = len;
338 }
339