From 80d6f2920e28ccbc8dc0eb767bf22b4ae9ad0123 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 18 Dec 2024 11:28:59 -0500 Subject: [PATCH] test: Add HS cache OOM cleanup test Part of #40996 Signed-off-by: David Goulet --- src/feature/hs/hs_cache.c | 16 ++++++++++- src/feature/hs/hs_cache.h | 5 ++++ src/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 index 4977446945..103c5ddf1f 100644 --- 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 index b6d6cc50b9..2f78f8479a 100644 --- 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 index a0b698b978..100a90e86a 100644 --- 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 blinded_key. 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, -- 2.47.2