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
usage(void)56 usage(void)
57 {
58 fprintf(stderr, "usage: %s [-H] <corpus-dir>\n", getprogname());
59 exit(1);
60 }
61
62 static void
write_one(const struct fuzz_params * params,const struct seed * seed,int dirfd,bool striphdr)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
main(int argc,char * argv[])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