diff options
Diffstat (limited to 'fuzz/fuzz_mgmt.c')
-rw-r--r-- | fuzz/fuzz_mgmt.c | 321 |
1 files changed, 164 insertions, 157 deletions
diff --git a/fuzz/fuzz_mgmt.c b/fuzz/fuzz_mgmt.c index d46daf6..0b6cf19 100644 --- a/fuzz/fuzz_mgmt.c +++ b/fuzz/fuzz_mgmt.c | |||
@@ -17,24 +17,15 @@ | |||
17 | 17 | ||
18 | #include "../openbsd-compat/openbsd-compat.h" | 18 | #include "../openbsd-compat/openbsd-compat.h" |
19 | 19 | ||
20 | #define TAG_PIN1 0x01 | ||
21 | #define TAG_PIN2 0x02 | ||
22 | #define TAG_RESET_WIRE_DATA 0x03 | ||
23 | #define TAG_INFO_WIRE_DATA 0x04 | ||
24 | #define TAG_SET_PIN_WIRE_DATA 0x05 | ||
25 | #define TAG_CHANGE_PIN_WIRE_DATA 0x06 | ||
26 | #define TAG_RETRY_WIRE_DATA 0x07 | ||
27 | #define TAG_SEED 0x08 | ||
28 | |||
29 | struct param { | 20 | struct param { |
30 | char pin1[MAXSTR]; | 21 | char pin1[MAXSTR]; |
31 | char pin2[MAXSTR]; | 22 | char pin2[MAXSTR]; |
32 | struct blob reset_wire_data; | 23 | struct blob reset_wire_data; |
33 | struct blob info_wire_data; | 24 | struct blob info_wire_data; |
34 | struct blob set_pin_wire_data; | 25 | struct blob set_pin_wire_data; |
35 | struct blob change_pin_wire_data; | 26 | struct blob change_pin_wire_data; |
36 | struct blob retry_wire_data; | 27 | struct blob retry_wire_data; |
37 | int seed; | 28 | int seed; |
38 | }; | 29 | }; |
39 | 30 | ||
40 | static const uint8_t dummy_reset_wire_data[] = { | 31 | static const uint8_t dummy_reset_wire_data[] = { |
@@ -72,56 +63,136 @@ static const uint8_t dummy_retry_wire_data[] = { | |||
72 | WIREDATA_CTAP_CBOR_RETRIES, | 63 | WIREDATA_CTAP_CBOR_RETRIES, |
73 | }; | 64 | }; |
74 | 65 | ||
75 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | 66 | struct param * |
76 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | 67 | unpack(const uint8_t *ptr, size_t len) |
77 | |||
78 | static int | ||
79 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
80 | { | 68 | { |
81 | uint8_t **pp = (void *)&ptr; | 69 | cbor_item_t *item = NULL, **v; |
82 | 70 | struct cbor_load_result cbor; | |
83 | if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || | 71 | struct param *p; |
84 | unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || | 72 | int ok = -1; |
85 | unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || | 73 | |
86 | unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || | 74 | if ((p = calloc(1, sizeof(*p))) == NULL || |
87 | unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || | 75 | (item = cbor_load(ptr, len, &cbor)) == NULL || |
88 | unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || | 76 | cbor.read != len || |
89 | unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || | 77 | cbor_isa_array(item) == false || |
90 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) | 78 | cbor_array_is_definite(item) == false || |
91 | return (-1); | 79 | cbor_array_size(item) != 8 || |
92 | 80 | (v = cbor_array_handle(item)) == NULL) | |
93 | return (0); | 81 | goto fail; |
82 | |||
83 | if (unpack_int(v[0], &p->seed) < 0 || | ||
84 | unpack_string(v[1], p->pin1) < 0 || | ||
85 | unpack_string(v[2], p->pin2) < 0 || | ||
86 | unpack_blob(v[3], &p->reset_wire_data) < 0 || | ||
87 | unpack_blob(v[4], &p->info_wire_data) < 0 || | ||
88 | unpack_blob(v[5], &p->set_pin_wire_data) < 0 || | ||
89 | unpack_blob(v[6], &p->change_pin_wire_data) < 0 || | ||
90 | unpack_blob(v[7], &p->retry_wire_data) < 0) | ||
91 | goto fail; | ||
92 | |||
93 | ok = 0; | ||
94 | fail: | ||
95 | if (ok < 0) { | ||
96 | free(p); | ||
97 | p = NULL; | ||
98 | } | ||
99 | |||
100 | if (item) | ||
101 | cbor_decref(&item); | ||
102 | |||
103 | return p; | ||
94 | } | 104 | } |
95 | 105 | ||
96 | static size_t | 106 | size_t |
97 | pack(uint8_t *ptr, size_t len, const struct param *p) | 107 | pack(uint8_t *ptr, size_t len, const struct param *p) |
98 | { | 108 | { |
99 | const size_t max = len; | 109 | cbor_item_t *argv[8], *array = NULL; |
100 | 110 | size_t cbor_alloc_len, cbor_len = 0; | |
101 | if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || | 111 | unsigned char *cbor = NULL; |
102 | pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || | 112 | |
103 | pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || | 113 | memset(argv, 0, sizeof(argv)); |
104 | pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || | 114 | |
105 | pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || | 115 | if ((array = cbor_new_definite_array(8)) == NULL || |
106 | pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || | 116 | (argv[0] = pack_int(p->seed)) == NULL || |
107 | pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || | 117 | (argv[1] = pack_string(p->pin1)) == NULL || |
108 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) | 118 | (argv[2] = pack_string(p->pin2)) == NULL || |
109 | return (0); | 119 | (argv[3] = pack_blob(&p->reset_wire_data)) == NULL || |
110 | 120 | (argv[4] = pack_blob(&p->info_wire_data)) == NULL || | |
111 | return (max - len); | 121 | (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL || |
122 | (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL || | ||
123 | (argv[7] = pack_blob(&p->retry_wire_data)) == NULL) | ||
124 | goto fail; | ||
125 | |||
126 | for (size_t i = 0; i < 8; i++) | ||
127 | if (cbor_array_push(array, argv[i]) == false) | ||
128 | goto fail; | ||
129 | |||
130 | if ((cbor_len = cbor_serialize_alloc(array, &cbor, | ||
131 | &cbor_alloc_len)) > len) { | ||
132 | cbor_len = 0; | ||
133 | goto fail; | ||
134 | } | ||
135 | |||
136 | memcpy(ptr, cbor, cbor_len); | ||
137 | fail: | ||
138 | for (size_t i = 0; i < 8; i++) | ||
139 | if (argv[i]) | ||
140 | cbor_decref(&argv[i]); | ||
141 | |||
142 | if (array) | ||
143 | cbor_decref(&array); | ||
144 | |||
145 | free(cbor); | ||
146 | |||
147 | return cbor_len; | ||
112 | } | 148 | } |
113 | 149 | ||
114 | static size_t | 150 | size_t |
115 | input_len(int max) | 151 | pack_dummy(uint8_t *ptr, size_t len) |
116 | { | 152 | { |
117 | return (2 * len_string(max) + 5 * len_blob(max) + len_int()); | 153 | struct param dummy; |
154 | uint8_t blob[4096]; | ||
155 | size_t blob_len; | ||
156 | |||
157 | memset(&dummy, 0, sizeof(dummy)); | ||
158 | |||
159 | strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); | ||
160 | strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); | ||
161 | |||
162 | dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); | ||
163 | dummy.info_wire_data.len = sizeof(dummy_info_wire_data); | ||
164 | dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); | ||
165 | dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); | ||
166 | dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); | ||
167 | |||
168 | memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, | ||
169 | dummy.reset_wire_data.len); | ||
170 | memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, | ||
171 | dummy.info_wire_data.len); | ||
172 | memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, | ||
173 | dummy.set_pin_wire_data.len); | ||
174 | memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, | ||
175 | dummy.change_pin_wire_data.len); | ||
176 | memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, | ||
177 | dummy.retry_wire_data.len); | ||
178 | |||
179 | assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); | ||
180 | |||
181 | if (blob_len > len) { | ||
182 | memcpy(ptr, blob, len); | ||
183 | return len; | ||
184 | } | ||
185 | |||
186 | memcpy(ptr, blob, blob_len); | ||
187 | |||
188 | return blob_len; | ||
118 | } | 189 | } |
119 | 190 | ||
120 | static fido_dev_t * | 191 | static fido_dev_t * |
121 | prepare_dev() | 192 | prepare_dev(void) |
122 | { | 193 | { |
123 | fido_dev_t *dev; | 194 | fido_dev_t *dev; |
124 | fido_dev_io_t io; | 195 | fido_dev_io_t io; |
125 | 196 | ||
126 | memset(&io, 0, sizeof(io)); | 197 | memset(&io, 0, sizeof(io)); |
127 | 198 | ||
@@ -133,14 +204,14 @@ prepare_dev() | |||
133 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | 204 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, |
134 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | 205 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { |
135 | fido_dev_free(&dev); | 206 | fido_dev_free(&dev); |
136 | return (NULL); | 207 | return NULL; |
137 | } | 208 | } |
138 | 209 | ||
139 | return (dev); | 210 | return dev; |
140 | } | 211 | } |
141 | 212 | ||
142 | static void | 213 | static void |
143 | dev_reset(struct param *p) | 214 | dev_reset(const struct param *p) |
144 | { | 215 | { |
145 | fido_dev_t *dev; | 216 | fido_dev_t *dev; |
146 | 217 | ||
@@ -155,16 +226,12 @@ dev_reset(struct param *p) | |||
155 | } | 226 | } |
156 | 227 | ||
157 | static void | 228 | static void |
158 | dev_get_cbor_info(struct param *p) | 229 | dev_get_cbor_info(const struct param *p) |
159 | { | 230 | { |
160 | fido_dev_t *dev; | 231 | fido_dev_t *dev; |
161 | fido_cbor_info_t *ci; | 232 | fido_cbor_info_t *ci; |
162 | uint64_t n; | 233 | uint64_t n; |
163 | uint8_t proto; | 234 | uint8_t proto, major, minor, build, flags; |
164 | uint8_t major; | ||
165 | uint8_t minor; | ||
166 | uint8_t build; | ||
167 | uint8_t flags; | ||
168 | 235 | ||
169 | set_wire_data(p->info_wire_data.body, p->info_wire_data.len); | 236 | set_wire_data(p->info_wire_data.body, p->info_wire_data.len); |
170 | 237 | ||
@@ -192,6 +259,7 @@ dev_get_cbor_info(struct param *p) | |||
192 | char * const *sa = fido_cbor_info_versions_ptr(ci); | 259 | char * const *sa = fido_cbor_info_versions_ptr(ci); |
193 | consume(sa[i], strlen(sa[i])); | 260 | consume(sa[i], strlen(sa[i])); |
194 | } | 261 | } |
262 | |||
195 | for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { | 263 | for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { |
196 | char * const *sa = fido_cbor_info_extensions_ptr(ci); | 264 | char * const *sa = fido_cbor_info_extensions_ptr(ci); |
197 | consume(sa[i], strlen(sa[i])); | 265 | consume(sa[i], strlen(sa[i])); |
@@ -207,6 +275,12 @@ dev_get_cbor_info(struct param *p) | |||
207 | n = fido_cbor_info_maxmsgsiz(ci); | 275 | n = fido_cbor_info_maxmsgsiz(ci); |
208 | consume(&n, sizeof(n)); | 276 | consume(&n, sizeof(n)); |
209 | 277 | ||
278 | n = fido_cbor_info_maxcredcntlst(ci); | ||
279 | consume(&n, sizeof(n)); | ||
280 | |||
281 | n = fido_cbor_info_maxcredidlen(ci); | ||
282 | consume(&n, sizeof(n)); | ||
283 | |||
210 | n = fido_cbor_info_fwversion(ci); | 284 | n = fido_cbor_info_fwversion(ci); |
211 | consume(&n, sizeof(n)); | 285 | consume(&n, sizeof(n)); |
212 | 286 | ||
@@ -222,7 +296,7 @@ out: | |||
222 | } | 296 | } |
223 | 297 | ||
224 | static void | 298 | static void |
225 | dev_set_pin(struct param *p) | 299 | dev_set_pin(const struct param *p) |
226 | { | 300 | { |
227 | fido_dev_t *dev; | 301 | fido_dev_t *dev; |
228 | 302 | ||
@@ -237,7 +311,7 @@ dev_set_pin(struct param *p) | |||
237 | } | 311 | } |
238 | 312 | ||
239 | static void | 313 | static void |
240 | dev_change_pin(struct param *p) | 314 | dev_change_pin(const struct param *p) |
241 | { | 315 | { |
242 | fido_dev_t *dev; | 316 | fido_dev_t *dev; |
243 | 317 | ||
@@ -252,10 +326,10 @@ dev_change_pin(struct param *p) | |||
252 | } | 326 | } |
253 | 327 | ||
254 | static void | 328 | static void |
255 | dev_get_retry_count(struct param *p) | 329 | dev_get_retry_count(const struct param *p) |
256 | { | 330 | { |
257 | fido_dev_t *dev; | 331 | fido_dev_t *dev; |
258 | int n; | 332 | int n = 0; |
259 | 333 | ||
260 | set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); | 334 | set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); |
261 | 335 | ||
@@ -268,103 +342,36 @@ dev_get_retry_count(struct param *p) | |||
268 | fido_dev_free(&dev); | 342 | fido_dev_free(&dev); |
269 | } | 343 | } |
270 | 344 | ||
271 | int | 345 | void |
272 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | 346 | test(const struct param *p) |
273 | { | 347 | { |
274 | struct param p; | 348 | prng_init((unsigned int)p->seed); |
275 | |||
276 | memset(&p, 0, sizeof(p)); | ||
277 | |||
278 | if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || | ||
279 | unpack(data, size, &p) < 0) | ||
280 | return (0); | ||
281 | |||
282 | prng_init((unsigned int)p.seed); | ||
283 | |||
284 | fido_init(FIDO_DEBUG); | 349 | fido_init(FIDO_DEBUG); |
285 | fido_set_log_handler(consume_str); | 350 | fido_set_log_handler(consume_str); |
286 | 351 | ||
287 | dev_reset(&p); | 352 | dev_reset(p); |
288 | dev_get_cbor_info(&p); | 353 | dev_get_cbor_info(p); |
289 | dev_set_pin(&p); | 354 | dev_set_pin(p); |
290 | dev_change_pin(&p); | 355 | dev_change_pin(p); |
291 | dev_get_retry_count(&p); | 356 | dev_get_retry_count(p); |
292 | |||
293 | return (0); | ||
294 | } | 357 | } |
295 | 358 | ||
296 | static size_t | 359 | void |
297 | pack_dummy(uint8_t *ptr, size_t len) | 360 | mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN |
298 | { | 361 | { |
299 | struct param dummy; | 362 | if (flags & MUTATE_SEED) |
300 | uint8_t blob[16384]; | 363 | p->seed = (int)seed; |
301 | size_t blob_len; | ||
302 | |||
303 | memset(&dummy, 0, sizeof(dummy)); | ||
304 | |||
305 | strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); | ||
306 | strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); | ||
307 | |||
308 | dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); | ||
309 | dummy.info_wire_data.len = sizeof(dummy_info_wire_data); | ||
310 | dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); | ||
311 | dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); | ||
312 | dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); | ||
313 | |||
314 | memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, | ||
315 | dummy.reset_wire_data.len); | ||
316 | memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, | ||
317 | dummy.info_wire_data.len); | ||
318 | memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, | ||
319 | dummy.set_pin_wire_data.len); | ||
320 | memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, | ||
321 | dummy.change_pin_wire_data.len); | ||
322 | memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, | ||
323 | dummy.retry_wire_data.len); | ||
324 | |||
325 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
326 | assert(blob_len != 0); | ||
327 | 364 | ||
328 | if (blob_len > len) { | 365 | if (flags & MUTATE_PARAM) { |
329 | memcpy(ptr, blob, len); | 366 | mutate_string(p->pin1); |
330 | return (len); | 367 | mutate_string(p->pin2); |
331 | } | 368 | } |
332 | 369 | ||
333 | memcpy(ptr, blob, blob_len); | 370 | if (flags & MUTATE_WIREDATA) { |
334 | 371 | mutate_blob(&p->reset_wire_data); | |
335 | return (blob_len); | 372 | mutate_blob(&p->info_wire_data); |
336 | } | 373 | mutate_blob(&p->set_pin_wire_data); |
337 | 374 | mutate_blob(&p->change_pin_wire_data); | |
338 | size_t | 375 | mutate_blob(&p->retry_wire_data); |
339 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | 376 | } |
340 | unsigned int seed) | ||
341 | { | ||
342 | struct param p; | ||
343 | uint8_t blob[16384]; | ||
344 | size_t blob_len; | ||
345 | |||
346 | memset(&p, 0, sizeof(p)); | ||
347 | |||
348 | if (unpack(data, size, &p) < 0) | ||
349 | return (pack_dummy(data, maxsize)); | ||
350 | |||
351 | p.seed = (int)seed; | ||
352 | |||
353 | mutate_string(p.pin1); | ||
354 | mutate_string(p.pin2); | ||
355 | |||
356 | mutate_blob(&p.reset_wire_data); | ||
357 | mutate_blob(&p.info_wire_data); | ||
358 | mutate_blob(&p.set_pin_wire_data); | ||
359 | mutate_blob(&p.change_pin_wire_data); | ||
360 | mutate_blob(&p.retry_wire_data); | ||
361 | |||
362 | blob_len = pack(blob, sizeof(blob), &p); | ||
363 | |||
364 | if (blob_len == 0 || blob_len > maxsize) | ||
365 | return (0); | ||
366 | |||
367 | memcpy(data, blob, blob_len); | ||
368 | |||
369 | return (blob_len); | ||
370 | } | 377 | } |