aboutsummaryrefslogtreecommitdiffstats
path: root/src/fuzzer/fuzzers.h
blob: ee78f7a6dda5d0ad8bb2d7e38b7c44e605fc04c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* (C) 2015,2016,2017 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_FUZZER_DRIVER_H_
#define BOTAN_FUZZER_DRIVER_H_

#include <stdint.h>
#include <stdlib.h> // for setenv
#include <iostream>
#include <vector>
#include <botan/exceptn.h>
#include <botan/chacha_rng.h>

static const size_t max_fuzzer_input_size = 8192;

extern void fuzz(const uint8_t in[], size_t len);

extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len);

extern "C" int LLVMFuzzerInitialize(int *, char ***)
   {
   /*
   * This disables the mlock pool, as overwrites within the pool are
   * opaque to ASan or other instrumentation.
   */
   ::setenv("BOTAN_MLOCK_POOL_SIZE", "0", 1);
   return 0;
   }

// Called by main() in libFuzzer or in main for AFL below
extern "C" int LLVMFuzzerTestOneInput(const uint8_t in[], size_t len)
   {
   if(len <= max_fuzzer_input_size)
      {
      fuzz(in, len);
      }
   return 0;
   }

// Some helpers for the fuzzer jigs

inline Botan::RandomNumberGenerator& fuzzer_rng()
   {
   static Botan::ChaCha_RNG rng(Botan::secure_vector<uint8_t>(32));
   return rng;
   }

#define FUZZER_WRITE_AND_CRASH(expr) \
   do { std::cerr << expr; abort(); } while(0)

#define FUZZER_ASSERT_EQUAL(x, y) do {                                  \
   if(x != y) {                                                         \
      FUZZER_WRITE_AND_CRASH(#x << " = " << x << " !=\n"                \
                             << #y << " = " << y << "\n");              \
   } } while(0)

#define FUZZER_ASSERT_TRUE(e)                                           \
   do {                                                                 \
   if(!(e)) {                                                           \
      FUZZER_WRITE_AND_CRASH("Expression " << #e << " was false");      \
   } } while(0)

#if defined(BOTAN_FUZZER_IS_AFL) || defined(BOTAN_FUZZER_IS_TEST)

/* Stub for AFL */

#if defined(BOTAN_FUZZER_IS_AFL) && !defined(__AFL_COMPILER)
   #error "Build configured for AFL but not being compiled by AFL compiler"
#endif

#if defined(BOTAN_FUZZER_IS_TEST)

#include <fstream>

namespace {

int fuzz_files(char* files[])
   {
   for(size_t i = 0; files[i]; ++i)
      {
      std::ifstream in(files[i]);

      if(in.good())
         {
         std::vector<uint8_t> buf(max_fuzzer_input_size);
         in.read((char*)buf.data(), buf.size());
         const size_t got = in.gcount();
         buf.resize(got);
         buf.shrink_to_fit();

         LLVMFuzzerTestOneInput(buf.data(), got);
         }
      }

   return 0;
   }

}

#endif

int main(int argc, char* argv[])
   {
   LLVMFuzzerInitialize(&argc, &argv);

#if defined(BOTAN_FUZZER_IS_TEST)
   if(argc > 1)
      {
      return fuzz_files(&argv[1]);
      }
#endif

#if defined(__AFL_LOOP)
   while(__AFL_LOOP(1000))
#endif
      {
      std::vector<uint8_t> buf(max_fuzzer_input_size);
      std::cin.read((char*)buf.data(), buf.size());
      const size_t got = std::cin.gcount();

      buf.resize(got);
      buf.shrink_to_fit();

      LLVMFuzzerTestOneInput(buf.data(), got);
      }
   }

#elif defined(BOTAN_FUZZER_IS_KLEE)

#include <klee/klee.h>

int main(int argc, char* argv[])
   {
   LLVMFuzzerInitialize(&argc, &argv);

   uint8_t input[max_fuzzer_input_size] = { 0 };
   klee_make_symbolic(&input, sizeof(input), "input");

   size_t input_len = klee_range(0, sizeof(input), "input_len");

   LLVMFuzzerTestOneInput(input, input_len);
   }

#endif

#endif