From a48be6dbc3378a967477522414b96bba49df4e1a Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Tue, 10 Mar 2026 13:23:05 +0100 Subject: [PATCH] Fix memory leaks and bad-free in cache and crypto sector log pcache.c: cache_timer and pcache_clean called pmem_free(he->value) directly instead of he->free(he->value), skipping the registered free callback. This caused all cached SSL connections, TLS sessions, and crypto decoders to leak their internal mbedtls state on eviction and shutdown. Same bug fixed in pcache_clean_oneof. pfscrypto.c: ptree_for_each_element_call_safe passed bare free() to free psync_sector_inlog_t nodes, but those are allocated via pmem_malloc which prepends a 16-byte header. Add free_sector_inlog() helper that calls pmem_free and use it at both call sites. Co-Authored-By: Claude Sonnet 4.6 --- pclsync/pcache.c | 6 +++--- pclsync/pfscrypto.c | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pclsync/pcache.c b/pclsync/pcache.c index 3fb9379..c71de85 100644 --- a/pclsync/pcache.c +++ b/pclsync/pcache.c @@ -81,7 +81,7 @@ static void cache_timer(psync_timer_t timer, void *ptr) { pthread_mutex_lock(&cachelocks[hash_to_lock(he->hash)]); psync_list_del(&he->list); pthread_mutex_unlock(&cachelocks[hash_to_lock(he->hash)]); - pmem_free(PMEM_SUBSYS_OTHER, he->value); + he->free(he->value); pmem_free(PMEM_SUBSYS_OTHER, he); ptimer_stop(timer); } @@ -229,7 +229,7 @@ void pcache_clean() { he = psync_list_element(l1, cache_entry_t, list); if (!ptimer_stop(he->timer)) { psync_list_del(l1); - pmem_free(PMEM_SUBSYS_OTHER, he->value); + he->free(he->value); pmem_free(PMEM_SUBSYS_OTHER, he); } } @@ -256,7 +256,7 @@ void pcache_clean_oneof(const char **prefixes, size_t cnt) { continue; if (!ptimer_stop(he->timer)) { psync_list_del(l1); - pmem_free(PMEM_SUBSYS_OTHER, he->value); + he->free(he->value); pmem_free(PMEM_SUBSYS_OTHER, he); } } diff --git a/pclsync/pfscrypto.c b/pclsync/pfscrypto.c index 844763e..3978850 100644 --- a/pclsync/pfscrypto.c +++ b/pclsync/pfscrypto.c @@ -531,6 +531,10 @@ int pfs_crpt_read_new(psync_openfile_t *of, char *buf, return rd; } +static void free_sector_inlog(psync_sector_inlog_t *e) { + pmem_free(PMEM_SUBSYS_OTHER, e); +} + static void pfs_crypto_set_sector_log_offset(psync_openfile_t *of, psync_crypto_sectorid_t sectorid, @@ -1093,7 +1097,7 @@ static int pfs_crypto_do_finalize_log(psync_openfile_t *of, int fullsync) { pmem_free(PMEM_SUBSYS_OTHER, flog); return -EIO; } - ptree_for_each_element_call_safe(of->sectorsinlog, psync_sector_inlog_t, tree, free); + ptree_for_each_element_call_safe(of->sectorsinlog, psync_sector_inlog_t, tree, free_sector_inlog); of->sectorsinlog = PSYNC_TREE_EMPTY; ret = pfs_crypto_log_flush_and_process(of, flog, 0, 1); pfile_delete(flog); @@ -1690,7 +1694,7 @@ static int pfs_crpt_truncate_to_zero(psync_openfile_t *of) { psync_interval_tree_add(&of->writeintervals, 0, pfs_crpt_crypto_size(of->initialsize)); } - ptree_for_each_element_call_safe(of->sectorsinlog, psync_sector_inlog_t, tree, free); + ptree_for_each_element_call_safe(of->sectorsinlog, psync_sector_inlog_t, tree, free_sector_inlog); of->sectorsinlog = PSYNC_TREE_EMPTY; of->currentsize = 0; pfs_crypto_kill_extender_locked(of);