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