From mboxrd@z Thu Jan 1 00:00:00 1970 From: Patrick McHardy Subject: [PATCH -stable 02/02]: netfilter: fix crashes in bridge netfilter caused by fragment jumps Date: Thu, 17 Dec 2009 16:18:06 +0100 Message-ID: <4B2A4BAE.3020704@trash.net> References: <4B2A4B84.9070802@trash.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------080101070804050409020503" Cc: Netfilter Development Mailinglist , Linux Netdev List , "David S. Miller" To: stable@kernel.org Return-path: In-Reply-To: <4B2A4B84.9070802@trash.net> Sender: netfilter-devel-owner@vger.kernel.org List-Id: netdev.vger.kernel.org This is a multi-part message in MIME format. --------------080101070804050409020503 Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: 7bit --------------080101070804050409020503 Content-Type: text/x-patch; name="02.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="02.diff" commit 182da5cb625b7e55bbf188c74861699f851feea8 Author: Patrick McHardy Date: Thu Dec 17 16:08:58 2009 +0100 netfilter: fix crashes in bridge netfilter caused by fragment jumps Upstream commit 8fa9ff68: When fragments from bridge netfilter are passed to IPv4 or IPv6 conntrack and a reassembly queue with the same fragment key already exists from reassembling a similar packet received on a different device (f.i. with multicasted fragments), the reassembled packet might continue on a different codepath than where the head fragment originated. This can cause crashes in bridge netfilter when a fragment received on a non-bridge device (and thus with skb->nf_bridge == NULL) continues through the bridge netfilter code. Add a new reassembly identifier for packets originating from bridge netfilter and use it to put those packets in insolated queues. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=14805 Reported-and-Tested-by: Chong Qiao Signed-off-by: Patrick McHardy diff --git a/include/net/ip.h b/include/net/ip.h index 2f47e54..69db943 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -342,6 +342,7 @@ enum ip_defrag_users IP_DEFRAG_CALL_RA_CHAIN, IP_DEFRAG_CONNTRACK_IN, IP_DEFRAG_CONNTRACK_OUT, + IP_DEFRAG_CONNTRACK_BRIDGE_IN, IP_DEFRAG_VS_IN, IP_DEFRAG_VS_OUT, IP_DEFRAG_VS_FWD diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a496499..639bbf0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -358,6 +358,7 @@ enum ip6_defrag_users { IP6_DEFRAG_LOCAL_DELIVER, IP6_DEFRAG_CONNTRACK_IN, IP6_DEFRAG_CONNTRACK_OUT, + IP6_DEFRAG_CONNTRACK_BRIDGE_IN, }; struct ip6_create_arg { diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index fa2d6b6..331ead3 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -34,6 +35,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) return err; } +static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, + struct sk_buff *skb) +{ +#ifdef CONFIG_BRIDGE_NETFILTER + if (skb->nf_bridge && + skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) + return IP_DEFRAG_CONNTRACK_BRIDGE_IN; +#endif + if (hooknum == NF_INET_PRE_ROUTING) + return IP_DEFRAG_CONNTRACK_IN; + else + return IP_DEFRAG_CONNTRACK_OUT; +} + static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, @@ -50,10 +65,8 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, #endif /* Gather fragments. */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { - if (nf_ct_ipv4_gather_frags(skb, - hooknum == NF_INET_PRE_ROUTING ? - IP_DEFRAG_CONNTRACK_IN : - IP_DEFRAG_CONNTRACK_OUT)) + enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb); + if (nf_ct_ipv4_gather_frags(skb, user)) return NF_STOLEN; } return NF_ACCEPT; diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c0a82fe..0956eba 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -190,6 +191,11 @@ out: static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, struct sk_buff *skb) { +#ifdef CONFIG_BRIDGE_NETFILTER + if (skb->nf_bridge && + skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) + return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; +#endif if (hooknum == NF_INET_PRE_ROUTING) return IP6_DEFRAG_CONNTRACK_IN; else --------------080101070804050409020503--