Commit 92e8c732 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Unbreak br_netfilter physdev match support, from Florian Westphal.

2) Use GFP_KERNEL_ACCOUNT for stateful/policy objects, from Chen Aotian.

3) Use IS_ENABLED() in nf_reset_trace(), from Florian Westphal.

4) Fix validation of catch-all set element.

5) Tighten requirements for catch-all set elements.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nf_tables: tighten netlink attribute requirements for catch-all elements
  netfilter: nf_tables: validate catch-all set elements
  netfilter: nf_tables: fix ifdef to also consider nf_tables=m
  netfilter: nf_tables: Modify nla_memdup's flag to GFP_KERNEL_ACCOUNT
  netfilter: br_netfilter: fix recent physdev match breakage
====================

Link: https://lore.kernel.org/r/20230418145048.67270-1-pablo@netfilter.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c0e73276 d4eb7e39
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -294,6 +294,7 @@ struct nf_bridge_info {
	u8			pkt_otherhost:1;
	u8			in_prerouting:1;
	u8			bridged_dnat:1;
	u8			sabotage_in_done:1;
	__u16			frag_max_size;
	struct net_device	*physindev;

@@ -4712,7 +4713,7 @@ static inline void nf_reset_ct(struct sk_buff *skb)

static inline void nf_reset_trace(struct sk_buff *skb)
{
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)
	skb->nf_trace = 0;
#endif
}
@@ -4732,7 +4733,7 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
	dst->_nfct = src->_nfct;
	nf_conntrack_get(skb_nfct(src));
#endif
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || IS_ENABLED(CONFIG_NF_TABLES)
	if (copy)
		dst->nf_trace = src->nf_trace;
#endif
+4 −0
Original line number Diff line number Diff line
@@ -1085,6 +1085,10 @@ struct nft_chain {
};

int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
			 const struct nft_set_iter *iter,
			 struct nft_set_elem *elem);
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);

enum nft_chain_types {
	NFT_CHAIN_T_DEFAULT = 0,
+11 −6
Original line number Diff line number Diff line
@@ -868,13 +868,18 @@ static unsigned int ip_sabotage_in(void *priv,
{
	struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);

	if (nf_bridge && !nf_bridge->in_prerouting &&
	if (nf_bridge) {
		if (nf_bridge->sabotage_in_done)
			return NF_ACCEPT;

		if (!nf_bridge->in_prerouting &&
		    !netif_is_l3_master(skb->dev) &&
		    !netif_is_l3_slave(skb->dev)) {
		nf_bridge_info_free(skb);
			nf_bridge->sabotage_in_done = 1;
			state->okfn(state->net, state->sk, skb);
			return NF_STOLEN;
		}
	}

	return NF_ACCEPT;
}
+61 −8
Original line number Diff line number Diff line
@@ -3447,6 +3447,64 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
	return 0;
}

int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
			 const struct nft_set_iter *iter,
			 struct nft_set_elem *elem)
{
	const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
	struct nft_ctx *pctx = (struct nft_ctx *)ctx;
	const struct nft_data *data;
	int err;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
	    *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
		return 0;

	data = nft_set_ext_data(ext);
	switch (data->verdict.code) {
	case NFT_JUMP:
	case NFT_GOTO:
		pctx->level++;
		err = nft_chain_validate(ctx, data->verdict.chain);
		if (err < 0)
			return err;
		pctx->level--;
		break;
	default:
		break;
	}

	return 0;
}

struct nft_set_elem_catchall {
	struct list_head	list;
	struct rcu_head		rcu;
	void			*elem;
};

int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
{
	u8 genmask = nft_genmask_next(ctx->net);
	struct nft_set_elem_catchall *catchall;
	struct nft_set_elem elem;
	struct nft_set_ext *ext;
	int ret = 0;

	list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
		ext = nft_set_elem_ext(set, catchall->elem);
		if (!nft_set_elem_active(ext, genmask))
			continue;

		elem.priv = catchall->elem;
		ret = nft_setelem_validate(ctx, set, NULL, &elem);
		if (ret < 0)
			return ret;
	}

	return ret;
}

static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
					     const struct nft_chain *chain,
					     const struct nlattr *nla);
@@ -4759,12 +4817,6 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
	return err;
}

struct nft_set_elem_catchall {
	struct list_head	list;
	struct rcu_head		rcu;
	void			*elem;
};

static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
				     struct nft_set *set)
{
@@ -6056,7 +6108,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
	if (err < 0)
		return err;

	if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
	if (((flags & NFT_SET_ELEM_CATCHALL) && nla[NFTA_SET_ELEM_KEY]) ||
	    (!(flags & NFT_SET_ELEM_CATCHALL) && !nla[NFTA_SET_ELEM_KEY]))
		return -EINVAL;

	if (flags != 0) {
@@ -7052,7 +7105,7 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
	}

	if (nla[NFTA_OBJ_USERDATA]) {
		obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL);
		obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL_ACCOUNT);
		if (obj->udata == NULL)
			goto err_userdata;

+4 −32
Original line number Diff line number Diff line
@@ -199,37 +199,6 @@ static int nft_lookup_dump(struct sk_buff *skb,
	return -1;
}

static int nft_lookup_validate_setelem(const struct nft_ctx *ctx,
				       struct nft_set *set,
				       const struct nft_set_iter *iter,
				       struct nft_set_elem *elem)
{
	const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
	struct nft_ctx *pctx = (struct nft_ctx *)ctx;
	const struct nft_data *data;
	int err;

	if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
	    *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
		return 0;

	data = nft_set_ext_data(ext);
	switch (data->verdict.code) {
	case NFT_JUMP:
	case NFT_GOTO:
		pctx->level++;
		err = nft_chain_validate(ctx, data->verdict.chain);
		if (err < 0)
			return err;
		pctx->level--;
		break;
	default:
		break;
	}

	return 0;
}

static int nft_lookup_validate(const struct nft_ctx *ctx,
			       const struct nft_expr *expr,
			       const struct nft_data **d)
@@ -245,9 +214,12 @@ static int nft_lookup_validate(const struct nft_ctx *ctx,
	iter.skip	= 0;
	iter.count	= 0;
	iter.err	= 0;
	iter.fn		= nft_lookup_validate_setelem;
	iter.fn		= nft_setelem_validate;

	priv->set->ops->walk(ctx, priv->set, &iter);
	if (!iter.err)
		iter.err = nft_set_catchall_validate(ctx, priv->set);

	if (iter.err < 0)
		return iter.err;