Commit f4b29d2e 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) Nicolas Dichtel updates MAINTAINERS file to add Netfilter IRC channel.

2) Skip non-IPv6 packets in nft_exthdr.

3) Skip non-TCP packets in nft_osf.

4) Skip non-TCP/UDP packets in nft_tproxy.

5) Memleak in hardware offload infrastructure when counters are used
   for first time in a rule.

6) The VLAN transfer routine must use FLOW_DISSECTOR_KEY_BASIC instead
   of FLOW_DISSECTOR_KEY_CONTROL. Moreover, make a more robust check
   for 802.1q and 802.1ad to restore simple matching on transport
   protocols.

7) Fix bogus EPERM when listing a ruleset when table ownership flag
   is set on.

8) Honor table ownership flag when table is referenced by handle.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ce8eb4c7 e31f072f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12659,6 +12659,7 @@ W: http://www.netfilter.org/
W:	http://www.iptables.org/
W:	http://www.nftables.org/
Q:	http://patchwork.ozlabs.org/project/netfilter-devel/list/
C:	irc://irc.libera.chat/netfilter
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git
F:	include/linux/netfilter*
+41 −24
Original line number Diff line number Diff line
@@ -571,7 +571,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
		    table->family == family &&
		    nft_active_genmask(table, genmask)) {
			if (nft_table_has_owner(table) &&
			    table->nlpid != nlpid)
			    nlpid && table->nlpid != nlpid)
				return ERR_PTR(-EPERM);

			return table;
@@ -583,7 +583,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,

static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
						   const struct nlattr *nla,
						   u8 genmask)
						   u8 genmask, u32 nlpid)
{
	struct nftables_pernet *nft_net;
	struct nft_table *table;
@@ -591,9 +591,14 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
	nft_net = nft_pernet(net);
	list_for_each_entry(table, &nft_net->tables, list) {
		if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
		    nft_active_genmask(table, genmask))
		    nft_active_genmask(table, genmask)) {
			if (nft_table_has_owner(table) &&
			    nlpid && table->nlpid != nlpid)
				return ERR_PTR(-EPERM);

			return table;
		}
	}

	return ERR_PTR(-ENOENT);
}
@@ -1279,7 +1284,8 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,

	if (nla[NFTA_TABLE_HANDLE]) {
		attr = nla[NFTA_TABLE_HANDLE];
		table = nft_table_lookup_byhandle(net, attr, genmask);
		table = nft_table_lookup_byhandle(net, attr, genmask,
						  NETLINK_CB(skb).portid);
	} else {
		attr = nla[NFTA_TABLE_NAME];
		table = nft_table_lookup(net, attr, family, genmask,
@@ -3243,9 +3249,9 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
	u8 genmask = nft_genmask_next(info->net);
	struct nft_rule *rule, *old_rule = NULL;
	struct nft_expr_info *expr_info = NULL;
	struct nft_flow_rule *flow = NULL;
	int family = nfmsg->nfgen_family;
	struct net *net = info->net;
	struct nft_flow_rule *flow;
	struct nft_userdata *udata;
	struct nft_table *table;
	struct nft_chain *chain;
@@ -3340,13 +3346,13 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
			err = -EINVAL;
			if (nla_type(tmp) != NFTA_LIST_ELEM)
				goto err1;
				goto err_release_expr;
			if (n == NFT_RULE_MAXEXPRS)
				goto err1;
				goto err_release_expr;
			err = nf_tables_expr_parse(&ctx, tmp, &expr_info[n]);
			if (err < 0) {
				NL_SET_BAD_ATTR(extack, tmp);
				goto err1;
				goto err_release_expr;
			}
			size += expr_info[n].ops->size;
			n++;
@@ -3355,7 +3361,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
	/* Check for overflow of dlen field */
	err = -EFBIG;
	if (size >= 1 << 12)
		goto err1;
		goto err_release_expr;

	if (nla[NFTA_RULE_USERDATA]) {
		ulen = nla_len(nla[NFTA_RULE_USERDATA]);
@@ -3366,7 +3372,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
	err = -ENOMEM;
	rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
	if (rule == NULL)
		goto err1;
		goto err_release_expr;

	nft_activate_next(net, rule);

@@ -3385,7 +3391,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		err = nf_tables_newexpr(&ctx, &expr_info[i], expr);
		if (err < 0) {
			NL_SET_BAD_ATTR(extack, expr_info[i].attr);
			goto err2;
			goto err_release_rule;
		}

		if (expr_info[i].ops->validate)
@@ -3395,16 +3401,24 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		expr = nft_expr_next(expr);
	}

	if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
		flow = nft_flow_rule_create(net, rule);
		if (IS_ERR(flow)) {
			err = PTR_ERR(flow);
			goto err_release_rule;
		}
	}

	if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
		trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
		if (trans == NULL) {
			err = -ENOMEM;
			goto err2;
			goto err_destroy_flow_rule;
		}
		err = nft_delrule(&ctx, old_rule);
		if (err < 0) {
			nft_trans_destroy(trans);
			goto err2;
			goto err_destroy_flow_rule;
		}

		list_add_tail_rcu(&rule->list, &old_rule->list);
@@ -3412,7 +3426,7 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
		trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
		if (!trans) {
			err = -ENOMEM;
			goto err2;
			goto err_destroy_flow_rule;
		}

		if (info->nlh->nlmsg_flags & NLM_F_APPEND) {
@@ -3430,21 +3444,19 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
	kvfree(expr_info);
	chain->use++;

	if (flow)
		nft_trans_flow_rule(trans) = flow;

	if (nft_net->validate_state == NFT_VALIDATE_DO)
		return nft_table_validate(net, table);

	if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
		flow = nft_flow_rule_create(net, rule);
		if (IS_ERR(flow))
			return PTR_ERR(flow);

		nft_trans_flow_rule(trans) = flow;
	}

	return 0;
err2:

err_destroy_flow_rule:
	nft_flow_rule_destroy(flow);
err_release_rule:
	nf_tables_rule_release(&ctx, rule);
err1:
err_release_expr:
	for (i = 0; i < n; i++) {
		if (expr_info[i].ops) {
			module_put(expr_info[i].ops->type->owner);
@@ -8839,11 +8851,16 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
			nft_rule_expr_deactivate(&trans->ctx,
						 nft_trans_rule(trans),
						 NFT_TRANS_ABORT);
			if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
				nft_flow_rule_destroy(nft_trans_flow_rule(trans));
			break;
		case NFT_MSG_DELRULE:
			trans->ctx.chain->use++;
			nft_clear(trans->ctx.net, nft_trans_rule(trans));
			nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
			if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
				nft_flow_rule_destroy(nft_trans_flow_rule(trans));

			nft_trans_destroy(trans);
			break;
		case NFT_MSG_NEWSET:
+7 −27
Original line number Diff line number Diff line
@@ -54,15 +54,10 @@ static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
					struct nft_flow_rule *flow)
{
	struct nft_flow_match *match = &flow->match;
	struct nft_offload_ethertype ethertype;

	if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL) &&
	    match->key.basic.n_proto != htons(ETH_P_8021Q) &&
	    match->key.basic.n_proto != htons(ETH_P_8021AD))
		return;

	ethertype.value = match->key.basic.n_proto;
	ethertype.mask = match->mask.basic.n_proto;
	struct nft_offload_ethertype ethertype = {
		.value	= match->key.basic.n_proto,
		.mask	= match->mask.basic.n_proto,
	};

	if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_VLAN) &&
	    (match->key.vlan.vlan_tpid == htons(ETH_P_8021Q) ||
@@ -76,7 +71,9 @@ static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
		match->dissector.offset[FLOW_DISSECTOR_KEY_CVLAN] =
			offsetof(struct nft_flow_key, cvlan);
		match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN);
	} else {
	} else if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC) &&
		   (match->key.basic.n_proto == htons(ETH_P_8021Q) ||
		    match->key.basic.n_proto == htons(ETH_P_8021AD))) {
		match->key.basic.n_proto = match->key.vlan.vlan_tpid;
		match->mask.basic.n_proto = match->mask.vlan.vlan_tpid;
		match->key.vlan.vlan_tpid = ethertype.value;
@@ -594,23 +591,6 @@ int nft_flow_rule_offload_commit(struct net *net)
		}
	}

	list_for_each_entry(trans, &nft_net->commit_list, list) {
		if (trans->ctx.family != NFPROTO_NETDEV)
			continue;

		switch (trans->msg_type) {
		case NFT_MSG_NEWRULE:
		case NFT_MSG_DELRULE:
			if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
				continue;

			nft_flow_rule_destroy(nft_trans_flow_rule(trans));
			break;
		default:
			break;
		}
	}

	return err;
}

+3 −0
Original line number Diff line number Diff line
@@ -42,6 +42,9 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
	unsigned int offset = 0;
	int err;

	if (pkt->skb->protocol != htons(ETH_P_IPV6))
		goto err;

	err = ipv6_find_hdr(pkt->skb, &offset, priv->type, NULL, NULL);
	if (priv->flags & NFT_EXTHDR_F_PRESENT) {
		nft_reg_store8(dest, err >= 0);
+5 −0
Original line number Diff line number Diff line
@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
	struct nf_osf_data data;
	struct tcphdr _tcph;

	if (pkt->tprot != IPPROTO_TCP) {
		regs->verdict.code = NFT_BREAK;
		return;
	}

	tcp = skb_header_pointer(skb, ip_hdrlen(skb),
				 sizeof(struct tcphdr), &_tcph);
	if (!tcp) {
Loading