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 }
139
140 void
mutate_int(int * i)141 mutate_int(int *i)
142 {
143 LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i));
144 }
145
146 void
mutate_blob(struct blob * blob)147 mutate_blob(struct blob *blob)
148 {
149 blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len,
150 sizeof(blob->body));
151 }
152
153 void
mutate_string(char * s)154 mutate_string(char *s)
155 {
156 size_t n;
157
158 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1);
159 s[n] = '\0';
160 }
161
162 static int
buf_read(unsigned char * ptr,size_t len,int ms)163 buf_read(unsigned char *ptr, size_t len, int ms)
164 {
165 size_t n;
166
167 (void)ms;
168
169 if (prng_up && uniform_random(400) < 1) {
170 errno = EIO;
171 return -1;
172 }
173
174 if (wire_data_len < len)
175 n = wire_data_len;
176 else
177 n = len;
178
179 memcpy(ptr, wire_data_ptr, n);
180
181 wire_data_ptr += n;
182 wire_data_len -= n;
183
184 return (int)n;
185 }
186
187 static int
buf_write(const unsigned char * ptr,size_t len)188 buf_write(const unsigned char *ptr, size_t len)
189 {
190 consume(ptr, len);
191
192 if (prng_up && uniform_random(400) < 1) {
193 errno = EIO;
194 return -1;
195 }
196
197 return (int)len;
198 }
199
200 static void *
hid_open(const char * path)201 hid_open(const char *path)
202 {
203 (void)path;
204
205 return (void *)HID_DEV_HANDLE;
206 }
207
208 static void
hid_close(void * handle)209 hid_close(void *handle)
210 {
211 assert(handle == (void *)HID_DEV_HANDLE);
212 }
213
214 static int
hid_read(void * handle,unsigned char * ptr,size_t len,int ms)215 hid_read(void *handle, unsigned char *ptr, size_t len, int ms)
216 {
217 assert(handle == (void *)HID_DEV_HANDLE);
218 assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN);
219
220 return buf_read(ptr, len, ms);
221 }
222
223 static int
hid_write(void * handle,const unsigned char * ptr,size_t len)224 hid_write(void *handle, const unsigned char *ptr, size_t len)
225 {
226 assert(handle == (void *)HID_DEV_HANDLE);
227 assert(len >= CTAP_MIN_REPORT_LEN + 1 &&
228 len <= CTAP_MAX_REPORT_LEN + 1);
229
230 return buf_write(ptr, len);
231 }
232
233 static void *
nfc_open(const char * path)234 nfc_open(const char *path)
235 {
236 (void)path;
237
238 return (void *)NFC_DEV_HANDLE;
239 }
240
241 static void
nfc_close(void * handle)242 nfc_close(void *handle)
243 {
244 assert(handle == (void *)NFC_DEV_HANDLE);
245 }
246
247 int
nfc_read(void * handle,unsigned char * ptr,size_t len,int ms)248 nfc_read(void *handle, unsigned char *ptr, size_t len, int ms)
249 {
250 assert(handle == (void *)NFC_DEV_HANDLE);
251 assert(len > 0 && len <= 264);
252
253 return buf_read(ptr, len, ms);
254 }
255
256 int
nfc_write(void * handle,const unsigned char * ptr,size_t len)257 nfc_write(void *handle, const unsigned char *ptr, size_t len)
258 {
259 assert(handle == (void *)NFC_DEV_HANDLE);
260 assert(len > 0 && len <= 256 + 2);
261
262 return buf_write(ptr, len);
263 }
264
265 ssize_t
fd_read(int fd,void * ptr,size_t len)266 fd_read(int fd, void *ptr, size_t len)
267 {
268 assert(fd != -1);
269
270 return buf_read(ptr, len, -1);
271 }
272
273 ssize_t
fd_write(int fd,const void * ptr,size_t len)274 fd_write(int fd, const void *ptr, size_t len)
275 {
276 assert(fd != -1);
277
278 return buf_write(ptr, len);
279 }
280
281 fido_dev_t *
open_dev(int nfc)282 open_dev(int nfc)
283 {
284 fido_dev_t *dev;
285 fido_dev_io_t io;
286 fido_dev_transport_t t;
287
288 memset(&io, 0, sizeof(io));
289 memset(&t, 0, sizeof(t));
290
291 if ((dev = fido_dev_new()) == NULL)
292 return NULL;
293
294 if (nfc) {
295 io.open = nfc_open;
296 io.close = nfc_close;
297 io.read = nfc_read;
298 io.write = nfc_write;
299 } else {
300 io.open = hid_open;
301 io.close = hid_close;
302 io.read = hid_read;
303 io.write = hid_write;
304 }
305
306 if (fido_dev_set_io_functions(dev, &io) != FIDO_OK)
307 goto fail;
308
309 if (nfc) {
310 t.rx = fido_nfc_rx;
311 t.tx = fido_nfc_tx;
312 if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK)
313 goto fail;
314 }
315
316 if (fido_dev_set_timeout(dev, 300) != FIDO_OK ||
317 fido_dev_open(dev, "nodev") != FIDO_OK)
318 goto fail;
319
320 return dev;
321 fail:
322 fido_dev_free(&dev);
323
324 return NULL;
325 }
326
327 void
set_wire_data(const uint8_t * ptr,size_t len)328 set_wire_data(const uint8_t *ptr, size_t len)
329 {
330 wire_data_ptr = ptr;
331 wire_data_len = len;
332 }
333