From d07cf217edc5063f73fdb40e5c295d8af0f3f274 Mon Sep 17 00:00:00 2001 From: Noel Power Date: Fri, 18 Dec 2020 21:36:52 +0000 Subject: [PATCH] TESTCODE for memcache test of get_share_mode_lock destruction there is a weird Bad talloc magic value - access after free error The only way I can see this happen is if the underlying memcache entry is evicted. --- lib/util/memcache.c | 1 + source3/locking/share_mode_lock.c | 20 +++-- source3/utils/cache-test.c | 117 ++++++++++++++++++++++++++++++ source3/utils/wscript_build | 6 ++ 4 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 source3/utils/cache-test.c diff --git a/lib/util/memcache.c b/lib/util/memcache.c index 1e616bd0e9a..3ccdb46b93a 100644 --- a/lib/util/memcache.c +++ b/lib/util/memcache.c @@ -230,6 +230,7 @@ static void memcache_trim(struct memcache *cache) } while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) { + DBG_ERR("evicting a cache item\n"); memcache_delete_element(cache, DLIST_TAIL(cache->mru)); } } diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index a97d8d44930..c5ac18dbeb5 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -151,7 +151,7 @@ static void share_mode_memcache_delete(struct share_mode_data *d) { const DATA_BLOB key = memcache_key(&d->id); - DBG_DEBUG("deleting entry for file %s seq %"PRIx64" key %s\n", + DBG_ERR("deleting entry for file %s seq %"PRIx64" key %s\n", d->base_name, d->sequence_number, file_id_string(talloc_tos(), &d->id)); @@ -164,8 +164,9 @@ static void share_mode_memcache_delete(struct share_mode_data *d) static void share_mode_memcache_store(struct share_mode_data *d) { const DATA_BLOB key = memcache_key(&d->id); + struct file_id fid = {.devid = 1, .inode = 2, .extid = 0}; - DBG_DEBUG("stored entry for file %s seq %"PRIx64" key %s\n", + DBG_ERR("stored entry for file %s seq %"PRIx64" key %s\n", d->base_name, d->sequence_number, file_id_string(talloc_tos(), &d->id)); @@ -231,7 +232,7 @@ static struct share_mode_data *share_mode_memcache_fetch(TALLOC_CTX *mem_ctx, SHARE_MODE_LOCK_CACHE, key); if (ptr == NULL) { - DEBUG(10,("failed to find entry for key %s\n", + DEBUG(0,("failed to find entry for key %s\n", file_id_string(mem_ctx, &id))); return NULL; } @@ -239,7 +240,7 @@ static struct share_mode_data *share_mode_memcache_fetch(TALLOC_CTX *mem_ctx, ndr_err = get_blob_sequence_number(blob, &sequence_number); if (ndr_err != NDR_ERR_SUCCESS) { /* Bad blob. Remove entry. */ - DEBUG(10,("bad blob %u key %s\n", + DEBUG(0,("bad blob %u deleting key %s\n", (unsigned int)ndr_err, file_id_string(mem_ctx, &id))); memcache_delete(NULL, @@ -250,7 +251,7 @@ static struct share_mode_data *share_mode_memcache_fetch(TALLOC_CTX *mem_ctx, d = (struct share_mode_data *)ptr; if (d->sequence_number != sequence_number) { - DBG_DEBUG("seq changed (cached %"PRIx64") (new %"PRIx64") " + DBG_ERR("(deleting) seq changed (cached %"PRIx64") (new %"PRIx64") " "for key %s\n", d->sequence_number, sequence_number, @@ -272,6 +273,10 @@ static struct share_mode_data *share_mode_memcache_fetch(TALLOC_CTX *mem_ctx, talloc_set_destructor(d, share_mode_data_nofree_destructor); /* Remove from the cache. We own it now. */ + DBG_ERR("deleted entry for file %s seq %"PRIx64" key %s\n", + d->base_name, + d->sequence_number, + file_id_string(mem_ctx, &id)); memcache_delete(NULL, SHARE_MODE_LOCK_CACHE, key); @@ -279,7 +284,7 @@ static struct share_mode_data *share_mode_memcache_fetch(TALLOC_CTX *mem_ctx, /* And reset the destructor to none. */ talloc_set_destructor(d, NULL); - DBG_DEBUG("fetched entry for file %s seq %"PRIx64" key %s\n", + DBG_ERR("fetched entry for file %s seq %"PRIx64" key %s\n", d->base_name, d->sequence_number, file_id_string(mem_ctx, &id)); @@ -381,6 +386,7 @@ static int share_mode_data_destructor(struct share_mode_data *d) return 0; } + DBG_ERR("about to unparse\n"); data = unparse_share_modes(d); if (data.dptr == NULL) { @@ -438,7 +444,7 @@ static int share_mode_data_destructor(struct share_mode_data *d) * sequence number matches. See parse_share_modes() * for details. */ - + DBG_ERR("about to store cache entry\n"); share_mode_memcache_store(d); return -1; } diff --git a/source3/utils/cache-test.c b/source3/utils/cache-test.c new file mode 100644 index 00000000000..738354d9de6 --- /dev/null +++ b/source3/utils/cache-test.c @@ -0,0 +1,117 @@ +#include "includes.h" +#include "popt_common.h" +#include +#include "lib/util/memcache.h" +#include "librpc/gen_ndr/open_files.h" +#include "include/locking.h" +#include "smbd/smbd.h" +#include "lib/util/memcache.h" + +static bool lcl_set_share_mode(struct share_mode_lock *lck, + struct files_struct *fsp, + uid_t uid, uint64_t mid, uint16_t op_type, + uint32_t lease_idx) +{ + struct share_mode_data *d = lck->data; + struct share_mode_entry *tmp, *e; + + if ((lease_idx != UINT32_MAX) && + (lease_idx >= d->num_leases)) { + return false; + } + + tmp = talloc_realloc(d, d->share_modes, struct share_mode_entry, + d->num_share_modes+1); + if (tmp == NULL) { + return false; + } + d->share_modes = tmp; + e = &d->share_modes[d->num_share_modes]; + d->num_share_modes += 1; + d->modified = true; + + ZERO_STRUCTP(e); +// e->pid = messaging_server_id(fsp->conn->sconn->msg_ctx); + e->share_access = fsp->share_access; + // e->private_options = fsp->fh->private_options; + e->access_mask = fsp->access_mask; + e->op_mid = mid; + e->op_type = op_type; + e->lease_idx = lease_idx; + e->time.tv_sec = fsp->open_time.tv_sec; + e->time.tv_usec = fsp->open_time.tv_usec; +// e->share_file_id = fsp->fh->gen_id; + e->uid = (uint32_t)uid; + e->flags = (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) ? + SHARE_MODE_FLAG_POSIX_OPEN : 0; + e->name_hash = fsp->name_hash; + + return true; +} + + +static void testmemfoo(TALLOC_CTX *ctx, struct file_id fid) +{ + struct share_mode_lock *lck = NULL; + struct timespec timespec = {0}; + struct smb_filename smb_fname = { + .base_name = talloc_strdup(ctx, "."), + }; + struct files_struct fsp = {0}; + int i; + smb_fname.st.st_ex_dev = fid.devid; + smb_fname.st.st_ex_ino = fid.inode; + lck = get_share_mode_lock(talloc_tos(), fid, + "/home/data/testshare", &smb_fname, ×pec); + DBG_ERR("#1 created lock\n"); + DBG_ERR("#1 allocating just one share_mode lock\n"); + lcl_set_share_mode(lck, &fsp, 1, 2, 3, + UINT32_MAX); + DBG_ERR("#1 free-ing lock\n"); + TALLOC_FREE(lck); + DBG_ERR("#1 freed lock\n"); + lck = get_share_mode_lock(talloc_tos(), fid, + "/home/data/testshare", &smb_fname, ×pec); + DBG_ERR("#2 created lock\n"); + DBG_ERR("#2 allocating many many (10000) share_mode locks\n"); + for (i = 0; i < 10000; i++) { + lcl_set_share_mode(lck, &fsp, i + 2, i + 3, i + 4, + UINT32_MAX); + } + lcl_set_share_mode(lck, &fsp, 2, 3, 4, + UINT32_MAX); + DBG_ERR("#2 free-ing lock\n"); + TALLOC_FREE(lck); + DBG_ERR("#2 freed lock\n"); +} + +int main(int argc, const char *argv[]) +{ + int result; + TALLOC_CTX *ctx = talloc_init("testmemcache"); + TALLOC_CTX *frame = talloc_stackframe(); + int stat_cache_size = 0; + struct memcache *cache = NULL; + int i; + smb_init_locale(); + + if (!lp_load_client(get_dyn_CONFIGFILE())) { + fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", + get_dyn_CONFIGFILE()); + exit(1); + } + + stat_cache_size = lp_max_stat_cache_size(); + fprintf(stderr, "setting memcache size to %d\n", stat_cache_size * 1024); + cache = memcache_init(ctx, stat_cache_size * 1024); + memcache_set_global(cache); + locking_init(); + for (i=0; i<1; i++) { + struct file_id fid = {.devid = 1 + i, .inode = 2 + i, .extid = 0}; + DBG_ERR("## iter %d\n", i); + testmemfoo(ctx, fid); + } + result = 0; + TALLOC_FREE(frame); + return result; +} diff --git a/source3/utils/wscript_build b/source3/utils/wscript_build index c6d1c29b310..742cf181e37 100644 --- a/source3/utils/wscript_build +++ b/source3/utils/wscript_build @@ -283,3 +283,9 @@ bld.SAMBA3_BINARY('destroy_netlogon_creds_cli', NETLOGON_CREDS_CLI ''', install=False) +bld.SAMBA3_BINARY('cache-test', + source='cache-test.c', + deps=''' + talloc + POPT_SAMBA + smbd_base''') -- 2.26.2