From f42bfb344af82d10615420a96d088f11a0f78065 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 1 May 2020 07:59:36 +0200 Subject: nft: cache: Re-establish cache consistency check Restore code ensuring __nft_build_cache() returns a consistent cache in which all ruleset elements belong to the same generation. This check was removed by commit 200bc39965149 ("nft: cache: Fix iptables-save segfault under stress") as it could lead to segfaults if a partial cache fetch was done while cache's chain list was traversed. With the new cache fetch logic, __nft_build_cache() is never called while holding references to cache entries. Signed-off-by: Phil Sutter --- iptables/nft-cache.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'iptables/nft-cache.c') diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 84ea97d3..638b18bc 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -484,12 +484,16 @@ static int fetch_rule_cache(struct nft_handle *h, return 0; } +static int flush_cache(struct nft_handle *h, struct nft_cache *c, + const char *tablename); + static void __nft_build_cache(struct nft_handle *h) { struct nft_cache_req *req = &h->cache_req; const struct builtin_table *t = NULL; struct list_head *chains = NULL; + uint32_t genid_check; if (h->cache_init) return; @@ -501,6 +505,7 @@ __nft_build_cache(struct nft_handle *h) } h->cache_init = true; +retry: mnl_genid_get(h, &h->nft_genid); if (req->level >= NFT_CL_TABLES) @@ -513,6 +518,12 @@ __nft_build_cache(struct nft_handle *h) fetch_set_cache(h, t, NULL); if (req->level >= NFT_CL_RULES) fetch_rule_cache(h, t); + + mnl_genid_get(h, &genid_check); + if (h->nft_genid != genid_check) { + flush_cache(h, h->cache, NULL); + goto retry; + } } static void __nft_flush_cache(struct nft_handle *h) -- cgit v1.2.3