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 200bc39965 ("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 <phil@nwl.cc>
This commit is contained in:
Phil Sutter
2020-05-01 07:59:36 +02:00
parent 7b3558f160
commit f42bfb344a
+11
View File
@@ -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)