]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: cache: Fix nft_release_cache() under stress
authorPhil Sutter <phil@nwl.cc>
Fri, 28 Feb 2020 19:32:13 +0000 (20:32 +0100)
committerPhil Sutter <phil@nwl.cc>
Fri, 6 Mar 2020 15:55:56 +0000 (16:55 +0100)
iptables-nft-restore calls nft_action(h, NFT_COMPAT_COMMIT) for each
COMMIT line in input. When restoring a dump containing multiple large
tables, chances are nft_rebuild_cache() has to run multiple times.

If the above happens, consecutive table contents are added to __cache[1]
which nft_rebuild_cache() then frees, so next commit attempt accesses
invalid memory.

Fix this by making nft_release_cache() (called after each successful
commit) return things into pre-rebuild state again, but keeping the
fresh cache copy.

Fixes: f6ad231d698c7 ("nft: keep original cache in case of ERESTART")
Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-cache.c

index 7345a27e2894b58bad4224b9ea9066c00f29dc3c..6f21f2283e0fbb3471748c29c03538f2cbe154ea 100644 (file)
@@ -647,8 +647,14 @@ void nft_rebuild_cache(struct nft_handle *h)
 
 void nft_release_cache(struct nft_handle *h)
 {
-       if (h->cache_index)
-               flush_cache(h, &h->__cache[0], NULL);
+       if (!h->cache_index)
+               return;
+
+       flush_cache(h, &h->__cache[0], NULL);
+       memcpy(&h->__cache[0], &h->__cache[1], sizeof(h->__cache[0]));
+       memset(&h->__cache[1], 0, sizeof(h->__cache[1]));
+       h->cache_index = 0;
+       h->cache = &h->__cache[0];
 }
 
 struct nftnl_table_list *nftnl_table_list_get(struct nft_handle *h)