tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit 80d6f2920e28ccbc8dc0eb767bf22b4ae9ad0123
parent beb3a5fe1526d58b92596fec235c4c41e2698850
Author: David Goulet <dgoulet@torproject.org>
Date:   Wed, 18 Dec 2024 11:28:59 -0500

test: Add HS cache OOM cleanup test

Part of #40996

Signed-off-by: David Goulet <dgoulet@torproject.org>

Diffstat:
Msrc/feature/hs/hs_cache.c | 16+++++++++++++++-
Msrc/feature/hs/hs_cache.h | 5+++++
Msrc/test/test_hs_cache.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c @@ -68,7 +68,7 @@ store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc) } /** Query our cache and return the entry or NULL if not found. */ -static hs_cache_dir_descriptor_t * +STATIC hs_cache_dir_descriptor_t * lookup_v3_desc_as_dir(const uint8_t *key) { tor_assert(key); @@ -1258,3 +1258,17 @@ hs_cache_increment_allocation(size_t n) } } } + +#ifdef TOR_UNIT_TESTS + +/** Test only: Set the downloaded counter value of a HSDir cache entry. */ +void +dir_set_downloaded(const ed25519_public_key_t *pk, uint64_t value) +{ + hs_cache_dir_descriptor_t *entry = lookup_v3_desc_as_dir(pk->pubkey); + if (entry) { + entry->n_downloaded = value; + } +} + +#endif /* TOR_UNIT_TESTS */ diff --git a/src/feature/hs/hs_cache.h b/src/feature/hs/hs_cache.h @@ -153,10 +153,15 @@ STATIC size_t cache_clean_v3_as_dir(time_t now, time_t global_cutoff); STATIC size_t cache_clean_v3_by_downloaded_as_dir(const uint64_t target, const size_t min_remove_bytes, uint64_t *next_lowest); +STATIC hs_cache_dir_descriptor_t *lookup_v3_desc_as_dir(const uint8_t *key); STATIC hs_cache_client_descriptor_t * lookup_v3_desc_as_client(const uint8_t *key); +#ifdef TOR_UNIT_TESTS +void dir_set_downloaded(const ed25519_public_key_t *pk, uint64_t value); +#endif /* TOR_UNIT_TESTS */ + #endif /* defined(HS_CACHE_PRIVATE) */ #endif /* !defined(TOR_HS_CACHE_H) */ diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c @@ -224,6 +224,61 @@ test_clean_as_dir(void *arg) tor_free(desc1_str); } +static void +test_clean_oom_as_dir(void *arg) +{ + size_t ret; + char *desc1_str = NULL, *desc2_str = NULL; + hs_descriptor_t *desc1 = NULL, *desc2 = NULL; + ed25519_keypair_t signing_kp1, signing_kp2; + + (void) arg; + + init_test(); + + /* Generate two valid descriptors. */ + ret = ed25519_keypair_generate(&signing_kp1, 0); + tt_int_op(ret, OP_EQ, 0); + ret = ed25519_keypair_generate(&signing_kp2, 0); + tt_int_op(ret, OP_EQ, 0); + desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1); + tt_assert(desc1); + desc2 = hs_helper_build_hs_desc_with_ip(&signing_kp2); + tt_assert(desc2); + ret = hs_desc_encode_descriptor(desc1, &signing_kp1, NULL, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_desc_encode_descriptor(desc2, &signing_kp2, NULL, &desc2_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc2_str); + tt_int_op(ret, OP_EQ, 0); + + /* Set the downloaded count to 42 for the second one. */ + dir_set_downloaded(&desc2->plaintext_data.blinded_pubkey, 42); + const hs_cache_dir_descriptor_t *entry = + lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey); + tt_u64_op(entry->n_downloaded, OP_EQ, 42); + + /* Spin the OOM cleanup for only 1 descriptor (very low amount of bytes). We + * expect desc1 to be cleaned up because its downloaded counter is 0. */ + size_t removed = hs_cache_handle_oom(1); + tt_size_op(removed, OP_GT, 0); + + /* Desc1 is gone. */ + entry = lookup_v3_desc_as_dir(desc1->plaintext_data.blinded_pubkey.pubkey); + tt_assert(!entry); + /* Desc2 is still there. */ + entry = lookup_v3_desc_as_dir(desc2->plaintext_data.blinded_pubkey.pubkey); + tt_assert(entry); + + done: + hs_descriptor_free(desc1); + hs_descriptor_free(desc2); + tor_free(desc1_str); + tor_free(desc2_str); +} + /* Test helper: Fetch an HS descriptor from an HSDir (for the hidden service with <b>blinded_key</b>. Return the received descriptor string. */ static char * @@ -705,6 +760,8 @@ struct testcase_t hs_cache[] = { NULL, NULL }, { "clean_as_dir", test_clean_as_dir, TT_FORK, NULL, NULL }, + { "clean_oom_as_dir", test_clean_oom_as_dir, TT_FORK, + NULL, NULL }, { "hsdir_revision_counter_check", test_hsdir_revision_counter_check, TT_FORK, NULL, NULL }, { "upload_and_download_hs_desc", test_upload_and_download_hs_desc, TT_FORK,