deserialize.cpp raw

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