Commit 963bdfc7 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) Set VLAN tag in tcp reset/icmp unreachable packets to reject
   connections in the bridge family, from Michael Braun.

2) Incorrect subcounter flag update in ipset, from Phil Sutter.

3) Possible buffer overflow in the pptp conntrack helper, based
   on patch from Dan Carpenter.

4) Restore userspace conntrack helper hook logic that broke after
   hook consolidation rework.

5) Unbreak userspace conntrack helper registration via
   nfnetlink_cthelper.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1a6da4fc 703acd70
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <uapi/linux/netfilter/nf_conntrack_tuple_common.h>

extern const char *const pptp_msg_name[];
extern const char *const pptp_msg_name(u_int16_t msg);

/* state of the control session */
enum pptp_ctrlsess_state {
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,12 @@ static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
	ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source);
	eth->h_proto = eth_hdr(oldskb)->h_proto;
	skb_pull(nskb, ETH_HLEN);

	if (skb_vlan_tag_present(oldskb)) {
		u16 vid = skb_vlan_tag_get(oldskb);

		__vlan_hwaccel_put_tag(nskb, oldskb->vlan_proto, vid);
	}
}

static int nft_bridge_iphdr_validate(struct sk_buff *skb)
+2 −5
Original line number Diff line number Diff line
@@ -166,8 +166,7 @@ pptp_outbound_pkt(struct sk_buff *skb,
		break;
	default:
		pr_debug("unknown outbound packet 0x%04x:%s\n", msg,
			 msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] :
					       pptp_msg_name[0]);
			 pptp_msg_name(msg));
		fallthrough;
	case PPTP_SET_LINK_INFO:
		/* only need to NAT in case PAC is behind NAT box */
@@ -268,9 +267,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
		pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID);
		break;
	default:
		pr_debug("unknown inbound packet %s\n",
			 msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] :
					       pptp_msg_name[0]);
		pr_debug("unknown inbound packet %s\n", pptp_msg_name(msg));
		fallthrough;
	case PPTP_START_SESSION_REQUEST:
	case PPTP_START_SESSION_REPLY:
+1 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
	/* Don't lookup sub-counters at all */
	opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
	if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
		opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
		opt->cmdflags |= IPSET_FLAG_SKIP_COUNTER_UPDATE;
	list_for_each_entry_rcu(e, &map->members, list) {
		ret = ip_set_test(e->id, skb, par, opt);
		if (ret <= 0)
+72 −6
Original line number Diff line number Diff line
@@ -2016,22 +2016,18 @@ static void nf_conntrack_attach(struct sk_buff *nskb, const struct sk_buff *skb)
	nf_conntrack_get(skb_nfct(nskb));
}

static int nf_conntrack_update(struct net *net, struct sk_buff *skb)
static int __nf_conntrack_update(struct net *net, struct sk_buff *skb,
				 struct nf_conn *ct)
{
	struct nf_conntrack_tuple_hash *h;
	struct nf_conntrack_tuple tuple;
	enum ip_conntrack_info ctinfo;
	struct nf_nat_hook *nat_hook;
	unsigned int status;
	struct nf_conn *ct;
	int dataoff;
	u16 l3num;
	u8 l4num;

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct || nf_ct_is_confirmed(ct))
		return 0;

	l3num = nf_ct_l3num(ct);

	dataoff = get_l4proto(skb, skb_network_offset(skb), l3num, &l4num);
@@ -2088,6 +2084,76 @@ static int nf_conntrack_update(struct net *net, struct sk_buff *skb)
	return 0;
}

/* This packet is coming from userspace via nf_queue, complete the packet
 * processing after the helper invocation in nf_confirm().
 */
static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
			       enum ip_conntrack_info ctinfo)
{
	const struct nf_conntrack_helper *helper;
	const struct nf_conn_help *help;
	unsigned int protoff;

	help = nfct_help(ct);
	if (!help)
		return 0;

	helper = rcu_dereference(help->helper);
	if (!(helper->flags & NF_CT_HELPER_F_USERSPACE))
		return 0;

	switch (nf_ct_l3num(ct)) {
	case NFPROTO_IPV4:
		protoff = skb_network_offset(skb) + ip_hdrlen(skb);
		break;
#if IS_ENABLED(CONFIG_IPV6)
	case NFPROTO_IPV6: {
		__be16 frag_off;
		u8 pnum;

		pnum = ipv6_hdr(skb)->nexthdr;
		protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
					   &frag_off);
		if (protoff < 0 || (frag_off & htons(~0x7)) != 0)
			return 0;
		break;
	}
#endif
	default:
		return 0;
	}

	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
	    !nf_is_loopback_packet(skb)) {
		if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
			return -1;
		}
	}

	/* We've seen it coming out the other side: confirm it */
	return nf_conntrack_confirm(skb) == NF_DROP ? - 1 : 0;
}

static int nf_conntrack_update(struct net *net, struct sk_buff *skb)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct;
	int err;

	ct = nf_ct_get(skb, &ctinfo);
	if (!ct)
		return 0;

	if (!nf_ct_is_confirmed(ct)) {
		err = __nf_conntrack_update(net, skb, ct);
		if (err < 0)
			return err;
	}

	return nf_confirm_cthelper(skb, ct, ctinfo);
}

static bool nf_conntrack_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
				       const struct sk_buff *skb)
{
Loading