Skip to content

Commit 236cf36

Browse files
committed
merge bitcoin#22734: Avoid crash on corrupt data, Force Check after deserialize
1 parent 2420ac9 commit 236cf36

File tree

6 files changed

+48
-50
lines changed

6 files changed

+48
-50
lines changed

src/Makefile.test.include

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,6 @@ test_fuzz_fuzz_SOURCES = \
263263
test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \
264264
test/fuzz/crypto_poly1305.cpp \
265265
test/fuzz/cuckoocache.cpp \
266-
test/fuzz/data_stream.cpp \
267266
test/fuzz/decode_tx.cpp \
268267
test/fuzz/descriptor_parse.cpp \
269268
test/fuzz/deserialize.cpp \

src/addrman.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,12 @@ void CAddrMan::Unserialize(Stream& s_)
389389
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
390390
}
391391

392-
Check();
392+
const int check_code{ForceCheckAddrman()};
393+
if (check_code != 0) {
394+
throw std::ios_base::failure(strprintf(
395+
"Corrupt data. Consistency check failed with code %s",
396+
check_code));
397+
}
393398
}
394399

395400
// explicit instantiation
@@ -764,14 +769,26 @@ CAddrInfo CAddrMan::Select_(bool newOnly) const
764769
}
765770
}
766771

767-
int CAddrMan::Check_() const
772+
void CAddrMan::Check() const
768773
{
769774
AssertLockHeld(cs);
770-
LogPrint(BCLog::ADDRMAN, "Addrman checks started: new %i, tried %i, total %u\n", nNew, nTried, vRandom.size());
771775

772776
// Run consistency checks 1 in m_consistency_check_ratio times if enabled
773-
if (m_consistency_check_ratio == 0) return 0;
774-
if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return 0;
777+
if (m_consistency_check_ratio == 0) return;
778+
if (insecure_rand.randrange(m_consistency_check_ratio) >= 1) return;
779+
780+
const int err{ForceCheckAddrman()};
781+
if (err) {
782+
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
783+
assert(false);
784+
}
785+
}
786+
787+
int CAddrMan::ForceCheckAddrman() const
788+
{
789+
AssertLockHeld(cs);
790+
791+
LogPrint(BCLog::ADDRMAN, "Addrman checks started: new %i, tried %i, total %u\n", nNew, nTried, vRandom.size());
775792

776793
std::unordered_set<int> setTried;
777794
std::unordered_map<int, int> mapNew;

src/addrman.h

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -406,20 +406,12 @@ class CAddrMan
406406
//! Return a random to-be-evicted tried table address.
407407
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
408408

409-
//! Consistency check
410-
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs)
411-
{
412-
AssertLockHeld(cs);
413-
414-
const int err = Check_();
415-
if (err) {
416-
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
417-
assert(false);
418-
}
419-
}
409+
//! Consistency check, taking into account m_consistency_check_ratio. Will std::abort if an inconsistency is detected.
410+
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
420411

421-
//! Perform consistency check. Returns an error code or zero.
422-
int Check_() const EXCLUSIVE_LOCKS_REQUIRED(cs);
412+
//! Perform consistency check, regardless of m_consistency_check_ratio.
413+
//! @returns an error code or zero.
414+
int ForceCheckAddrman() const EXCLUSIVE_LOCKS_REQUIRED(cs);
423415

424416
/**
425417
* Return all or many randomly selected addresses, optionally by network.

src/test/fuzz/addrman.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ void initialize_addrman()
2323
SelectParams(CBaseChainParams::REGTEST);
2424
}
2525

26+
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
27+
{
28+
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
29+
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
30+
CAddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0);
31+
try {
32+
ReadFromStream(addr_man, data_stream);
33+
} catch (const std::exception&) {
34+
}
35+
}
36+
2637
class CAddrManDeterministic : public CAddrMan
2738
{
2839
public:

src/test/fuzz/data_stream.cpp

Lines changed: 0 additions & 30 deletions
This file was deleted.

test/functional/feature_addrman.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def serialize_addrman(
1919
format=1,
2020
lowest_compatible=3,
2121
net_magic="regtest",
22+
bucket_key=1,
2223
len_new=None,
2324
len_tried=None,
2425
mock_checksum=None,
@@ -29,7 +30,7 @@ def serialize_addrman(
2930
r = MAGIC_BYTES[net_magic]
3031
r += struct.pack("B", format)
3132
r += struct.pack("B", INCOMPATIBILITY_BASE + lowest_compatible)
32-
r += ser_uint256(1)
33+
r += ser_uint256(bucket_key)
3334
r += struct.pack("i", len_new or len(new))
3435
r += struct.pack("i", len_tried or len(tried))
3536
ADDRMAN_NEW_BUCKET_COUNT = 1 << 10
@@ -119,6 +120,14 @@ def run_test(self):
119120
match=ErrorMatch.FULL_REGEX,
120121
)
121122

123+
self.log.info("Check that corrupt addrman cannot be read (failed check)")
124+
self.stop_node(0)
125+
write_addrman(peers_dat, bucket_key=0)
126+
self.nodes[0].assert_start_raises_init_error(
127+
expected_msg=init_error("Corrupt data. Consistency check failed with code -16: .*"),
128+
match=ErrorMatch.FULL_REGEX,
129+
)
130+
122131
self.log.info("Check that missing addrman is recreated")
123132
self.stop_node(0)
124133
os.remove(peers_dat)

0 commit comments

Comments
 (0)