Commit 2650be2c authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for net:

1) Allow conntrack entries with l3num == NFPROTO_IPV4 or == NFPROTO_IPV6
   only via ctnetlink, from Will McVicker.

2) Batch notifications to userspace to improve netlink socket receive
   utilization.

3) Restore mark based dump filtering via ctnetlink, from Martin Willi.

4) nf_conncount_init() fails with -EPROTO with CONFIG_IPV6, from
   Eelco Chaudron.

5) Containers fail to match on meta skuid and skgid, use socket user_ns
   to retrieve meta skuid and skgid.
===================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 843d926b 0c92411b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ struct netns_nftables {
	struct list_head	tables;
	struct list_head	commit_list;
	struct list_head	module_list;
	struct list_head	notify_list;
	struct mutex		commit_mutex;
	unsigned int		base_seq;
	u8			gencursor;
+5 −17
Original line number Diff line number Diff line
@@ -851,7 +851,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
}

struct ctnetlink_filter {
	u_int32_t cta_flags;
	u8 family;

	u_int32_t orig_flags;
@@ -906,10 +905,6 @@ static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
					 struct nf_conntrack_zone *zone,
					 u_int32_t flags);

/* applied on filters */
#define CTA_FILTER_F_CTA_MARK			(1 << 0)
#define CTA_FILTER_F_CTA_MARK_MASK		(1 << 1)

static struct ctnetlink_filter *
ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
{
@@ -930,14 +925,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
#ifdef CONFIG_NF_CONNTRACK_MARK
	if (cda[CTA_MARK]) {
		filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
		filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK);

		if (cda[CTA_MARK_MASK]) {
		if (cda[CTA_MARK_MASK])
			filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
			filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK_MASK);
		} else {
		else
			filter->mark.mask = 0xffffffff;
		}
	} else if (cda[CTA_MARK_MASK]) {
		err = -EINVAL;
		goto err_filter;
@@ -1117,11 +1108,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
	}

#ifdef CONFIG_NF_CONNTRACK_MARK
	if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK_MASK)) &&
	    (ct->mark & filter->mark.mask) != filter->mark.val)
		goto ignore_entry;
	else if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK)) &&
		 ct->mark != filter->mark.val)
	if ((ct->mark & filter->mark.mask) != filter->mark.val)
		goto ignore_entry;
#endif

@@ -1404,7 +1391,8 @@ ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
	if (err < 0)
		return err;


	if (l3num != NFPROTO_IPV4 && l3num != NFPROTO_IPV6)
		return -EOPNOTSUPP;
	tuple->src.l3num = l3num;

	if (flags & CTA_FILTER_FLAG(CTA_IP_DST) ||
+2 −0
Original line number Diff line number Diff line
@@ -565,6 +565,7 @@ static int nf_ct_netns_inet_get(struct net *net)
	int err;

	err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
#if IS_ENABLED(CONFIG_IPV6)
	if (err < 0)
		goto err1;
	err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
@@ -575,6 +576,7 @@ static int nf_ct_netns_inet_get(struct net *net)
err2:
	nf_ct_netns_put(net, NFPROTO_IPV4);
err1:
#endif
	return err;
}

+57 −13
Original line number Diff line number Diff line
@@ -684,6 +684,18 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
	return -1;
}

struct nftnl_skb_parms {
	bool report;
};
#define NFT_CB(skb)	(*(struct nftnl_skb_parms*)&((skb)->cb))

static void nft_notify_enqueue(struct sk_buff *skb, bool report,
			       struct list_head *notify_list)
{
	NFT_CB(skb).report = report;
	list_add_tail(&skb->list, notify_list);
}

static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
{
	struct sk_buff *skb;
@@ -715,8 +727,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
		goto err;
	}

	nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
		       ctx->report, GFP_KERNEL);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -1468,8 +1479,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
		goto err;
	}

	nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
		       ctx->report, GFP_KERNEL);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -2807,8 +2817,7 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
		goto err;
	}

	nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
		       ctx->report, GFP_KERNEL);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -3837,8 +3846,7 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
		goto err;
	}

	nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, ctx->report,
		       gfp_flags);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -4959,8 +4967,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
		goto err;
	}

	nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report,
		       GFP_KERNEL);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -6275,7 +6282,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
		goto err;
	}

	nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, gfp);
	nft_notify_enqueue(skb, report, &net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -7085,8 +7092,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
		goto err;
	}

	nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
		       ctx->report, GFP_KERNEL);
	nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
	return;
err:
	nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
@@ -7695,6 +7701,41 @@ static void nf_tables_commit_release(struct net *net)
	mutex_unlock(&net->nft.commit_mutex);
}

static void nft_commit_notify(struct net *net, u32 portid)
{
	struct sk_buff *batch_skb = NULL, *nskb, *skb;
	unsigned char *data;
	int len;

	list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) {
		if (!batch_skb) {
new_batch:
			batch_skb = skb;
			len = NLMSG_GOODSIZE - skb->len;
			list_del(&skb->list);
			continue;
		}
		len -= skb->len;
		if (len > 0 && NFT_CB(skb).report == NFT_CB(batch_skb).report) {
			data = skb_put(batch_skb, skb->len);
			memcpy(data, skb->data, skb->len);
			list_del(&skb->list);
			kfree_skb(skb);
			continue;
		}
		nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
			       NFT_CB(batch_skb).report, GFP_KERNEL);
		goto new_batch;
	}

	if (batch_skb) {
		nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
			       NFT_CB(batch_skb).report, GFP_KERNEL);
	}

	WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
}

static int nf_tables_commit(struct net *net, struct sk_buff *skb)
{
	struct nft_trans *trans, *next;
@@ -7897,6 +7938,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
		}
	}

	nft_commit_notify(net, NETLINK_CB(skb).portid);
	nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
	nf_tables_commit_release(net);

@@ -8721,6 +8763,7 @@ static int __net_init nf_tables_init_net(struct net *net)
	INIT_LIST_HEAD(&net->nft.tables);
	INIT_LIST_HEAD(&net->nft.commit_list);
	INIT_LIST_HEAD(&net->nft.module_list);
	INIT_LIST_HEAD(&net->nft.notify_list);
	mutex_init(&net->nft.commit_mutex);
	net->nft.base_seq = 1;
	net->nft.validate_state = NFT_VALIDATE_SKIP;
@@ -8737,6 +8780,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
	mutex_unlock(&net->nft.commit_mutex);
	WARN_ON_ONCE(!list_empty(&net->nft.tables));
	WARN_ON_ONCE(!list_empty(&net->nft.module_list));
	WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
}

static struct pernet_operations nf_tables_net_ops = {
+2 −2
Original line number Diff line number Diff line
@@ -147,11 +147,11 @@ nft_meta_get_eval_skugid(enum nft_meta_keys key,

	switch (key) {
	case NFT_META_SKUID:
		*dest = from_kuid_munged(&init_user_ns,
		*dest = from_kuid_munged(sock_net(sk)->user_ns,
					 sock->file->f_cred->fsuid);
		break;
	case NFT_META_SKGID:
		*dest =	from_kgid_munged(&init_user_ns,
		*dest =	from_kgid_munged(sock_net(sk)->user_ns,
					 sock->file->f_cred->fsgid);
		break;
	default: