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

netfilter: nf_tables: remove catchall element in GC sync path

The expired catchall element is not deactivated and removed from GC sync
path. This path holds mutex so just call nft_setelem_data_deactivate()
and nft_setelem_catchall_remove() before queueing the GC work.

Fixes: 4a9e12ea7e70 ("netfilter: nft_set_pipapo: call nft_trans_gc_queue_sync() in catchall GC")
Reported-by: lonial con <kongln9170@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+17 -5
+17 -5
net/netfilter/nf_tables_api.c
··· 6520 6520 return ret; 6521 6521 } 6522 6522 6523 + static void nft_setelem_catchall_destroy(struct nft_set_elem_catchall *catchall) 6524 + { 6525 + list_del_rcu(&catchall->list); 6526 + kfree_rcu(catchall, rcu); 6527 + } 6528 + 6523 6529 static void nft_setelem_catchall_remove(const struct net *net, 6524 6530 const struct nft_set *set, 6525 6531 struct nft_elem_priv *elem_priv) ··· 6534 6528 6535 6529 list_for_each_entry_safe(catchall, next, &set->catchall_list, list) { 6536 6530 if (catchall->elem == elem_priv) { 6537 - list_del_rcu(&catchall->list); 6538 - kfree_rcu(catchall, rcu); 6531 + nft_setelem_catchall_destroy(catchall); 6539 6532 break; 6540 6533 } 6541 6534 } ··· 9683 9678 unsigned int gc_seq, 9684 9679 bool sync) 9685 9680 { 9686 - struct nft_set_elem_catchall *catchall; 9681 + struct nft_set_elem_catchall *catchall, *next; 9687 9682 const struct nft_set *set = gc->set; 9683 + struct nft_elem_priv *elem_priv; 9688 9684 struct nft_set_ext *ext; 9689 9685 9690 - list_for_each_entry_rcu(catchall, &set->catchall_list, list) { 9686 + list_for_each_entry_safe(catchall, next, &set->catchall_list, list) { 9691 9687 ext = nft_set_elem_ext(set, catchall->elem); 9692 9688 9693 9689 if (!nft_set_elem_expired(ext)) ··· 9706 9700 if (!gc) 9707 9701 return NULL; 9708 9702 9709 - nft_trans_gc_elem_add(gc, catchall->elem); 9703 + elem_priv = catchall->elem; 9704 + if (sync) { 9705 + nft_setelem_data_deactivate(gc->net, gc->set, elem_priv); 9706 + nft_setelem_catchall_destroy(catchall); 9707 + } 9708 + 9709 + nft_trans_gc_elem_add(gc, elem_priv); 9710 9710 } 9711 9711 9712 9712 return gc;