xref: /netbsd-src/external/bsd/pam-u2f/dist/fuzz/fuzz_format_parsers.c (revision 540ca2718c85d7b6631d382e3e93f4dc91e51282)
1 /*
2  * Copyright (C) 2020-2022 Yubico AB - See COPYING
3  */
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <errno.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 
13 #include "fuzz/fuzz.h"
14 #include "util.h"
15 
16 static void cleanup(device_t *devs, unsigned int n_devs) {
17   for (unsigned int i = 0; i < n_devs; i++) {
18     free(devs[i].keyHandle);
19     free(devs[i].publicKey);
20     free(devs[i].coseType);
21     free(devs[i].attributes);
22     devs[i].keyHandle = NULL;
23     devs[i].publicKey = NULL;
24     devs[i].coseType = NULL;
25     devs[i].attributes = NULL;
26   }
27 }
28 
29 #define DEV_MAX_SIZE 10
30 
31 int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
32 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
33   device_t devs[12] = {0};
34   unsigned int n_devs = 12;
35   FILE *fp = NULL;
36   size_t fp_len = 0;
37   size_t offset = 0;
38   char username[256] = "user";
39   size_t username_len = 0;
40   cfg_t cfg = {0};
41 
42   cfg.max_devs = DEV_MAX_SIZE;
43   cfg.auth_file = "/path/to/authfile"; /* XXX: any path works, file mocked */
44   cfg.sshformat = 1;
45 
46   /* first 6 byte decides which parser we should call, if
47    * we want to run with debug and also sets the initial seed */
48   if (size < 6) {
49     return -1;
50   }
51   /* do not always run with debug, only 8/255 times */
52   if (data[offset++] < 9) {
53     cfg.debug = 1;
54   }
55 
56   /* predictable random for this seed */
57   prng_init((uint32_t) data[offset] << 24 | (uint32_t) data[offset + 1] << 16 |
58             (uint32_t) data[offset + 2] << 8 | (uint32_t) data[offset + 3]);
59   offset += 4;
60 
61   /* choose which format parser to run, even == native, odd == ssh */
62   if (data[offset++] % 2) {
63     cfg.sshformat = 0;
64     /* native format, get a random username first */
65     if (size < 7) {
66       return -1;
67     }
68     username_len = data[offset++];
69     if (username_len > (size - offset)) {
70       username_len = (size - offset);
71     }
72     memset(username, 0, sizeof(username));
73     memcpy(username, &data[offset], username_len);
74     offset += username_len;
75   }
76 
77   fp_len = size - offset;
78   fp = tmpfile();
79   if (fp == NULL || (fwrite(&data[offset], 1, fp_len, fp)) != fp_len) {
80     fprintf(stderr, "failed to create file for parser: %s\n", strerror(errno));
81     if (fp != NULL) {
82       fclose(fp);
83     }
84     return -1;
85   }
86   (void) fseek(fp, 0L, SEEK_SET);
87 
88   set_user(username);
89   set_authfile(fileno(fp));
90 
91   get_devices_from_authfile(&cfg, username, devs, &n_devs);
92 
93   cleanup(devs, n_devs);
94   fclose(fp);
95 
96   return 0;
97 }
98