From dfc7f622c55cb53dc8aa04b058d8df841f03f3fa Mon Sep 17 00:00:00 2001 From: Alec Muffett Date: Mon, 1 Jun 2026 04:33:47 +0400 Subject: [PATCH] a4-ff: add Packet prefix-cap boundary tests + fix core_test link order Add packet_test.cpp covering MAX_PREFIX_LENGTH (16) boundary behaviour of the Packet read-constructor (Bug-9 hardening): zero/under/at-cap sizes succeed, over-cap throws std::ios_base::failure, and UAF max-size garbage is rejected without crashing. Wire packet_test.cpp into core_test and fix the pre-existing static-link order bug that left core_test (and the bucket of test/ binaries) RED: libltc_coin.a, pulled in transitively, references core::timestamp() after core has already been processed by ld, leaving it undefined. Linking c2pool_merged_mining after core re-injects core via merged_mining PUBLIC dependency, resolving the late reference. CMake-only, runtime-behaviour preserving. ctest core_test: 32/32 pass. --- src/core/test/CMakeLists.txt | 4 +-- src/core/test/packet_test.cpp | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/core/test/packet_test.cpp diff --git a/src/core/test/CMakeLists.txt b/src/core/test/CMakeLists.txt index 5207c767d..784c1b543 100644 --- a/src/core/test/CMakeLists.txt +++ b/src/core/test/CMakeLists.txt @@ -1,6 +1,6 @@ if (BUILD_TESTING AND (GTest_FOUND OR GTEST_FOUND)) - add_executable(core_test pack_test.cpp events_test.cpp chain_test.cpp) - target_link_libraries(core_test PRIVATE GTest::gtest_main core GTest::gtest) + add_executable(core_test pack_test.cpp events_test.cpp chain_test.cpp packet_test.cpp) + target_link_libraries(core_test PRIVATE GTest::gtest_main core c2pool_merged_mining GTest::gtest) include(GoogleTest) include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) diff --git a/src/core/test/packet_test.cpp b/src/core/test/packet_test.cpp new file mode 100644 index 000000000..5b5e5f6d6 --- /dev/null +++ b/src/core/test/packet_test.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// A4 (Bug-9 hardening) cap-boundary tests for the Packet read-constructor. +// The read ctor caps prefix_length at MAX_PREFIX_LENGTH (16) and throws +// std::ios_base::failure on over-cap values, which is how UAF garbage from a +// destroyed m_node (Bug-3-family rapid disconnect/reconnect) is rejected +// without crashing the process. See src/core/packet.hpp. +namespace { + +constexpr size_t kCap = 16; // must track MAX_PREFIX_LENGTH in packet.hpp + +// --- at/under the cap: must succeed and size the prefix exactly --- + +TEST(PacketPrefixCap, ZeroLengthSucceeds) +{ + core::Packet p(0); + EXPECT_EQ(p.prefix.size(), 0u); +} + +TEST(PacketPrefixCap, JustUnderCapSucceeds) +{ + core::Packet p(kCap - 1); + EXPECT_EQ(p.prefix.size(), kCap - 1); +} + +TEST(PacketPrefixCap, AtCapSucceeds) +{ + // Boundary: exactly at the cap is the largest accepted value. + core::Packet p(kCap); + EXPECT_EQ(p.prefix.size(), kCap); +} + +// --- over the cap: must throw cleanly, never resize --- + +TEST(PacketPrefixCap, JustOverCapThrows) +{ + EXPECT_THROW({ core::Packet p(kCap + 1); }, std::ios_base::failure); +} + +TEST(PacketPrefixCap, WayOverCapThrows) +{ + EXPECT_THROW({ core::Packet p(1024); }, std::ios_base::failure); +} + +TEST(PacketPrefixCap, UafGarbageMaxSizeThrows) +{ + // Simulates the garbage size_t read from a freed m_node vector; pre-cap + // this reached resize() and aborted via std::length_error. + EXPECT_THROW({ core::Packet p(std::numeric_limits::max()); }, + std::ios_base::failure); +} + +} // namespace