Commit 28b7a6b8 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso
Browse files

netfilter: nf_tables: avoid false-positive lockdep splats in set walker



Its not possible to add or delete elements from hash and bitmap sets,
as long as caller is holding the transaction mutex, so its ok to iterate
the list outside of rcu read side critical section.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent b3e8f29d
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -88,13 +88,15 @@ bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
}

static struct nft_bitmap_elem *
nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
nft_bitmap_elem_find(const struct net *net,
		     const struct nft_set *set, struct nft_bitmap_elem *this,
		     u8 genmask)
{
	const struct nft_bitmap *priv = nft_set_priv(set);
	struct nft_bitmap_elem *be;

	list_for_each_entry_rcu(be, &priv->list, head) {
	list_for_each_entry_rcu(be, &priv->list, head,
				lockdep_is_held(&nft_pernet(net)->commit_mutex)) {
		if (memcmp(nft_set_ext_key(&be->ext),
			   nft_set_ext_key(&this->ext), set->klen) ||
		    !nft_set_elem_active(&be->ext, genmask))
@@ -132,7 +134,7 @@ static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
	u8 genmask = nft_genmask_next(net);
	u32 idx, off;

	be = nft_bitmap_elem_find(set, new, genmask);
	be = nft_bitmap_elem_find(net, set, new, genmask);
	if (be) {
		*elem_priv = &be->priv;
		return -EEXIST;
@@ -201,7 +203,7 @@ nft_bitmap_deactivate(const struct net *net, const struct nft_set *set,

	nft_bitmap_location(set, elem->key.val.data, &idx, &off);

	be = nft_bitmap_elem_find(set, this, genmask);
	be = nft_bitmap_elem_find(net, set, this, genmask);
	if (!be)
		return NULL;

+2 −1
Original line number Diff line number Diff line
@@ -647,7 +647,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
	int i;

	for (i = 0; i < priv->buckets; i++) {
		hlist_for_each_entry_rcu(he, &priv->table[i], node) {
		hlist_for_each_entry_rcu(he, &priv->table[i], node,
					 lockdep_is_held(&nft_pernet(ctx->net)->commit_mutex)) {
			if (iter->count < iter->skip)
				goto cont;