xref: /netbsd-src/external/bsd/pam-u2f/dist/fuzz/fuzz_format_parsers.c (revision 540ca2718c85d7b6631d382e3e93f4dc91e51282)
13ff1169cSchristos /*
2*540ca271Schristos  * Copyright (C) 2020-2022 Yubico AB - See COPYING
33ff1169cSchristos  */
43ff1169cSchristos #include <sys/types.h>
53ff1169cSchristos #include <sys/stat.h>
6*540ca271Schristos #include <errno.h>
7*540ca271Schristos #include <stdint.h>
8*540ca271Schristos #include <stdio.h>
9*540ca271Schristos #include <stdlib.h>
10*540ca271Schristos #include <string.h>
113ff1169cSchristos #include <unistd.h>
123ff1169cSchristos 
133ff1169cSchristos #include "fuzz/fuzz.h"
14*540ca271Schristos #include "util.h"
153ff1169cSchristos 
163ff1169cSchristos static void cleanup(device_t *devs, unsigned int n_devs) {
173ff1169cSchristos   for (unsigned int i = 0; i < n_devs; i++) {
183ff1169cSchristos     free(devs[i].keyHandle);
193ff1169cSchristos     free(devs[i].publicKey);
203ff1169cSchristos     free(devs[i].coseType);
213ff1169cSchristos     free(devs[i].attributes);
223ff1169cSchristos     devs[i].keyHandle = NULL;
233ff1169cSchristos     devs[i].publicKey = NULL;
243ff1169cSchristos     devs[i].coseType = NULL;
253ff1169cSchristos     devs[i].attributes = NULL;
263ff1169cSchristos   }
273ff1169cSchristos }
283ff1169cSchristos 
293ff1169cSchristos #define DEV_MAX_SIZE 10
303ff1169cSchristos 
313ff1169cSchristos int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
323ff1169cSchristos int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
333ff1169cSchristos   device_t devs[12] = {0};
343ff1169cSchristos   unsigned int n_devs = 12;
353ff1169cSchristos   FILE *fp = NULL;
363ff1169cSchristos   size_t fp_len = 0;
373ff1169cSchristos   size_t offset = 0;
38*540ca271Schristos   char username[256] = "user";
393ff1169cSchristos   size_t username_len = 0;
403ff1169cSchristos   cfg_t cfg = {0};
41*540ca271Schristos 
423ff1169cSchristos   cfg.max_devs = DEV_MAX_SIZE;
43*540ca271Schristos   cfg.auth_file = "/path/to/authfile"; /* XXX: any path works, file mocked */
44*540ca271Schristos   cfg.sshformat = 1;
453ff1169cSchristos 
463ff1169cSchristos   /* first 6 byte decides which parser we should call, if
473ff1169cSchristos    * we want to run with debug and also sets the initial seed */
483ff1169cSchristos   if (size < 6) {
493ff1169cSchristos     return -1;
503ff1169cSchristos   }
513ff1169cSchristos   /* do not always run with debug, only 8/255 times */
523ff1169cSchristos   if (data[offset++] < 9) {
533ff1169cSchristos     cfg.debug = 1;
543ff1169cSchristos   }
553ff1169cSchristos 
563ff1169cSchristos   /* predictable random for this seed */
573ff1169cSchristos   prng_init((uint32_t) data[offset] << 24 | (uint32_t) data[offset + 1] << 16 |
583ff1169cSchristos             (uint32_t) data[offset + 2] << 8 | (uint32_t) data[offset + 3]);
593ff1169cSchristos   offset += 4;
603ff1169cSchristos 
613ff1169cSchristos   /* choose which format parser to run, even == native, odd == ssh */
623ff1169cSchristos   if (data[offset++] % 2) {
63*540ca271Schristos     cfg.sshformat = 0;
643ff1169cSchristos     /* native format, get a random username first */
653ff1169cSchristos     if (size < 7) {
663ff1169cSchristos       return -1;
673ff1169cSchristos     }
683ff1169cSchristos     username_len = data[offset++];
693ff1169cSchristos     if (username_len > (size - offset)) {
703ff1169cSchristos       username_len = (size - offset);
713ff1169cSchristos     }
72*540ca271Schristos     memset(username, 0, sizeof(username));
733ff1169cSchristos     memcpy(username, &data[offset], username_len);
743ff1169cSchristos     offset += username_len;
753ff1169cSchristos   }
763ff1169cSchristos 
773ff1169cSchristos   fp_len = size - offset;
783ff1169cSchristos   fp = tmpfile();
793ff1169cSchristos   if (fp == NULL || (fwrite(&data[offset], 1, fp_len, fp)) != fp_len) {
803ff1169cSchristos     fprintf(stderr, "failed to create file for parser: %s\n", strerror(errno));
813ff1169cSchristos     if (fp != NULL) {
823ff1169cSchristos       fclose(fp);
833ff1169cSchristos     }
843ff1169cSchristos     return -1;
853ff1169cSchristos   }
863ff1169cSchristos   (void) fseek(fp, 0L, SEEK_SET);
873ff1169cSchristos 
88*540ca271Schristos   set_user(username);
89*540ca271Schristos   set_authfile(fileno(fp));
90*540ca271Schristos 
91*540ca271Schristos   get_devices_from_authfile(&cfg, username, devs, &n_devs);
923ff1169cSchristos 
933ff1169cSchristos   cleanup(devs, n_devs);
943ff1169cSchristos   fclose(fp);
953ff1169cSchristos 
963ff1169cSchristos   return 0;
973ff1169cSchristos }
98