1 /*- 2 * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/param.h> 8 9 #undef NDEBUG 10 #include <assert.h> 11 #include <err.h> 12 #include <fcntl.h> 13 #include <stdbool.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <unistd.h> 18 19 #include <libder.h> 20 21 #include "fuzzers.h" 22 23 #define LARGE_SIZE (1024 * 64) 24 25 static const uint8_t empty_seq[] = { BT_SEQUENCE, 0x00 }; 26 static const uint8_t long_size[21] = { BT_OCTETSTRING, 0x83, 0x00, 0x00, 0x10 }; 27 28 /* 64k */ 29 #define LARGE_SIZE_ENCODING 0x83, 0x01, 0x00, 0x00 30 static const uint8_t large_octet[LARGE_SIZE + 5] = { BT_OCTETSTRING, LARGE_SIZE_ENCODING }; 31 32 #define VARLEN_SEQ BT_OCTETSTRING, 0x04, 0x01, 0x02, 0x03, 0x04 33 #define VARLEN_CHILDREN VARLEN_SEQ, VARLEN_SEQ, VARLEN_SEQ 34 static const uint8_t varlen[] = { BT_SEQUENCE, 0x80, 35 VARLEN_CHILDREN, 0x00, 0x00 }; 36 37 #define BITSTRING1 BT_BITSTRING, 0x04, 0x03, 0xc0, 0xc0, 0xcc 38 #define BITSTRING2 BT_BITSTRING, 0x04, 0x05, 0xdd, 0xdd, 0xff 39 static const uint8_t constructed_bitstring[] = { 0x20 | BT_BITSTRING, 40 2 * 6, BITSTRING1, BITSTRING2 }; 41 42 #define FUZZER_SEED(seq) { #seq, sizeof(seq), seq } 43 static const struct seed { 44 const char *seed_name; 45 size_t seed_seqsz; 46 const uint8_t *seed_seq; 47 } seeds[] = { 48 FUZZER_SEED(empty_seq), 49 FUZZER_SEED(long_size), 50 FUZZER_SEED(large_octet), 51 FUZZER_SEED(varlen), 52 FUZZER_SEED(constructed_bitstring), 53 }; 54 55 static void 56 usage(void) 57 { 58 fprintf(stderr, "usage: %s [-H] <corpus-dir>\n", getprogname()); 59 exit(1); 60 } 61 62 static void 63 write_one(const struct fuzz_params *params, const struct seed *seed, int dirfd, 64 bool striphdr) 65 { 66 char *name; 67 int fd = -1; 68 69 assert(asprintf(&name, "base_%d_%d_%d_%s", params->type, 70 params->buftype, params->strict, seed->seed_name) != -1); 71 72 fd = openat(dirfd, name, O_RDWR | O_TRUNC | O_CREAT, 0644); 73 assert(fd != -1); 74 75 /* 76 * Write our params + seed; if we're stripping the header we won't have 77 * the full params, but we'll still have our signal byte for strict 78 * mode. 79 */ 80 if (!striphdr) 81 assert(write(fd, ¶ms, sizeof(params)) == sizeof(params)); 82 else 83 assert(write(fd, ¶ms->strict, sizeof(params->strict)) == sizeof(params->strict)); 84 85 assert(write(fd, seed->seed_seq, seed->seed_seqsz) == seed->seed_seqsz); 86 87 free(name); 88 close(fd); 89 } 90 91 int 92 main(int argc, char *argv[]) 93 { 94 struct fuzz_params params; 95 const struct seed *seed; 96 const char *seed_dir; 97 int dirfd = -1; 98 bool striphdr = false; 99 100 if (argc < 2 || argc > 3) 101 usage(); 102 103 if (argc == 3 && strcmp(argv[1], "-H") != 0) 104 usage(); 105 106 striphdr = argc == 3; 107 seed_dir = argv[argc - 1]; 108 109 dirfd = open(seed_dir, O_SEARCH); 110 if (dirfd == -1) 111 err(1, "%s: open", seed_dir); 112 113 memset(¶ms, 0, sizeof(params)); 114 115 for (int type = 0; type < STREAM_END; type++) { 116 params.type = type; 117 118 for (int buffered = 0; buffered < BUFFER_END; buffered++) { 119 params.buftype = buffered; 120 121 for (uint8_t strict = 0; strict < 2; strict++) { 122 params.strict = strict; 123 124 for (size_t i = 0; i < nitems(seeds); i++) { 125 seed = &seeds[i]; 126 127 write_one(¶ms, seed, dirfd, striphdr); 128 } 129 } 130 131 if (type != STREAM_FILE) 132 break; 133 } 134 } 135 136 close(dirfd); 137 } 138