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