By the time nft_action() decides to rebuild the cache, nft_cmd structs have been freed already and therefore table and chain names in nft_cache_req point to invalid memory. Fix this by duplicating the strings and freeing them when releasing the cache. Signed-off-by: Phil Sutter <phil@xxxxxx> --- iptables/nft-cache.c | 14 ++++++++++---- iptables/nft.h | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 83af9a2f689e1..84ea97d3e54a6 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -39,7 +39,7 @@ static void cache_chain_list_insert(struct list_head *list, const char *name) } new = xtables_malloc(sizeof(*new)); - new->name = name; + new->name = strdup(name); list_add_tail(&new->head, pos ? &pos->head : list); } @@ -54,7 +54,10 @@ void nft_cache_level_set(struct nft_handle *h, int level, if (!cmd || !cmd->table || req->all_chains) return; - req->table = cmd->table; + if (!req->table) + req->table = strdup(cmd->table); + else + assert(!strcmp(req->table, cmd->table)); if (!cmd->chain) { req->all_chains = true; @@ -663,11 +666,14 @@ void nft_release_cache(struct nft_handle *h) if (req->level != NFT_CL_FAKE) req->level = NFT_CL_TABLES; - req->table = NULL; - + if (req->table) { + free(req->table); + req->table = NULL; + } req->all_chains = false; list_for_each_entry_safe(cc, cc_tmp, &req->chain_list, head) { list_del(&cc->head); + free(cc->name); free(cc); } } diff --git a/iptables/nft.h b/iptables/nft.h index 045393da7c179..aeacc608fcb9f 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -73,12 +73,12 @@ enum obj_update_type { struct cache_chain { struct list_head head; - const char *name; + char *name; }; struct nft_cache_req { enum nft_cache_level level; - const char *table; + char *table; bool all_chains; struct list_head chain_list; }; -- 2.25.1