Currently ASan will not detect use-after-free issues for memory allocated by a PoolResource
. This is because ASan is only aware of the memory chunks allocated by PoolResource
but not the individual “sub-chunks” within.
E.g. this test will not produce an ASan error even though the referenced coin has been deallocated:
0diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
1index c46144b34b..aa6ca15ce1 100644
2--- a/src/test/coins_tests.cpp
3+++ b/src/test/coins_tests.cpp
4@@ -508,6 +508,17 @@ BOOST_FIXTURE_TEST_CASE(updatecoins_simulation_test, UpdateTest)
5 BOOST_CHECK(spent_a_duplicate_coinbase);
6 }
7
8+BOOST_AUTO_TEST_CASE(asan_uaf)
9+{
10+ CCoinsMapMemoryResource cache_coins_memory_resource{};
11+ CCoinsMap map(0, SaltedOutpointHasher(/*deterministic=*/true), CCoinsMap::key_equal{}, &cache_coins_memory_resource);
12+ COutPoint outpoint{};
13+ map.emplace(outpoint, Coin{});
14+ auto& coin = map.at(outpoint);
15+ map.erase(outpoint);
16+ coin.coin.nHeight = 1;
17+}
18+
19 BOOST_AUTO_TEST_CASE(ccoins_serialization)
20 {
21 // Good example
Fix this by applying manual ASan poisoning for memory allocated by PoolResource
:
- Newly allocated chunks are poisoned as a whole
- “Sub-chunks” are unpoisoned/re-poisoned during allocation/deallocation
With the poisoning applied, ASan catches the issue in the test above:
0$ ./build_unit/bin/test_bitcoin --run_test="coins_tests/asan_uaf"
1Running 1 test case...
2=================================================================
3==366064==ERROR: AddressSanitizer: use-after-poison on address 0x7f99c3204870 at pc 0x55569dab6f8a bp 0x7ffe0210e4d0 sp 0x7ffe0210e4c8
4READ of size 4 at 0x7f99c3204870 thread T0 (b-test)