From fae5c633dc05a045aaac370b383e4799cb0e0590 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 18 Aug 2021 09:07:18 +0200 Subject: [PATCH 1/4] move-only: Move CAddrMan::Check to cpp file This speeds up compilation of the whole program because the included header file is smaller. Can be reviewed with --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space --- src/addrman.cpp | 11 +++++++++++ src/addrman.h | 11 +---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index a1e8cb1bf1..e3f370134f 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -743,6 +743,17 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const } } +void CAddrMan::Check() const +{ + AssertLockHeld(cs); + + const int err = Check_(); + if (err) { + LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); + assert(false); + } +} + int CAddrMan::Check_() const { AssertLockHeld(cs); diff --git a/src/addrman.h b/src/addrman.h index 0885231ebc..ca291d60ab 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -392,16 +392,7 @@ private: CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); //! Consistency check - void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs) - { - AssertLockHeld(cs); - - const int err = Check_(); - if (err) { - LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); - assert(false); - } - } + void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs); //! Perform consistency check. Returns an error code or zero. int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs); From fa298971e6890715e2b0b93f2a7f445d32d6622f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 18 Aug 2021 09:17:06 +0200 Subject: [PATCH 2/4] Refactor: Turn the internal addrman check helper into a forced check --- src/addrman.cpp | 12 ++++++------ src/addrman.h | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index e3f370134f..a6f38075d8 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -747,21 +747,21 @@ void CAddrMan::Check() const { AssertLockHeld(cs); - const int err = Check_(); + // Run consistency checks 1 in m_consistency_check_ratio times if enabled + if (m_consistency_check_ratio == 0) return; + if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return; + + const int err{ForceCheckAddrman()}; if (err) { LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); assert(false); } } -int CAddrMan::Check_() const +int CAddrMan::ForceCheckAddrman() const { AssertLockHeld(cs); - // Run consistency checks 1 in m_consistency_check_ratio times if enabled - if (m_consistency_check_ratio == 0) return 0; - if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return 0; - LogPrint(BCLog::ADDRMAN, "Addrman checks started: new %i, tried %i, total %u\n", nNew, nTried, vRandom.size()); std::unordered_set setTried; diff --git a/src/addrman.h b/src/addrman.h index ca291d60ab..7dd8528bef 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -391,11 +391,12 @@ private: //! Return a random to-be-evicted tried table address. CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); - //! Consistency check + //! Consistency check, taking into account m_consistency_check_ratio. Will std::abort if an inconsistency is detected. void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs); - //! Perform consistency check. Returns an error code or zero. - int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs); + //! Perform consistency check, regardless of m_consistency_check_ratio. + //! @returns an error code or zero. + int ForceCheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs); /** * Return all or many randomly selected addresses, optionally by network. From fa7a883f5a219d5f3c2f992b090db4e6c279db12 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 18 Aug 2021 09:57:56 +0200 Subject: [PATCH 3/4] addrman: Replace assert with throw on corrupt data Assert should only be used for program internal logic errors, not to sanitize external user input. --- src/addrman.cpp | 7 ++++++- test/functional/feature_addrman.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index a6f38075d8..7c6b8fe64d 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -386,7 +386,12 @@ void CAddrMan::Unserialize(Stream& s_) LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost); } - Check(); + const int check_code{ForceCheckAddrman()}; + if (check_code != 0) { + throw std::ios_base::failure(strprintf( + "Corrupt data. Consistency check failed with code %s", + check_code)); + } } // explicit instantiation diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py index 42afd74ac9..55d3e48c64 100755 --- a/test/functional/feature_addrman.py +++ b/test/functional/feature_addrman.py @@ -19,6 +19,7 @@ def serialize_addrman( format=1, lowest_compatible=3, net_magic="regtest", + bucket_key=1, len_new=None, len_tried=None, mock_checksum=None, @@ -29,7 +30,7 @@ def serialize_addrman( r = MAGIC_BYTES[net_magic] r += struct.pack("B", format) r += struct.pack("B", INCOMPATIBILITY_BASE + lowest_compatible) - r += ser_uint256(1) + r += ser_uint256(bucket_key) r += struct.pack("i", len_new or len(new)) r += struct.pack("i", len_tried or len(tried)) ADDRMAN_NEW_BUCKET_COUNT = 1 << 10 @@ -119,6 +120,14 @@ class AddrmanTest(BitcoinTestFramework): match=ErrorMatch.FULL_REGEX, ) + self.log.info("Check that corrupt addrman cannot be read (failed check)") + self.stop_node(0) + write_addrman(peers_dat, bucket_key=0) + self.nodes[0].assert_start_raises_init_error( + expected_msg=init_error("Corrupt data. Consistency check failed with code -16: .*"), + match=ErrorMatch.FULL_REGEX, + ) + self.log.info("Check that missing addrman is recreated") self.stop_node(0) os.remove(peers_dat) From fa3669f72f69662049b55ad1a482b4a0f9f7ae40 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 10 Sep 2021 16:37:03 +0200 Subject: [PATCH 4/4] fuzz: Move all addrman fuzz targets to one file Can be reviewed with --color-moved=dimmed-zebra --- src/Makefile.test.include | 1 - src/test/fuzz/addrman.cpp | 11 +++++++++++ src/test/fuzz/data_stream.cpp | 30 ------------------------------ 3 files changed, 11 insertions(+), 31 deletions(-) delete mode 100644 src/test/fuzz/data_stream.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index a85a359960..be63214c23 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -232,7 +232,6 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \ test/fuzz/crypto_poly1305.cpp \ test/fuzz/cuckoocache.cpp \ - test/fuzz/data_stream.cpp \ test/fuzz/decode_tx.cpp \ test/fuzz/descriptor_parse.cpp \ test/fuzz/deserialize.cpp \ diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 95c5a99c1b..45ee778b87 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -23,6 +23,17 @@ void initialize_addrman() SelectParams(CBaseChainParams::REGTEST); } +FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); + CAddrMan addr_man(/* asmap */ std::vector(), /* deterministic */ false, /* consistency_check_ratio */ 0); + try { + ReadFromStream(addr_man, data_stream); + } catch (const std::exception&) { + } +} + class CAddrManDeterministic : public CAddrMan { public: diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp deleted file mode 100644 index 323090e041..0000000000 --- a/src/test/fuzz/data_stream.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2020-2021 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -void initialize_data_stream_addr_man() -{ - static const auto testing_setup = MakeNoLogFileContext<>(); -} - -FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man) -{ - FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); - CAddrMan addr_man(/* asmap */ std::vector(), /* deterministic */ false, /* consistency_check_ratio */ 0); - try { - ReadFromStream(addr_man, data_stream); - } catch (const std::exception&) { - } -}