Commit 792aaea9 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Florian Westphal says:

====================
netfilter: updates for net-next

The following patchset contains Netfilter updates for *net-next*:

1) Fix net-next-only use-after-free bug in nf_tables rbtree set:
   Expired elements cannot be released right away after unlink anymore
   because there is no guarantee that the binary-search blob is going to
   be updated.  Spotted by syzkaller.

2) Fix esoteric bug in nf_queue with udp fraglist gro, broken since
   6.11. Patch 3 adds extends the nfqueue selftest for this.

4) Use dedicated slab for flowtable entries, currently the -512 cache
   is used, which is wasteful.  From Qingfang Deng.

5) Recent net-next update extended existing test for ip6ip6 tunnels, add
   the required /config entry.  Test still passed by accident because the
   previous tests network setup gets re-used, so also update the test so
   it will fail in case the ip6ip6 tunnel interface cannot be added.

6) Fix 'nft get element mytable myset { 1.2.3.4 }' on big endian
   platforms, this was broken since code was added in v5.1.

7) Fix nf_tables counter reset support on 32bit platforms, where counter
   reset may cause huge values to appear due to wraparound.
   Broken since reset feature was added in v6.11.  From Anders Grahn.

8-11) update nf_tables rbtree set type to detect partial
   operlaps.  This will eventually speed up nftables userspace: at this
   time userspace does a netlink dump of the set content which slows down
   incremental updates on interval sets.  From Pablo Neira Ayuso.

* tag 'nf-next-26-02-06' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next:
  netfilter: nft_set_rbtree: validate open interval overlap
  netfilter: nft_set_rbtree: validate element belonging to interval
  netfilter: nft_set_rbtree: check for partial overlaps in anonymous sets
  netfilter: nft_set_rbtree: fix bogus EEXIST with NLM_F_CREATE with null interval
  netfilter: nft_counter: fix reset of counters on 32bit archs
  netfilter: nft_set_hash: fix get operation on big endian
  selftests: netfilter: add IPV6_TUNNEL to config
  netfilter: flowtable: dedicated slab for flow entry
  selftests: netfilter: nft_queue.sh: add udp fraglist gro test case
  netfilter: nfnetlink_queue: do shared-unconfirmed check before segmentation
  netfilter: nft_set_rbtree: don't gc elements on insert
====================

Link: https://patch.msgid.link/20260206153048.17570-1-fw@strlen.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3a468736 64894696
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -97,6 +97,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
	local64_add(val, &p->v);
}

static inline void u64_stats_sub(u64_stats_t *p, s64 val)
{
	local64_sub(val, &p->v);
}

static inline void u64_stats_inc(u64_stats_t *p)
{
	local64_inc(&p->v);
@@ -145,6 +150,11 @@ static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
	p->v += val;
}

static inline void u64_stats_sub(u64_stats_t *p, s64 val)
{
	p->v -= val;
}

static inline void u64_stats_inc(u64_stats_t *p)
{
	p->v++;
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ struct nf_queue_entry {
	struct net_device	*physout;
#endif
	struct nf_hook_state	state;
	bool			nf_ct_is_unconfirmed;
	u16			size; /* sizeof(entry) + saved route keys */
	u16			queue_num;

+4 −0
Original line number Diff line number Diff line
@@ -277,6 +277,8 @@ struct nft_userdata {
	unsigned char		data[];
};

#define NFT_SET_ELEM_INTERNAL_LAST	0x1

/* placeholder structure for opaque set element backend representation. */
struct nft_elem_priv { };

@@ -286,6 +288,7 @@ struct nft_elem_priv { };
 *	@key: element key
 *	@key_end: closing element key
 *	@data: element data
 * 	@flags: flags
 *	@priv: element private data and extensions
 */
struct nft_set_elem {
@@ -301,6 +304,7 @@ struct nft_set_elem {
		u32		buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
		struct nft_data val;
	} data;
	u32			flags;
	struct nft_elem_priv	*priv;
};

+10 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

static DEFINE_MUTEX(flowtable_lock);
static LIST_HEAD(flowtables);
static __read_mostly struct kmem_cache *flow_offload_cachep;

static void
flow_offload_fill_dir(struct flow_offload *flow,
@@ -56,7 +57,7 @@ struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
	if (unlikely(nf_ct_is_dying(ct)))
		return NULL;

	flow = kzalloc(sizeof(*flow), GFP_ATOMIC);
	flow = kmem_cache_zalloc(flow_offload_cachep, GFP_ATOMIC);
	if (!flow)
		return NULL;

@@ -812,9 +813,13 @@ static int __init nf_flow_table_module_init(void)
{
	int ret;

	flow_offload_cachep = KMEM_CACHE(flow_offload, SLAB_HWCACHE_ALIGN);
	if (!flow_offload_cachep)
		return -ENOMEM;

	ret = register_pernet_subsys(&nf_flow_table_net_ops);
	if (ret < 0)
		return ret;
		goto out_pernet;

	ret = nf_flow_table_offload_init();
	if (ret)
@@ -830,6 +835,8 @@ static int __init nf_flow_table_module_init(void)
	nf_flow_table_offload_exit();
out_offload:
	unregister_pernet_subsys(&nf_flow_table_net_ops);
out_pernet:
	kmem_cache_destroy(flow_offload_cachep);
	return ret;
}

@@ -837,6 +844,7 @@ static void __exit nf_flow_table_module_exit(void)
{
	nf_flow_table_offload_exit();
	unregister_pernet_subsys(&nf_flow_table_net_ops);
	kmem_cache_destroy(flow_offload_cachep);
}

module_init(nf_flow_table_module_init);
+22 −4
Original line number Diff line number Diff line
@@ -7270,7 +7270,8 @@ static u32 nft_set_maxsize(const struct nft_set *set)
}

static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
			    const struct nlattr *attr, u32 nlmsg_flags)
			    const struct nlattr *attr, u32 nlmsg_flags,
			    bool last)
{
	struct nft_expr *expr_array[NFT_SET_EXPR_MAX] = {};
	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
@@ -7556,6 +7557,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	if (flags)
		*nft_set_ext_flags(ext) = flags;

	if (last)
		elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
	else
		elem.flags = 0;

	if (obj)
		*nft_set_ext_obj(ext) = obj;

@@ -7636,6 +7642,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
			 * and an existing one.
			 */
			err = -EEXIST;
		} else if (err == -ECANCELED) {
			/* ECANCELED reports an existing nul-element in
			 * interval sets.
			 */
			err = 0;
		}
		goto err_element_clash;
	}
@@ -7714,7 +7725,8 @@ static int nf_tables_newsetelem(struct sk_buff *skb,
	nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);

	nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
		err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
		err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags,
				       nla_is_last(attr, rem));
		if (err < 0) {
			NL_SET_BAD_ATTR(extack, attr);
			return err;
@@ -7838,7 +7850,7 @@ static void nft_trans_elems_destroy_abort(const struct nft_ctx *ctx,
}

static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
			   const struct nlattr *attr)
			   const struct nlattr *attr, bool last)
{
	struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
	struct nft_set_ext_tmpl tmpl;
@@ -7906,6 +7918,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
	if (flags)
		*nft_set_ext_flags(ext) = flags;

	if (last)
		elem.flags = NFT_SET_ELEM_INTERNAL_LAST;
	else
		elem.flags = 0;

	trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
	if (trans == NULL)
		goto fail_trans;
@@ -8053,7 +8070,8 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
		return nft_set_flush(&ctx, set, genmask);

	nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
		err = nft_del_setelem(&ctx, set, attr);
		err = nft_del_setelem(&ctx, set, attr,
				      nla_is_last(attr, rem));
		if (err == -ENOENT &&
		    NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
			continue;
Loading