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 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, typename P> 115 void AssertEqualAfterSerializeDeserialize(const T& obj, const P& params) 116 { 117 assert(Deserialize<T>(Serialize(obj, params), params) == obj); 118 } 119 template <typename T> 120 void AssertEqualAfterSerializeDeserialize(const T& obj) 121 { 122 assert(Deserialize<T>(Serialize(obj)) == obj); 123 } 124 125 } // namespace 126 127 FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, { 128 BlockFilter block_filter; 129 DeserializeFromFuzzingInput(buffer, block_filter); 130 }) 131 FUZZ_TARGET(addr_info_deserialize, .init = initialize_deserialize) 132 { 133 FuzzedDataProvider fdp{buffer.data(), buffer.size()}; 134 (void)ConsumeDeserializable<AddrInfo>(fdp, ConsumeDeserializationParams<CAddress::SerParams>(fdp)); 135 } 136 FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, { 137 CBlockFileInfo block_file_info; 138 DeserializeFromFuzzingInput(buffer, block_file_info); 139 }) 140 FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, { 141 CBlockHeaderAndShortTxIDs block_header_and_short_txids; 142 DeserializeFromFuzzingInput(buffer, block_header_and_short_txids); 143 }) 144 FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, { 145 CFeeRate fee_rate; 146 DeserializeFromFuzzingInput(buffer, fee_rate); 147 AssertEqualAfterSerializeDeserialize(fee_rate); 148 }) 149 FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, { 150 CMerkleBlock merkle_block; 151 DeserializeFromFuzzingInput(buffer, merkle_block); 152 }) 153 FUZZ_TARGET_DESERIALIZE(out_point_deserialize, { 154 COutPoint out_point; 155 DeserializeFromFuzzingInput(buffer, out_point); 156 AssertEqualAfterSerializeDeserialize(out_point); 157 }) 158 FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, { 159 CPartialMerkleTree partial_merkle_tree; 160 DeserializeFromFuzzingInput(buffer, partial_merkle_tree); 161 }) 162 FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, { 163 CPubKey pub_key; 164 DeserializeFromFuzzingInput(buffer, pub_key); 165 AssertEqualAfterSerializeDeserialize(pub_key); 166 }) 167 FUZZ_TARGET_DESERIALIZE(script_deserialize, { 168 CScript script; 169 DeserializeFromFuzzingInput(buffer, script); 170 }) 171 FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, { 172 CTxIn tx_in; 173 DeserializeFromFuzzingInput(buffer, tx_in); 174 AssertEqualAfterSerializeDeserialize(tx_in); 175 }) 176 FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, { 177 FlatFilePos flat_file_pos; 178 DeserializeFromFuzzingInput(buffer, flat_file_pos); 179 AssertEqualAfterSerializeDeserialize(flat_file_pos); 180 }) 181 FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, { 182 KeyOriginInfo key_origin_info; 183 DeserializeFromFuzzingInput(buffer, key_origin_info); 184 AssertEqualAfterSerializeDeserialize(key_origin_info); 185 }) 186 FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, { 187 PartiallySignedTransaction partially_signed_transaction; 188 DeserializeFromFuzzingInput(buffer, partially_signed_transaction); 189 }) 190 FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, { 191 PrefilledTransaction prefilled_transaction; 192 DeserializeFromFuzzingInput(buffer, prefilled_transaction); 193 }) 194 FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, { 195 PSBTInput psbt_input; 196 DeserializeFromFuzzingInput(buffer, psbt_input); 197 }) 198 FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, { 199 PSBTOutput psbt_output; 200 DeserializeFromFuzzingInput(buffer, psbt_output); 201 }) 202 FUZZ_TARGET_DESERIALIZE(block_deserialize, { 203 CBlock block; 204 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block)); 205 }) 206 FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, { 207 CBlockLocator bl; 208 DeserializeFromFuzzingInput(buffer, bl); 209 }) 210 FUZZ_TARGET_DESERIALIZE(blockmerkleroot, { 211 CBlock block; 212 DeserializeFromFuzzingInput(buffer, TX_WITH_WITNESS(block)); 213 bool mutated; 214 BlockMerkleRoot(block, &mutated); 215 }) 216 FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { 217 CBlockHeader bh; 218 DeserializeFromFuzzingInput(buffer, bh); 219 }) 220 FUZZ_TARGET_DESERIALIZE(txundo_deserialize, { 221 CTxUndo tu; 222 DeserializeFromFuzzingInput(buffer, tu); 223 }) 224 FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, { 225 CBlockUndo bu; 226 DeserializeFromFuzzingInput(buffer, bu); 227 }) 228 FUZZ_TARGET_DESERIALIZE(coins_deserialize, { 229 Coin coin; 230 DeserializeFromFuzzingInput(buffer, coin); 231 }) 232 FUZZ_TARGET(netaddr_deserialize, .init = initialize_deserialize) 233 { 234 FuzzedDataProvider fdp{buffer.data(), buffer.size()}; 235 const auto maybe_na{ConsumeDeserializable<CNetAddr>(fdp, ConsumeDeserializationParams<CNetAddr::SerParams>(fdp))}; 236 if (!maybe_na) return; 237 const CNetAddr& na{*maybe_na}; 238 if (na.IsAddrV1Compatible()) { 239 AssertEqualAfterSerializeDeserialize(na, CNetAddr::V1); 240 } 241 AssertEqualAfterSerializeDeserialize(na, CNetAddr::V2); 242 } 243 FUZZ_TARGET(service_deserialize, .init = initialize_deserialize) 244 { 245 FuzzedDataProvider fdp{buffer.data(), buffer.size()}; 246 const auto ser_params{ConsumeDeserializationParams<CNetAddr::SerParams>(fdp)}; 247 const auto maybe_s{ConsumeDeserializable<CService>(fdp, ser_params)}; 248 if (!maybe_s) return; 249 const CService& s{*maybe_s}; 250 if (s.IsAddrV1Compatible()) { 251 AssertEqualAfterSerializeDeserialize(s, CNetAddr::V1); 252 } 253 AssertEqualAfterSerializeDeserialize(s, CNetAddr::V2); 254 if (ser_params.enc == CNetAddr::Encoding::V1) { 255 assert(s.IsAddrV1Compatible()); 256 } 257 } 258 FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, { 259 CMessageHeader mh; 260 DeserializeFromFuzzingInput(buffer, mh); 261 (void)mh.IsMessageTypeValid(); 262 }) 263 FUZZ_TARGET(address_deserialize, .init = initialize_deserialize) 264 { 265 FuzzedDataProvider fdp{buffer.data(), buffer.size()}; 266 const auto ser_enc{ConsumeDeserializationParams<CAddress::SerParams>(fdp)}; 267 const auto maybe_a{ConsumeDeserializable<CAddress>(fdp, ser_enc)}; 268 if (!maybe_a) return; 269 const CAddress& a{*maybe_a}; 270 // A CAddress in V1 mode will roundtrip 271 // in all 4 formats (v1/v2, network/disk) 272 if (ser_enc.enc == CNetAddr::Encoding::V1) { 273 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK); 274 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK); 275 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK); 276 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK); 277 } else { 278 // A CAddress in V2 mode will roundtrip in both V2 formats, and also in the V1 formats 279 // if it's V1 compatible. 280 if (a.IsAddrV1Compatible()) { 281 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_DISK); 282 AssertEqualAfterSerializeDeserialize(a, CAddress::V1_NETWORK); 283 } 284 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_NETWORK); 285 AssertEqualAfterSerializeDeserialize(a, CAddress::V2_DISK); 286 } 287 } 288 FUZZ_TARGET_DESERIALIZE(inv_deserialize, { 289 CInv i; 290 DeserializeFromFuzzingInput(buffer, i); 291 }) 292 FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, { 293 CBloomFilter bf; 294 DeserializeFromFuzzingInput(buffer, bf); 295 }) 296 FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, { 297 CDiskBlockIndex dbi; 298 DeserializeFromFuzzingInput(buffer, dbi); 299 }) 300 FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, { 301 CTxOut to; 302 auto toc = Using<TxOutCompression>(to); 303 DeserializeFromFuzzingInput(buffer, toc); 304 }) 305 FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, { 306 BlockTransactions bt; 307 DeserializeFromFuzzingInput(buffer, bt); 308 }) 309 FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, { 310 BlockTransactionsRequest btr; 311 DeserializeFromFuzzingInput(buffer, btr); 312 }) 313 FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, { 314 auto msg_start = Params().MessageStart(); 315 SnapshotMetadata snapshot_metadata{msg_start}; 316 DeserializeFromFuzzingInput(buffer, snapshot_metadata); 317 }) 318 FUZZ_TARGET_DESERIALIZE(uint160_deserialize, { 319 uint160 u160; 320 DeserializeFromFuzzingInput(buffer, u160); 321 AssertEqualAfterSerializeDeserialize(u160); 322 }) 323 FUZZ_TARGET_DESERIALIZE(uint256_deserialize, { 324 uint256 u256; 325 DeserializeFromFuzzingInput(buffer, u256); 326 AssertEqualAfterSerializeDeserialize(u256); 327 }) 328 // Classes intentionally not covered in this file since their deserialization code is 329 // fuzzed elsewhere: 330 // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp 331 // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp