]>
Commit | Line | Data |
---|---|---|
80e6ae8f GKH |
1 | From 8fa9ff6849bb86c59cc2ea9faadf3cb2d5223497 Mon Sep 17 00:00:00 2001 |
2 | From: Patrick McHardy <kaber@trash.net> | |
3 | Date: Tue, 15 Dec 2009 16:59:59 +0100 | |
4 | Subject: netfilter: fix crashes in bridge netfilter caused by fragment jumps | |
5 | ||
6 | From: Patrick McHardy <kaber@trash.net> | |
7 | ||
8 | commit 8fa9ff6849bb86c59cc2ea9faadf3cb2d5223497 upstream. | |
9 | ||
10 | When fragments from bridge netfilter are passed to IPv4 or IPv6 conntrack | |
11 | and a reassembly queue with the same fragment key already exists from | |
12 | reassembling a similar packet received on a different device (f.i. with | |
13 | multicasted fragments), the reassembled packet might continue on a different | |
14 | codepath than where the head fragment originated. This can cause crashes | |
15 | in bridge netfilter when a fragment received on a non-bridge device (and | |
16 | thus with skb->nf_bridge == NULL) continues through the bridge netfilter | |
17 | code. | |
18 | ||
19 | Add a new reassembly identifier for packets originating from bridge | |
20 | netfilter and use it to put those packets in insolated queues. | |
21 | ||
22 | Fixes http://bugzilla.kernel.org/show_bug.cgi?id=14805 | |
23 | ||
24 | Reported-and-Tested-by: Chong Qiao <qiaochong@loongson.cn> | |
25 | Signed-off-by: Patrick McHardy <kaber@trash.net> | |
26 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
27 | ||
28 | --- | |
29 | include/net/ip.h | 1 + | |
30 | include/net/ipv6.h | 1 + | |
31 | net/ipv4/netfilter/nf_defrag_ipv4.c | 21 +++++++++++++++++---- | |
32 | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 6 ++++++ | |
33 | 4 files changed, 25 insertions(+), 4 deletions(-) | |
34 | ||
35 | --- a/include/net/ip.h | |
36 | +++ b/include/net/ip.h | |
37 | @@ -342,6 +342,7 @@ enum ip_defrag_users | |
38 | IP_DEFRAG_CALL_RA_CHAIN, | |
39 | IP_DEFRAG_CONNTRACK_IN, | |
40 | IP_DEFRAG_CONNTRACK_OUT, | |
41 | + IP_DEFRAG_CONNTRACK_BRIDGE_IN, | |
42 | IP_DEFRAG_VS_IN, | |
43 | IP_DEFRAG_VS_OUT, | |
44 | IP_DEFRAG_VS_FWD | |
45 | --- a/include/net/ipv6.h | |
46 | +++ b/include/net/ipv6.h | |
47 | @@ -358,6 +358,7 @@ enum ip6_defrag_users { | |
48 | IP6_DEFRAG_LOCAL_DELIVER, | |
49 | IP6_DEFRAG_CONNTRACK_IN, | |
50 | IP6_DEFRAG_CONNTRACK_OUT, | |
51 | + IP6_DEFRAG_CONNTRACK_BRIDGE_IN, | |
52 | }; | |
53 | ||
54 | struct ip6_create_arg { | |
55 | --- a/net/ipv4/netfilter/nf_defrag_ipv4.c | |
56 | +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c | |
57 | @@ -14,6 +14,7 @@ | |
58 | #include <net/route.h> | |
59 | #include <net/ip.h> | |
60 | ||
61 | +#include <linux/netfilter_bridge.h> | |
62 | #include <linux/netfilter_ipv4.h> | |
63 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | |
64 | ||
65 | @@ -34,6 +35,20 @@ static int nf_ct_ipv4_gather_frags(struc | |
66 | return err; | |
67 | } | |
68 | ||
69 | +static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, | |
70 | + struct sk_buff *skb) | |
71 | +{ | |
72 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
73 | + if (skb->nf_bridge && | |
74 | + skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | |
75 | + return IP_DEFRAG_CONNTRACK_BRIDGE_IN; | |
76 | +#endif | |
77 | + if (hooknum == NF_INET_PRE_ROUTING) | |
78 | + return IP_DEFRAG_CONNTRACK_IN; | |
79 | + else | |
80 | + return IP_DEFRAG_CONNTRACK_OUT; | |
81 | +} | |
82 | + | |
83 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | |
84 | struct sk_buff *skb, | |
85 | const struct net_device *in, | |
86 | @@ -50,10 +65,8 @@ static unsigned int ipv4_conntrack_defra | |
87 | #endif | |
88 | /* Gather fragments. */ | |
89 | if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { | |
90 | - if (nf_ct_ipv4_gather_frags(skb, | |
91 | - hooknum == NF_INET_PRE_ROUTING ? | |
92 | - IP_DEFRAG_CONNTRACK_IN : | |
93 | - IP_DEFRAG_CONNTRACK_OUT)) | |
94 | + enum ip_defrag_users user = nf_ct_defrag_user(hooknum, skb); | |
95 | + if (nf_ct_ipv4_gather_frags(skb, user)) | |
96 | return NF_STOLEN; | |
97 | } | |
98 | return NF_ACCEPT; | |
99 | --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |
100 | +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |
101 | @@ -20,6 +20,7 @@ | |
102 | #include <net/ipv6.h> | |
103 | #include <net/inet_frag.h> | |
104 | ||
105 | +#include <linux/netfilter_bridge.h> | |
106 | #include <linux/netfilter_ipv6.h> | |
107 | #include <net/netfilter/nf_conntrack.h> | |
108 | #include <net/netfilter/nf_conntrack_helper.h> | |
109 | @@ -190,6 +191,11 @@ out: | |
110 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | |
111 | struct sk_buff *skb) | |
112 | { | |
113 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
114 | + if (skb->nf_bridge && | |
115 | + skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | |
116 | + return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; | |
117 | +#endif | |
118 | if (hooknum == NF_INET_PRE_ROUTING) | |
119 | return IP6_DEFRAG_CONNTRACK_IN; | |
120 | else |