Commit 7da538c1 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) Wait for rcu grace period after releasing netns in ctnetlink,
   from Florian Westphal.

2) Incorrect command type in flowtable offload ndo invocation,
   from wenxu.

3) Incorrect callback type in flowtable offload flow tuple
   updates, also from wenxu.

4) Fix compile warning on flowtable offload infrastructure due to
   possible reference to uninitialized variable, from Nathan Chancellor.

5) Do not inline nf_ct_resolve_clash(), this is called from slow
   path / stress situations. From Florian Westphal.

6) Missing IPv6 flow selector description in flowtable offload.

7) Missing check for NETDEV_UNREGISTER in nf_tables offload
   infrastructure, from wenxu.

8) Update NAT selftest to use randomized netns names, from
   Florian Westphal.

9) Restore nfqueue bridge support, from Marco Oliverio.

10) Compilation warning in SCTP_CHUNKMAP_*() on xt_sctp header.
    From Phil Sutter.

11) Fix bogus lookup/get match for non-anonymous rbtree sets.

12) Missing netlink validation for NFT_SET_ELEM_INTERVAL_END
    elements.

13) Missing netlink validation for NFT_DATA_VALUE after
    nft_data_init().

14) If rule specifies no actions, offload infrastructure returns
    EOPNOTSUPP.

15) Module refcount leak in object updates.

16) Missing sanitization for ARP traffic from br_netfilter, from
    Eric Dumazet.

17) Compilation breakage on big-endian due to incorrect memcpy()
    size in the flowtable offload infrastructure.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f8fc57e8 7acd9378
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -41,19 +41,19 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) 		\
	do { 						\
		(chunkmap)[type / bytes(__u32)] |= 	\
			1 << (type % bytes(__u32));	\
			1u << (type % bytes(__u32));	\
	} while (0)

#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)		 	\
	do {							\
		(chunkmap)[type / bytes(__u32)] &= 		\
			~(1 << (type % bytes(__u32)));	\
			~(1u << (type % bytes(__u32)));	\
	} while (0)

#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) 			\
({								\
	((chunkmap)[type / bytes (__u32)] & 		\
		(1 << (type % bytes (__u32)))) ? 1: 0;	\
		(1u << (type % bytes (__u32)))) ? 1: 0;	\
})

#define SCTP_CHUNKMAP_RESET(chunkmap) \
+3 −0
Original line number Diff line number Diff line
@@ -662,6 +662,9 @@ static unsigned int br_nf_forward_arp(void *priv,
		nf_bridge_pull_encap_header(skb);
	}

	if (unlikely(!pskb_may_pull(skb, sizeof(struct arphdr))))
		return NF_DROP;

	if (arp_hdr(skb)->ar_pln != 4) {
		if (is_vlan_arp(skb, state->net))
			nf_bridge_push_encap_header(skb);
+4 −3
Original line number Diff line number Diff line
@@ -895,7 +895,8 @@ static void nf_ct_acct_merge(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
}

/* Resolve race on insertion if this protocol allows this. */
static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb,
static __cold noinline int
nf_ct_resolve_clash(struct net *net, struct sk_buff *skb,
		    enum ip_conntrack_info ctinfo,
		    struct nf_conntrack_tuple_hash *h)
{
+3 −0
Original line number Diff line number Diff line
@@ -3626,6 +3626,9 @@ static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)

	list_for_each_entry(net, net_exit_list, exit_list)
		ctnetlink_net_exit(net);

	/* wait for other cpus until they are done with ctnl_notifiers */
	synchronize_rcu();
}

static struct pernet_operations ctnetlink_net_ops = {
+45 −38
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ struct nf_flow_key {
	struct flow_dissector_key_basic			basic;
	union {
		struct flow_dissector_key_ipv4_addrs	ipv4;
		struct flow_dissector_key_ipv6_addrs	ipv6;
	};
	struct flow_dissector_key_tcp			tcp;
	struct flow_dissector_key_ports			tp;
@@ -57,6 +58,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_CONTROL, control);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
	NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);

@@ -69,9 +71,18 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
		key->ipv4.dst = tuple->dst_v4.s_addr;
		mask->ipv4.dst = 0xffffffff;
		break;
       case AF_INET6:
		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
		key->basic.n_proto = htons(ETH_P_IPV6);
		key->ipv6.src = tuple->src_v6;
		memset(&mask->ipv6.src, 0xff, sizeof(mask->ipv6.src));
		key->ipv6.dst = tuple->dst_v6;
		memset(&mask->ipv6.dst, 0xff, sizeof(mask->ipv6.dst));
		break;
	default:
		return -EOPNOTSUPP;
	}
	match->dissector.used_keys |= BIT(key->control.addr_type);
	mask->basic.n_proto = 0xffff;

	switch (tuple->l4proto) {
@@ -96,14 +107,13 @@ static int nf_flow_rule_match(struct nf_flow_match *match,

	match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL) |
				      BIT(FLOW_DISSECTOR_KEY_BASIC) |
				      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
				      BIT(FLOW_DISSECTOR_KEY_PORTS);
	return 0;
}

static void flow_offload_mangle(struct flow_action_entry *entry,
				enum flow_action_mangle_base htype,
				u32 offset, u8 *value, u8 *mask)
				enum flow_action_mangle_base htype, u32 offset,
				const __be32 *value, const __be32 *mask)
{
	entry->id = FLOW_ACTION_MANGLE;
	entry->mangle.htype = htype;
@@ -140,12 +150,12 @@ static int flow_offload_eth_src(struct net *net,
	memcpy(&val16, dev->dev_addr, 2);
	val = val16 << 16;
	flow_offload_mangle(entry0, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 4,
			    (u8 *)&val, (u8 *)&mask);
			    &val, &mask);

	mask = ~0xffffffff;
	memcpy(&val, dev->dev_addr + 2, 4);
	flow_offload_mangle(entry1, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 8,
			    (u8 *)&val, (u8 *)&mask);
			    &val, &mask);
	dev_put(dev);

	return 0;
@@ -170,13 +180,13 @@ static int flow_offload_eth_dst(struct net *net,
	mask = ~0xffffffff;
	memcpy(&val, n->ha, 4);
	flow_offload_mangle(entry0, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 0,
			    (u8 *)&val, (u8 *)&mask);
			    &val, &mask);

	mask = ~0x0000ffff;
	memcpy(&val16, n->ha + 4, 2);
	val = val16;
	flow_offload_mangle(entry1, FLOW_ACT_MANGLE_HDR_TYPE_ETH, 4,
			    (u8 *)&val, (u8 *)&mask);
			    &val, &mask);
	neigh_release(n);

	return 0;
@@ -206,7 +216,7 @@ static void flow_offload_ipv4_snat(struct net *net,
	}

	flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
			    (u8 *)&addr, (u8 *)&mask);
			    &addr, &mask);
}

static void flow_offload_ipv4_dnat(struct net *net,
@@ -233,12 +243,12 @@ static void flow_offload_ipv4_dnat(struct net *net,
	}

	flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP4, offset,
			    (u8 *)&addr, (u8 *)&mask);
			    &addr, &mask);
}

static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
				     unsigned int offset,
				     u8 *addr, u8 *mask)
				     const __be32 *addr, const __be32 *mask)
{
	struct flow_action_entry *entry;
	int i;
@@ -246,8 +256,7 @@ static void flow_offload_ipv6_mangle(struct nf_flow_rule *flow_rule,
	for (i = 0; i < sizeof(struct in6_addr) / sizeof(u32); i += sizeof(u32)) {
		entry = flow_action_entry_next(flow_rule);
		flow_offload_mangle(entry, FLOW_ACT_MANGLE_HDR_TYPE_IP6,
				    offset + i,
				    &addr[i], mask);
				    offset + i, &addr[i], mask);
	}
}

@@ -257,23 +266,23 @@ static void flow_offload_ipv6_snat(struct net *net,
				   struct nf_flow_rule *flow_rule)
{
	u32 mask = ~htonl(0xffffffff);
	const u8 *addr;
	const __be32 *addr;
	u32 offset;

	switch (dir) {
	case FLOW_OFFLOAD_DIR_ORIGINAL:
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v6.s6_addr;
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_v6.s6_addr32;
		offset = offsetof(struct ipv6hdr, saddr);
		break;
	case FLOW_OFFLOAD_DIR_REPLY:
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6.s6_addr;
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_v6.s6_addr32;
		offset = offsetof(struct ipv6hdr, daddr);
		break;
	default:
		return;
	}

	flow_offload_ipv6_mangle(flow_rule, offset, (u8 *)addr, (u8 *)&mask);
	flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
}

static void flow_offload_ipv6_dnat(struct net *net,
@@ -282,23 +291,23 @@ static void flow_offload_ipv6_dnat(struct net *net,
				   struct nf_flow_rule *flow_rule)
{
	u32 mask = ~htonl(0xffffffff);
	const u8 *addr;
	const __be32 *addr;
	u32 offset;

	switch (dir) {
	case FLOW_OFFLOAD_DIR_ORIGINAL:
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v6.s6_addr;
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.src_v6.s6_addr32;
		offset = offsetof(struct ipv6hdr, daddr);
		break;
	case FLOW_OFFLOAD_DIR_REPLY:
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6.s6_addr;
		addr = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_v6.s6_addr32;
		offset = offsetof(struct ipv6hdr, saddr);
		break;
	default:
		return;
	}

	flow_offload_ipv6_mangle(flow_rule, offset, (u8 *)addr, (u8 *)&mask);
	flow_offload_ipv6_mangle(flow_rule, offset, addr, &mask);
}

static int flow_offload_l4proto(const struct flow_offload *flow)
@@ -326,25 +335,24 @@ static void flow_offload_port_snat(struct net *net,
				   struct nf_flow_rule *flow_rule)
{
	struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
	u32 mask = ~htonl(0xffff0000);
	__be16 port;
	u32 mask = ~htonl(0xffff0000), port;
	u32 offset;

	switch (dir) {
	case FLOW_OFFLOAD_DIR_ORIGINAL:
		port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port;
		port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
		offset = 0; /* offsetof(struct tcphdr, source); */
		break;
	case FLOW_OFFLOAD_DIR_REPLY:
		port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port;
		port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port);
		offset = 0; /* offsetof(struct tcphdr, dest); */
		break;
	default:
		break;
		return;
	}

	port = htonl(port << 16);
	flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
			    (u8 *)&port, (u8 *)&mask);
			    &port, &mask);
}

static void flow_offload_port_dnat(struct net *net,
@@ -353,25 +361,24 @@ static void flow_offload_port_dnat(struct net *net,
				   struct nf_flow_rule *flow_rule)
{
	struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
	u32 mask = ~htonl(0xffff);
	__be16 port;
	u32 mask = ~htonl(0xffff), port;
	u32 offset;

	switch (dir) {
	case FLOW_OFFLOAD_DIR_ORIGINAL:
		port = flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port;
		port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_port);
		offset = 0; /* offsetof(struct tcphdr, source); */
		break;
	case FLOW_OFFLOAD_DIR_REPLY:
		port = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port;
		port = ntohs(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.src_port);
		offset = 0; /* offsetof(struct tcphdr, dest); */
		break;
	default:
		break;
		return;
	}

	port = htonl(port);
	flow_offload_mangle(entry, flow_offload_l4proto(flow), offset,
			    (u8 *)&port, (u8 *)&mask);
			    &port, &mask);
}

static void flow_offload_ipv4_checksum(struct net *net,
@@ -574,7 +581,7 @@ static int flow_offload_tuple_add(struct flow_offload_work *offload,
	cls_flow.rule = flow_rule->rule;

	list_for_each_entry(block_cb, &flowtable->flow_block.cb_list, list) {
		err = block_cb->cb(TC_SETUP_FT, &cls_flow,
		err = block_cb->cb(TC_SETUP_CLSFLOWER, &cls_flow,
				   block_cb->cb_priv);
		if (err < 0)
			continue;
@@ -599,7 +606,7 @@ static void flow_offload_tuple_del(struct flow_offload_work *offload,
			     &offload->flow->tuplehash[dir].tuple, &extack);

	list_for_each_entry(block_cb, &flowtable->flow_block.cb_list, list)
		block_cb->cb(TC_SETUP_FT, &cls_flow, block_cb->cb_priv);
		block_cb->cb(TC_SETUP_CLSFLOWER, &cls_flow, block_cb->cb_priv);

	offload->flow->flags |= FLOW_OFFLOAD_HW_DEAD;
}
@@ -656,7 +663,7 @@ static void flow_offload_tuple_stats(struct flow_offload_work *offload,
			     &offload->flow->tuplehash[dir].tuple, &extack);

	list_for_each_entry(block_cb, &flowtable->flow_block.cb_list, list)
		block_cb->cb(TC_SETUP_FT, &cls_flow, block_cb->cb_priv);
		block_cb->cb(TC_SETUP_CLSFLOWER, &cls_flow, block_cb->cb_priv);
	memcpy(stats, &cls_flow.stats, sizeof(*stats));
}

@@ -822,7 +829,7 @@ int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
	bo.extack	= &extack;
	INIT_LIST_HEAD(&bo.cb_list);

	err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
	err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_FT, &bo);
	if (err < 0)
		return err;

Loading