1 // Copyright (c) 2009-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <addrdb.h>
6 #include <addrman.h>
7 #include <blockencodings.h>
8 #include <blockfilter.h>
9 #include <chain.h>
10 #include <coins.h>
11 #include <compressor.h>
12 #include <consensus/merkle.h>
13 #include <key.h>
14 #include <merkleblock.h>
15 #include <net.h>
16 #include <netbase.h>
17 #include <node/utxo_snapshot.h>
18 #include <optional.h>
19 #include <primitives/block.h>
20 #include <protocol.h>
21 #include <psbt.h>
22 #include <pubkey.h>
23 #include <script/keyorigin.h>
24 #include <streams.h>
25 #include <undo.h>
26 #include <version.h>
27
28 #include <exception>
29 #include <stdexcept>
30 #include <stdint.h>
31 #include <unistd.h>
32
33 #include <vector>
34
35 #include <test/fuzz/fuzz.h>
36
initialize()37 void initialize()
38 {
39 // Fuzzers using pubkey must hold an ECCVerifyHandle.
40 static const ECCVerifyHandle verify_handle;
41 }
42
43 namespace {
44
45 struct invalid_fuzzing_input_exception : public std::exception {
46 };
47
48 template <typename T>
Serialize(const T & obj,const int version=INIT_PROTO_VERSION)49 CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION)
50 {
51 CDataStream ds(SER_NETWORK, version);
52 ds << obj;
53 return ds;
54 }
55
56 template <typename T>
Deserialize(CDataStream ds)57 T Deserialize(CDataStream ds)
58 {
59 T obj;
60 ds >> obj;
61 return obj;
62 }
63
64 template <typename T>
DeserializeFromFuzzingInput(const std::vector<uint8_t> & buffer,T & obj,const Optional<int> protocol_version=nullopt)65 void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj, const Optional<int> protocol_version = nullopt)
66 {
67 CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
68 if (protocol_version) {
69 ds.SetVersion(*protocol_version);
70 } else {
71 try {
72 int version;
73 ds >> version;
74 ds.SetVersion(version);
75 } catch (const std::ios_base::failure&) {
76 throw invalid_fuzzing_input_exception();
77 }
78 }
79 try {
80 ds >> obj;
81 } catch (const std::ios_base::failure&) {
82 throw invalid_fuzzing_input_exception();
83 }
84 assert(buffer.empty() || !Serialize(obj).empty());
85 }
86
87 template <typename T>
AssertEqualAfterSerializeDeserialize(const T & obj,const int version=INIT_PROTO_VERSION)88 void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION)
89 {
90 assert(Deserialize<T>(Serialize(obj, version)) == obj);
91 }
92
93 } // namespace
94
test_one_input(const std::vector<uint8_t> & buffer)95 void test_one_input(const std::vector<uint8_t>& buffer)
96 {
97 try {
98 #if BLOCK_FILTER_DESERIALIZE
99 BlockFilter block_filter;
100 DeserializeFromFuzzingInput(buffer, block_filter);
101 #elif ADDR_INFO_DESERIALIZE
102 CAddrInfo addr_info;
103 DeserializeFromFuzzingInput(buffer, addr_info);
104 #elif BLOCK_FILE_INFO_DESERIALIZE
105 CBlockFileInfo block_file_info;
106 DeserializeFromFuzzingInput(buffer, block_file_info);
107 #elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE
108 CBlockHeaderAndShortTxIDs block_header_and_short_txids;
109 DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
110 #elif FEE_RATE_DESERIALIZE
111 CFeeRate fee_rate;
112 DeserializeFromFuzzingInput(buffer, fee_rate);
113 AssertEqualAfterSerializeDeserialize(fee_rate);
114 #elif MERKLE_BLOCK_DESERIALIZE
115 CMerkleBlock merkle_block;
116 DeserializeFromFuzzingInput(buffer, merkle_block);
117 #elif OUT_POINT_DESERIALIZE
118 COutPoint out_point;
119 DeserializeFromFuzzingInput(buffer, out_point);
120 AssertEqualAfterSerializeDeserialize(out_point);
121 #elif PARTIAL_MERKLE_TREE_DESERIALIZE
122 CPartialMerkleTree partial_merkle_tree;
123 DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
124 #elif PUB_KEY_DESERIALIZE
125 CPubKey pub_key;
126 DeserializeFromFuzzingInput(buffer, pub_key);
127 // TODO: The following equivalence should hold for CPubKey? Fix.
128 // AssertEqualAfterSerializeDeserialize(pub_key);
129 #elif SCRIPT_DESERIALIZE
130 CScript script;
131 DeserializeFromFuzzingInput(buffer, script);
132 #elif SUB_NET_DESERIALIZE
133 CSubNet sub_net_1;
134 DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION);
135 AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION);
136 CSubNet sub_net_2;
137 DeserializeFromFuzzingInput(buffer, sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
138 AssertEqualAfterSerializeDeserialize(sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
139 CSubNet sub_net_3;
140 DeserializeFromFuzzingInput(buffer, sub_net_3);
141 AssertEqualAfterSerializeDeserialize(sub_net_3, INIT_PROTO_VERSION | ADDRV2_FORMAT);
142 #elif TX_IN_DESERIALIZE
143 CTxIn tx_in;
144 DeserializeFromFuzzingInput(buffer, tx_in);
145 AssertEqualAfterSerializeDeserialize(tx_in);
146 #elif FLAT_FILE_POS_DESERIALIZE
147 FlatFilePos flat_file_pos;
148 DeserializeFromFuzzingInput(buffer, flat_file_pos);
149 AssertEqualAfterSerializeDeserialize(flat_file_pos);
150 #elif KEY_ORIGIN_INFO_DESERIALIZE
151 KeyOriginInfo key_origin_info;
152 DeserializeFromFuzzingInput(buffer, key_origin_info);
153 AssertEqualAfterSerializeDeserialize(key_origin_info);
154 #elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE
155 PartiallySignedTransaction partially_signed_transaction;
156 DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
157 #elif PREFILLED_TRANSACTION_DESERIALIZE
158 PrefilledTransaction prefilled_transaction;
159 DeserializeFromFuzzingInput(buffer, prefilled_transaction);
160 #elif PSBT_INPUT_DESERIALIZE
161 PSBTInput psbt_input;
162 DeserializeFromFuzzingInput(buffer, psbt_input);
163 #elif PSBT_OUTPUT_DESERIALIZE
164 PSBTOutput psbt_output;
165 DeserializeFromFuzzingInput(buffer, psbt_output);
166 #elif BLOCK_DESERIALIZE
167 CBlock block;
168 DeserializeFromFuzzingInput(buffer, block);
169 #elif BLOCKLOCATOR_DESERIALIZE
170 CBlockLocator bl;
171 DeserializeFromFuzzingInput(buffer, bl);
172 #elif BLOCKMERKLEROOT
173 CBlock block;
174 DeserializeFromFuzzingInput(buffer, block);
175 bool mutated;
176 BlockMerkleRoot(block, &mutated);
177 #elif ADDRMAN_DESERIALIZE
178 CAddrMan am;
179 DeserializeFromFuzzingInput(buffer, am);
180 #elif BLOCKHEADER_DESERIALIZE
181 CBlockHeader bh;
182 DeserializeFromFuzzingInput(buffer, bh);
183 #elif BANENTRY_DESERIALIZE
184 CBanEntry be;
185 DeserializeFromFuzzingInput(buffer, be);
186 #elif TXUNDO_DESERIALIZE
187 CTxUndo tu;
188 DeserializeFromFuzzingInput(buffer, tu);
189 #elif BLOCKUNDO_DESERIALIZE
190 CBlockUndo bu;
191 DeserializeFromFuzzingInput(buffer, bu);
192 #elif COINS_DESERIALIZE
193 Coin coin;
194 DeserializeFromFuzzingInput(buffer, coin);
195 #elif NETADDR_DESERIALIZE
196 CNetAddr na;
197 DeserializeFromFuzzingInput(buffer, na);
198 if (na.IsAddrV1Compatible()) {
199 AssertEqualAfterSerializeDeserialize(na);
200 }
201 AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT);
202 #elif SERVICE_DESERIALIZE
203 CService s;
204 DeserializeFromFuzzingInput(buffer, s);
205 if (s.IsAddrV1Compatible()) {
206 AssertEqualAfterSerializeDeserialize(s);
207 }
208 AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT);
209 CService s1;
210 DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION);
211 AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION);
212 assert(s1.IsAddrV1Compatible());
213 CService s2;
214 DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
215 AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT);
216 #elif MESSAGEHEADER_DESERIALIZE
217 CMessageHeader mh;
218 DeserializeFromFuzzingInput(buffer, mh);
219 (void)mh.IsCommandValid();
220 #elif ADDRESS_DESERIALIZE
221 CAddress a;
222 DeserializeFromFuzzingInput(buffer, a);
223 #elif INV_DESERIALIZE
224 CInv i;
225 DeserializeFromFuzzingInput(buffer, i);
226 #elif BLOOMFILTER_DESERIALIZE
227 CBloomFilter bf;
228 DeserializeFromFuzzingInput(buffer, bf);
229 #elif DISKBLOCKINDEX_DESERIALIZE
230 CDiskBlockIndex dbi;
231 DeserializeFromFuzzingInput(buffer, dbi);
232 #elif TXOUTCOMPRESSOR_DESERIALIZE
233 CTxOut to;
234 auto toc = Using<TxOutCompression>(to);
235 DeserializeFromFuzzingInput(buffer, toc);
236 #elif BLOCKTRANSACTIONS_DESERIALIZE
237 BlockTransactions bt;
238 DeserializeFromFuzzingInput(buffer, bt);
239 #elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
240 BlockTransactionsRequest btr;
241 DeserializeFromFuzzingInput(buffer, btr);
242 #elif SNAPSHOTMETADATA_DESERIALIZE
243 SnapshotMetadata snapshot_metadata;
244 DeserializeFromFuzzingInput(buffer, snapshot_metadata);
245 #elif UINT160_DESERIALIZE
246 uint160 u160;
247 DeserializeFromFuzzingInput(buffer, u160);
248 AssertEqualAfterSerializeDeserialize(u160);
249 #elif UINT256_DESERIALIZE
250 uint256 u256;
251 DeserializeFromFuzzingInput(buffer, u256);
252 AssertEqualAfterSerializeDeserialize(u256);
253 #else
254 #error Need at least one fuzz target to compile
255 #endif
256 // Classes intentionally not covered in this file since their deserialization code is
257 // fuzzed elsewhere:
258 // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
259 // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp
260 } catch (const invalid_fuzzing_input_exception&) {
261 }
262 }
263