From: Jiri Pirko <jpirko@redhat.com> Date: Tue, 24 Aug 2010 17:13:34 -0400 Subject: [net] netfilter: fix crashes caused by fragment jumps Message-id: <20100824171333.GA2681@psychotron.redhat.com> Patchwork-id: 27806 O-Subject: [RHEL5.6 patch] BZ617268 net: netfilter: fix crashes in bridge netfilter caused by fragment jumps Bugzilla: 617268 RH-Acked-by: Neil Horman <nhorman@redhat.com> RH-Acked-by: Thomas Graf <tgraf@redhat.com> RH-Acked-by: David S. Miller <davem@redhat.com> BZ617268 https://bugzilla.redhat.com/show_bug.cgi?id=617268 Description: When fragments from bridge netfilter are passed to IPv4 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 was causing 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. Upstream: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8fa9ff6849bb86c59cc2ea9faadf3cb2d5223497 Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=2682317 Sucessfully tested by customer. Jirka Signed-off-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/include/net/ip.h b/include/net/ip.h index f8c889c..8bc7617 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -329,6 +329,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/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 3b3a393..453d2aa 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -31,6 +31,7 @@ #define ASSERT_READ_LOCK(x) #define ASSERT_WRITE_LOCK(x) +#include <linux/netfilter_bridge.h> #include <linux/netfilter_ipv4/ip_conntrack.h> #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> #include <linux/netfilter_ipv4/ip_conntrack_core.h> @@ -430,6 +431,20 @@ static unsigned int ip_conntrack_help(unsigned int hooknum, return NF_ACCEPT; } +static enum ip_defrag_users ip_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_IP_PRE_ROUTING) + return IP_DEFRAG_CONNTRACK_IN; + else + return IP_DEFRAG_CONNTRACK_OUT; +} + static unsigned int ip_conntrack_defrag(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, @@ -449,10 +464,8 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, #endif /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { - *pskb = ip_ct_gather_frags(*pskb, - hooknum == NF_IP_PRE_ROUTING ? - IP_DEFRAG_CONNTRACK_IN : - IP_DEFRAG_CONNTRACK_OUT); + enum ip_defrag_users user = ip_ct_defrag_user(hooknum, *pskb); + *pskb = ip_ct_gather_frags(*pskb, user); if (!*pskb) return NF_STOLEN; }