]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: cache: Re-establish cache consistency check
authorPhil Sutter <phil@nwl.cc>
Fri, 1 May 2020 05:59:36 +0000 (07:59 +0200)
committerPhil Sutter <phil@nwl.cc>
Mon, 11 May 2020 12:28:29 +0000 (14:28 +0200)
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 <phil@nwl.cc>
iptables/nft-cache.c

index 84ea97d3e54a62d4b4da64a91d936406a8ce9d6f..638b18bc7e3824ad49dc14e194501f56ce6044e1 100644 (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)