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