MCPcopy Create free account
hub / github.com/ElementsProject/lightning / LLVMFuzzerCustomMutator

Function LLVMFuzzerCustomMutator

tests/fuzz/fuzz-bolt11.c:90–144  ·  view source on GitHub ↗

We use a custom mutator to produce an input corpus that consists entirely of correctly encoded bech32 strings. This enables us to efficiently fuzz the bolt11 decoding logic without the fuzzer getting stuck on fuzzing the bech32 decoding/encoding logic. This custom mutator does the following things: 1. Attempt to bech32 decode the given input (returns the encoded dummy invoice on failure). 2. Muta

Source from the content-addressed store, hash-verified

88// 4. Write the encoded result to `fuzz_data` if its size does not exceed
89// `max_size`, otherwise return the encoded dummy invoice.
90size_t LLVMFuzzerCustomMutator(uint8_t *fuzz_data, size_t size, size_t max_size,
91 unsigned int seed)
92{
93 // A minimum size of 9 prevents hrp_maxlen <= 0 and data_maxlen <= 0.
94 if (size < 9)
95 return initial_input(fuzz_data, size, max_size);
96
97 // Interpret fuzz input as string (ensure it's null terminated).
98 char *input = to_string(tmpctx, fuzz_data, size);
99
100 // Attempt to bech32 decode the input.
101 size_t hrp_maxlen = strlen(input) - 6;
102 char *hrp = tal_arr(tmpctx, char, hrp_maxlen);
103 size_t data_maxlen = strlen(input) - 8;
104 u5 *data = tal_arr(tmpctx, u5, data_maxlen);
105 size_t datalen = 0;
106 if (bech32_decode(hrp, data, &datalen, input, (size_t)-1) !=
107 BECH32_ENCODING_BECH32) {
108 // Decoding failed, this should only happen when starting from
109 // an empty corpus.
110 return initial_input(fuzz_data, size, max_size);
111 }
112
113 // Mutate either the hrp or data. Given the same seed, the same
114 // mutation is performed.
115 srand(seed);
116 switch (rand() % 2) {
117 case 0: { // Mutate hrp and ensure it's still null terminated.
118 size_t new_len = LLVMFuzzerMutate((uint8_t *)hrp, strlen(hrp),
119 hrp_maxlen - 1);
120 hrp[new_len] = '\0';
121 break;
122 }
123 case 1: // Mutate data and re-assign datalen.
124 datalen =
125 LLVMFuzzerMutate((uint8_t *)data, datalen, data_maxlen);
126 break;
127 }
128
129 // Encode the mutated input.
130 char *output = tal_arr(tmpctx, char, strlen(hrp) + datalen + 8);
131 if (!bech32_encode(output, hrp, data, datalen, (size_t)-1,
132 BECH32_ENCODING_BECH32)) {
133 return initial_input(fuzz_data, size, max_size);
134 }
135
136 // Write the result into `fuzz_data`.
137 size_t output_len = strlen(output);
138 if (output_len > max_size)
139 return initial_input(fuzz_data, size, max_size);
140
141 memcpy(fuzz_data, output, output_len);
142 clean_tmpctx();
143 return output_len;
144}
145
146size_t LLVMFuzzerCustomCrossOver(const u8 *in1, size_t in1_size, const u8 *in2,
147 size_t in2_size, u8 *out, size_t max_out_size,

Callers

nothing calls this directly

Calls 6

LLVMFuzzerMutateFunction · 0.85
clean_tmpctxFunction · 0.85
initial_inputFunction · 0.70
to_stringFunction · 0.70
bech32_decodeFunction · 0.50
bech32_encodeFunction · 0.50

Tested by

no test coverage detected