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