deserialize.cpp raw

   1  // Copyright (c) 2009-2021 The Limenka 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  
  37  using node::SnapshotMetadata;
  38  
  39  namespace {
  40  const BasicTestingSetup* g_setup;
  41  } // namespace
  42  
  43  void initialize_deserialize()
  44  {
  45      static const auto testing_setup = MakeNoLogFileContext<>();
  46      g_setup = testing_setup.get();
  47  }
  48  
  49  #define FUZZ_TARGET_DESERIALIZE(name, code)                \
  50      FUZZ_TARGET(name, .init = initialize_deserialize)         \
  51      {                                                      \
  52          try {                                              \
  53              code                                           \
  54          } catch (const invalid_fuzzing_input_exception&) { \
  55          }                                                  \
  56      }
  57  
  58  namespace {
  59  
  60  struct invalid_fuzzing_input_exception : public std::exception {
  61  };
  62  
  63  template <typename T, typename P>
  64  DataStream Serialize(const T& obj, const P& params)
  65  {
  66      DataStream ds{};
  67      ds << params(obj);
  68      return ds;
  69  }
  70  
  71  template <typename T, typename P>
  72  T Deserialize(DataStream&& ds, const P& params)
  73  {
  74      T obj;
  75      ds >> params(obj);
  76      return obj;
  77  }
  78  
  79  template <typename T, typename P>
  80  void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj, const P& params)
  81  {
  82      DataStream ds{buffer};
  83      try {
  84          ds >> params(obj);
  85      } catch (const std::ios_base::failure&) {
  86          throw invalid_fuzzing_input_exception();
  87      }
  88      assert(buffer.empty() || !Serialize(obj, params).empty());
  89  }
  90  
  91  template <typename T>
  92  DataStream Serialize(const T& obj)
  93  {
  94      DataStream ds{};
  95      ds << obj;
  96      return ds;
  97  }
  98  
  99  template <typename T>
 100  T Deserialize(DataStream ds)
 101  {
 102      T obj;
 103      ds >> obj;
 104      return obj;
 105  }
 106  
 107  template <typename T>
 108  void DeserializeFromFuzzingInput(FuzzBufferType buffer, T&& obj)
 109  {
 110      DataStream ds{buffer};
 111      try {
 112          ds >> 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
 337