Commit ecf43926 authored by Paolo Abeni's avatar Paolo Abeni
Browse files
Florian Westphal says:

====================
netfilter updates for net

The following three patches fix regressions in the netfilter subsystem:

1. Reject attempts to repeatedly toggle the 'dormant' flag in a single
   transaction.  Doing so makes nf_tables lose track of the real state
   vs. the desired state.  This ends with an attempt to unregister hooks
   that were never registered in the first place, which yields a splat.

2. Fix element counting in the new nftables garbage collection infra
   that came with 6.5:  More than 255 expired elements wraps a counter
   which results in memory leak.

3. Since 6.4 ipset can BUG when a set is renamed while a CREATE command
   is in progress, fix from Jozsef Kadlecsik.

* tag 'nf-23-09-20' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: ipset: Fix race between IPSET_CMD_CREATE and IPSET_CMD_SWAP
  netfilter: nf_tables: fix memleak when more than 255 elements expired
  netfilter: nf_tables: disable toggling dormant table state more than once
====================

Link: https://lore.kernel.org/r/20230920084156.4192-1-fw@strlen.de


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents fc21f083 7433b6d2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1682,7 +1682,7 @@ struct nft_trans_gc {
	struct net		*net;
	struct nft_set		*set;
	u32			seq;
	u8			count;
	u16			count;
	void			*priv[NFT_TRANS_GC_BATCHCOUNT];
	struct rcu_head		rcu;
};
+10 −2
Original line number Diff line number Diff line
@@ -682,6 +682,14 @@ __ip_set_put(struct ip_set *set)
/* set->ref can be swapped out by ip_set_swap, netlink events (like dump) need
 * a separate reference counter
 */
static void
__ip_set_get_netlink(struct ip_set *set)
{
	write_lock_bh(&ip_set_ref_lock);
	set->ref_netlink++;
	write_unlock_bh(&ip_set_ref_lock);
}

static void
__ip_set_put_netlink(struct ip_set *set)
{
@@ -1693,11 +1701,11 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb,

	do {
		if (retried) {
			__ip_set_get(set);
			__ip_set_get_netlink(set);
			nfnl_unlock(NFNL_SUBSYS_IPSET);
			cond_resched();
			nfnl_lock(NFNL_SUBSYS_IPSET);
			__ip_set_put(set);
			__ip_set_put_netlink(set);
		}

		ip_set_lock(set);
+12 −2
Original line number Diff line number Diff line
@@ -1219,6 +1219,10 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
	     flags & NFT_TABLE_F_OWNER))
		return -EOPNOTSUPP;

	/* No dormant off/on/off/on games in single transaction */
	if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
		return -EINVAL;

	trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
				sizeof(struct nft_trans_table));
	if (trans == NULL)
@@ -9575,12 +9579,15 @@ static int nft_trans_gc_space(struct nft_trans_gc *trans)
struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
					      unsigned int gc_seq, gfp_t gfp)
{
	struct nft_set *set;

	if (nft_trans_gc_space(gc))
		return gc;

	set = gc->set;
	nft_trans_gc_queue_work(gc);

	return nft_trans_gc_alloc(gc->set, gc_seq, gfp);
	return nft_trans_gc_alloc(set, gc_seq, gfp);
}

void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
@@ -9595,15 +9602,18 @@ void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)

struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp)
{
	struct nft_set *set;

	if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net)))
		return NULL;

	if (nft_trans_gc_space(gc))
		return gc;

	set = gc->set;
	call_rcu(&gc->rcu, nft_trans_gc_trans_free);

	return nft_trans_gc_alloc(gc->set, 0, gfp);
	return nft_trans_gc_alloc(set, 0, gfp);
}

void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)