/ src / test / fuzz / deserialize.cpp
deserialize.cpp
  1  // Copyright (c) 2009-2021 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 <addrman_impl.h>
  8  #include <blockencodings.h>
  9  #include <blockfilter.h>
 10  #include <chain.h>
 11  #include <coins.h>
 12  #include <common/args.h>
 13  #include <compressor.h>
 14  #include <consensus/merkle.h>
 15  #include <key.h>
 16  #include <merkleblock.h>
 17  #include <net.h>
 18  #include <netbase.h>
 19  #include <netgroup.h>
 20  #include <node/utxo_snapshot.h>
 21  #include <primitives/block.h>
 22  #include <protocol.h>
 23  #include <psbt.h>
 24  #include <pubkey.h>
 25  #include <script/keyorigin.h>
 26  #include <streams.h>
 27  #include <test/fuzz/fuzz.h>
 28  #include <test/fuzz/util.h>
 29  #include <test/util/setup_common.h>
 30  #include <undo.h>
 31  
 32  #include <exception>
 33  #include <optional>
 34  #include <stdexcept>
 35  #include <stdint.h>
 36  #include <unistd.h>
 37  
 38  using node::SnapshotMetadata;
 39  
 40  namespace {
 41  const BasicTestingSetup* g_setup;
 42  } // namespace
 43  
 44  void initialize_deserialize()
 45  {
 46      static const auto testing_setup = MakeNoLogFileContext<>();
 47      g_setup = testing_setup.get();
 48  }
 49  
 50  #define FUZZ_TARGET_DESERIALIZE(name, code)                \
 51      FUZZ_TARGET(name, .init = initialize_deserialize)         \
 52      {                                                      \
 53          try {                                              \
 54              code                                           \
 55          } catch (const invalid_fuzzing_input_exception&) { \
 56          }                                                  \
 57      }
 58  
 59  namespace {
 60  
 61  struct invalid_fuzzing_input_exception : public std::exception {
 62  };
 63  
 64  template <typename T, typename P>
 65  DataStream Serialize(const T& obj, const P& params)
 66  {
 67      DataStream ds{};
 68      ds << params(obj);
 69      return ds;
 70  }
 71  
 72  template <typename T, typename P>
 73  T Deserialize(DataStream&& ds, const P& params)
 74  {
 75      T obj;
 76      ds >> params(obj);
 77      return obj;
 78  }
 79  
 80  template <typename T, typename P>
 81  void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
 82  {
 83      DataStream ds{buffer};
 84      try {
 85          ds >> params(obj);
 86      } catch (const std::ios_base::failure&) {
 87          throw invalid_fuzzing_input_exception();
 88      }
 89      assert(buffer.empty() || !Serialize(obj, params).empty());
 90  }
 91  
 92  template <typename T>
 93  DataStream Serialize(const T& obj)
 94  {
 95      DataStream ds{};
 96      ds << obj;
 97      return ds;
 98  }
 99  
100  template <typename T>
101  T Deserialize(DataStream ds)
102  {
103      T obj;
104      ds >> obj;
105      return obj;
106  }
107  
108  template <typename T>
109  void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj)
110  {
111      DataStream ds{buffer};
112      try {
113          ds >> obj;
114      } catch (const std::ios_base::failure&) {
115          throw invalid_fuzzing_input_exception();
116      }
117      assert(buffer.empty() || !Serialize(obj).empty());
118  }
119  
120  template <typename T, typename P>
121  void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params)
122  {
123      assert(Deserialize<T>(Serialize(obj, params), params) == obj);
124  }
125  template <typename T>
126  void AssertEqualAfterSerializeDeserialize(const T& obj)
127  {
128      assert(Deserialize<T>(Serialize(obj)) == obj);
129  }
130  
131  } // namespace
132  
133  FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, {
134      BlockFilter block_filter;
135      DeserializeFromFuzzingInput(buffer, block_filter);
136  })
137  FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize)
138  {
139      FuzzedDataProvider fdp{buffer.data(), buffer.size()};
140      (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp));
141  }
142  FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, {
143      CBlockFileInfo block_file_info;
144      DeserializeFromFuzzingInput(buffer, block_file_info);
145  })
146  FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, {
147      CBlockHeaderAndShortTxIDs block_header_and_short_txids;
148      DeserializeFromFuzzingInput(buffer, block_header_and_short_txids);
149  })
150  FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, {
151      CFeeRate fee_rate;
152      DeserializeFromFuzzingInput(buffer, fee_rate);
153      AssertEqualAfterSerializeDeserialize(fee_rate);
154  })
155  FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, {
156      CMerkleBlock merkle_block;
157      DeserializeFromFuzzingInput(buffer, merkle_block);
158  })
159  FUZZ_TARGET_DESERIALIZE(out_point_deserialize, {
160      COutPoint out_point;
161      DeserializeFromFuzzingInput(buffer, out_point);
162      AssertEqualAfterSerializeDeserialize(out_point);
163  })
164  FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, {
165      CPartialMerkleTree partial_merkle_tree;
166      DeserializeFromFuzzingInput(buffer, partial_merkle_tree);
167  })
168  FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, {
169      CPubKey pub_key;
170      DeserializeFromFuzzingInput(buffer, pub_key);
171      AssertEqualAfterSerializeDeserialize(pub_key);
172  })
173  FUZZ_TARGET_DESERIALIZE(script_deserialize, {
174      CScript script;
175      DeserializeFromFuzzingInput(buffer, script);
176  })
177  FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, {
178      CTxIn tx_in;
179      DeserializeFromFuzzingInput(buffer, tx_in);
180      AssertEqualAfterSerializeDeserialize(tx_in);
181  })
182  FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, {
183      FlatFilePos flat_file_pos;
184      DeserializeFromFuzzingInput(buffer, flat_file_pos);
185      AssertEqualAfterSerializeDeserialize(flat_file_pos);
186  })
187  FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, {
188      KeyOriginInfo key_origin_info;
189      DeserializeFromFuzzingInput(buffer, key_origin_info);
190      AssertEqualAfterSerializeDeserialize(key_origin_info);
191  })
192  FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, {
193      PartiallySignedTransaction partially_signed_transaction;
194      DeserializeFromFuzzingInput(buffer, partially_signed_transaction);
195  })
196  FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, {
197      PrefilledTransaction prefilled_transaction;
198      DeserializeFromFuzzingInput(buffer, prefilled_transaction);
199  })
200  FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, {
201      PSBTInput psbt_input;
202      DeserializeFromFuzzingInput(buffer, psbt_input);
203  })
204  FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, {
205      PSBTOutput psbt_output;
206      DeserializeFromFuzzingInput(buffer, psbt_output);
207  })
208  FUZZ_TARGET_DESERIALIZE(block_deserialize, {
209      CBlock block;
210      DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
211  })
212  FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, {
213      CBlockLocator bl;
214      DeserializeFromFuzzingInput(buffer, bl);
215  })
216  FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
217      CBlock block;
218      DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block));
219      bool mutated;
220      BlockMerkleRoot(block, &mutated);
221  })
222  FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, {
223      CBlockHeader bh;
224      DeserializeFromFuzzingInput(buffer, bh);
225  })
226  FUZZ_TARGET_DESERIALIZE(txundo_deserialize, {
227      CTxUndo tu;
228      DeserializeFromFuzzingInput(buffer, tu);
229  })
230  FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, {
231      CBlockUndo bu;
232      DeserializeFromFuzzingInput(buffer, bu);
233  })
234  FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
235      Coin coin;
236      DeserializeFromFuzzingInput(buffer, coin);
237  })
238  FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize)
239  {
240      FuzzedDataProvider fdp{buffer.data(), buffer.size()};
241      const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))};
242      if (!maybe_na) return;
243      const CNetAddr& na{*maybe_na};
244      if (na.IsAddrV1Compatible()) {
245          AssertEqualAfterSerializeDeserialize(na, CNetAddr::V1);
246      }
247      AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2);
248  }
249  FUZZ_TARGET(service_deserialize, .init = initialize_deserialize)
250  {
251      FuzzedDataProvider fdp{buffer.data(), buffer.size()};
252      const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)};
253      const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)};
254      if (!maybe_s) return;
255      const CService& s{*maybe_s};
256      if (s.IsAddrV1Compatible()) {
257          AssertEqualAfterSerializeDeserialize(s, CNetAddr::V1);
258      }
259      AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2);
260      if (ser_params.enc == CNetAddr::Encoding::V1) {
261          assert(s.IsAddrV1Compatible());
262      }
263  }
264  FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, {
265      CMessageHeader mh;
266      DeserializeFromFuzzingInput(buffer, mh);
267      (void)mh.IsCommandValid();
268  })
269  FUZZ_TARGET(address_deserialize, .init = initialize_deserialize)
270  {
271      FuzzedDataProvider fdp{buffer.data(), buffer.size()};
272      const auto ser_enc{ConsumeDeserializationParams<CAddress::SerParams>(fdp)};
273      const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, ser_enc)};
274      if (!maybe_a) return;
275      const CAddress& a{*maybe_a};
276      // A CAddress in V1 mode will roundtrip
277      // in all 4 formats (v1/v2, network/disk)
278      if (ser_enc.enc == CNetAddr::Encoding::V1) {
279          AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
280          AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
281          AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
282          AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
283      } else {
284          // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats
285          // if it's V1 compatible.
286          if (a.IsAddrV1Compatible()) {
287              AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK);
288              AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK);
289          }
290          AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK);
291          AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK);
292      }
293  }
294  FUZZ_TARGET_DESERIALIZE(inv_deserialize, {
295      CInv i;
296      DeserializeFromFuzzingInput(buffer, i);
297  })
298  FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, {
299      CBloomFilter bf;
300      DeserializeFromFuzzingInput(buffer, bf);
301  })
302  FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, {
303      CDiskBlockIndex dbi;
304      DeserializeFromFuzzingInput(buffer, dbi);
305  })
306  FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, {
307      CTxOut to;
308      auto toc = Using<TxOutCompression>(to);
309      DeserializeFromFuzzingInput(buffer, toc);
310  })
311  FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, {
312      BlockTransactions bt;
313      DeserializeFromFuzzingInput(buffer, bt);
314  })
315  FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, {
316      BlockTransactionsRequest btr;
317      DeserializeFromFuzzingInput(buffer, btr);
318  })
319  FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, {
320      SnapshotMetadata snapshot_metadata;
321      DeserializeFromFuzzingInput(buffer, snapshot_metadata);
322  })
323  FUZZ_TARGET_DESERIALIZE(uint160_deserialize, {
324      uint160 u160;
325      DeserializeFromFuzzingInput(buffer, u160);
326      AssertEqualAfterSerializeDeserialize(u160);
327  })
328  FUZZ_TARGET_DESERIALIZE(uint256_deserialize, {
329      uint256 u256;
330      DeserializeFromFuzzingInput(buffer, u256);
331      AssertEqualAfterSerializeDeserialize(u256);
332  })
333  // Classes intentionally not covered in this file since their deserialization code is
334  // fuzzed elsewhere:
335  // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp
336  // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp