aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-12-15 10:59:59 -0500
committerPatrick McHardy <kaber@trash.net>2009-12-15 10:59:59 -0500
commit8fa9ff6849bb86c59cc2ea9faadf3cb2d5223497 (patch)
tree42c1cc382a9cfbb2907ab1471418404f874d53f2 /net
parent0b5ccb2ee250136dd7385b1c7da28417d0d4d32d (diff)
netfilter: fix crashes in bridge netfilter caused by fragment jumps
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 <qiaochong@loongson.cn> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c21
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c6
2 files changed, 23 insertions, 4 deletions
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index fa2d6b6fc3e5..331ead3ebd1b 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -14,6 +14,7 @@
14#include <net/route.h> 14#include <net/route.h>
15#include <net/ip.h> 15#include <net/ip.h>
16 16
17#include <linux/netfilter_bridge.h>
17#include <linux/netfilter_ipv4.h> 18#include <linux/netfilter_ipv4.h>
18#include <net/netfilter/ipv4/nf_defrag_ipv4.h> 19#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
19 20
@@ -34,6 +35,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
34 return err; 35 return err;
35} 36}
36 37
38static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
39 struct sk_buff *skb)
40{
41#ifdef CONFIG_BRIDGE_NETFILTER
42 if (skb->nf_bridge &&
43 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
44 return IP_DEFRAG_CONNTRACK_BRIDGE_IN;
45#endif
46 if (hooknum == NF_INET_PRE_ROUTING)
47 return IP_DEFRAG_CONNTRACK_IN;
48 else
49 return IP_DEFRAG_CONNTRACK_OUT;
50}
51
37static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 52static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
38 struct sk_buff *skb, 53 struct sk_buff *skb,
39 const struct net_device *in, 54 const struct net_device *in,
@@ -50,10 +65,8 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
50#endif 65#endif
51 /* Gather fragments. */ 66 /* Gather fragments. */
52 if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { 67 if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
53 if (nf_ct_ipv4_gather_frags(skb, 68 enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb);
54 hooknum == NF_INET_PRE_ROUTING ? 69 if (nf_ct_ipv4_gather_frags(skb, user))
55 IP_DEFRAG_CONNTRACK_IN :
56 IP_DEFRAG_CONNTRACK_OUT))
57 return NF_STOLEN; 70 return NF_STOLEN;
58 } 71 }
59 return NF_ACCEPT; 72 return NF_ACCEPT;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index c0a82fe78321..0956ebabbff2 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -20,6 +20,7 @@
20#include <net/ipv6.h> 20#include <net/ipv6.h>
21#include <net/inet_frag.h> 21#include <net/inet_frag.h>
22 22
23#include <linux/netfilter_bridge.h>
23#include <linux/netfilter_ipv6.h> 24#include <linux/netfilter_ipv6.h>
24#include <net/netfilter/nf_conntrack.h> 25#include <net/netfilter/nf_conntrack.h>
25#include <net/netfilter/nf_conntrack_helper.h> 26#include <net/netfilter/nf_conntrack_helper.h>
@@ -190,6 +191,11 @@ out:
190static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, 191static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
191 struct sk_buff *skb) 192 struct sk_buff *skb)
192{ 193{
194#ifdef CONFIG_BRIDGE_NETFILTER
195 if (skb->nf_bridge &&
196 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
197 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN;
198#endif
193 if (hooknum == NF_INET_PRE_ROUTING) 199 if (hooknum == NF_INET_PRE_ROUTING)
194 return IP6_DEFRAG_CONNTRACK_IN; 200 return IP6_DEFRAG_CONNTRACK_IN;
195 else 201 else