Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: fix race when create new element in dynset

Packets may race when create the new element in nft_hash_update:
CPU0 CPU1
lookup_fast - fail lookup_fast - fail
new - ok new - ok
insert - ok insert - fail(EEXIST)

So when race happened, we reuse the existing element. Otherwise,
these *racing* packets will not be handled properly.

Fixes: 22fe54d5fefc ("netfilter: nf_tables: add support for dynamic set updates")
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Liping Zhang and committed by
Pablo Neira Ayuso
dab45060 61f9e292

+12 -3
+12 -3
net/netfilter/nft_set_hash.c
··· 98 98 const struct nft_set_ext **ext) 99 99 { 100 100 struct nft_hash *priv = nft_set_priv(set); 101 - struct nft_hash_elem *he; 101 + struct nft_hash_elem *he, *prev; 102 102 struct nft_hash_cmp_arg arg = { 103 103 .genmask = NFT_GENMASK_ANY, 104 104 .set = set, ··· 112 112 he = new(set, expr, regs); 113 113 if (he == NULL) 114 114 goto err1; 115 - if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, 116 - nft_hash_params)) 115 + 116 + prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node, 117 + nft_hash_params); 118 + if (IS_ERR(prev)) 117 119 goto err2; 120 + 121 + /* Another cpu may race to insert the element with the same key */ 122 + if (prev) { 123 + nft_set_elem_destroy(set, he, true); 124 + he = prev; 125 + } 126 + 118 127 out: 119 128 *ext = &he->ext; 120 129 return true;