]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.3/ipv6-reassembly-use-seperate-reassembly-queues-for-conntrack-and-local-delivery.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.3 / ipv6-reassembly-use-seperate-reassembly-queues-for-conntrack-and-local-delivery.patch
1 From 0b5ccb2ee250136dd7385b1c7da28417d0d4d32d Mon Sep 17 00:00:00 2001
2 From: Patrick McHardy <kaber@trash.net>
3 Date: Tue, 15 Dec 2009 16:59:18 +0100
4 Subject: ipv6: reassembly: use seperate reassembly queues for conntrack and local delivery
5
6 From: Patrick McHardy <kaber@trash.net>
7
8 commit 0b5ccb2ee250136dd7385b1c7da28417d0d4d32d upstream.
9
10 Currently the same reassembly queue might be used for packets reassembled
11 by conntrack in different positions in the stack (PREROUTING/LOCAL_OUT),
12 as well as local delivery. This can cause "packet jumps" when the fragment
13 completing a reassembled packet is queued from a different position in the
14 stack than the previous ones.
15
16 Add a "user" identifier to the reassembly queue key to seperate the queues
17 of each caller, similar to what we do for IPv4.
18
19 Signed-off-by: Patrick McHardy <kaber@trash.net>
20 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
21
22 ---
23 include/net/ipv6.h | 7 +++++++
24 include/net/netfilter/ipv6/nf_conntrack_ipv6.h | 2 +-
25 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 13 +++++++++++--
26 net/ipv6/netfilter/nf_conntrack_reasm.c | 7 ++++---
27 net/ipv6/reassembly.c | 5 ++++-
28 5 files changed, 27 insertions(+), 7 deletions(-)
29
30 --- a/include/net/ipv6.h
31 +++ b/include/net/ipv6.h
32 @@ -354,8 +354,15 @@ static inline int ipv6_prefix_equal(cons
33
34 struct inet_frag_queue;
35
36 +enum ip6_defrag_users {
37 + IP6_DEFRAG_LOCAL_DELIVER,
38 + IP6_DEFRAG_CONNTRACK_IN,
39 + IP6_DEFRAG_CONNTRACK_OUT,
40 +};
41 +
42 struct ip6_create_arg {
43 __be32 id;
44 + u32 user;
45 struct in6_addr *src;
46 struct in6_addr *dst;
47 };
48 --- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
49 +++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
50 @@ -9,7 +9,7 @@ extern struct nf_conntrack_l4proto nf_co
51
52 extern int nf_ct_frag6_init(void);
53 extern void nf_ct_frag6_cleanup(void);
54 -extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb);
55 +extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
56 extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
57 struct net_device *in,
58 struct net_device *out,
59 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
60 +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
61 @@ -187,6 +187,16 @@ out:
62 return nf_conntrack_confirm(skb);
63 }
64
65 +static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
66 + struct sk_buff *skb)
67 +{
68 + if (hooknum == NF_INET_PRE_ROUTING)
69 + return IP6_DEFRAG_CONNTRACK_IN;
70 + else
71 + return IP6_DEFRAG_CONNTRACK_OUT;
72 +
73 +}
74 +
75 static unsigned int ipv6_defrag(unsigned int hooknum,
76 struct sk_buff *skb,
77 const struct net_device *in,
78 @@ -199,8 +209,7 @@ static unsigned int ipv6_defrag(unsigned
79 if (skb->nfct)
80 return NF_ACCEPT;
81
82 - reasm = nf_ct_frag6_gather(skb);
83 -
84 + reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
85 /* queued */
86 if (reasm == NULL)
87 return NF_STOLEN;
88 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c
89 +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
90 @@ -170,13 +170,14 @@ out:
91 /* Creation primitives. */
92
93 static __inline__ struct nf_ct_frag6_queue *
94 -fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
95 +fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
96 {
97 struct inet_frag_queue *q;
98 struct ip6_create_arg arg;
99 unsigned int hash;
100
101 arg.id = id;
102 + arg.user = user;
103 arg.src = src;
104 arg.dst = dst;
105
106 @@ -561,7 +562,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *
107 return 0;
108 }
109
110 -struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
111 +struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
112 {
113 struct sk_buff *clone;
114 struct net_device *dev = skb->dev;
115 @@ -607,7 +608,7 @@ struct sk_buff *nf_ct_frag6_gather(struc
116 if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh)
117 nf_ct_frag6_evictor();
118
119 - fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
120 + fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr);
121 if (fq == NULL) {
122 pr_debug("Can't find and can't create new queue\n");
123 goto ret_orig;
124 --- a/net/ipv6/reassembly.c
125 +++ b/net/ipv6/reassembly.c
126 @@ -72,6 +72,7 @@ struct frag_queue
127 struct inet_frag_queue q;
128
129 __be32 id; /* fragment id */
130 + u32 user;
131 struct in6_addr saddr;
132 struct in6_addr daddr;
133
134 @@ -141,7 +142,7 @@ int ip6_frag_match(struct inet_frag_queu
135 struct ip6_create_arg *arg = a;
136
137 fq = container_of(q, struct frag_queue, q);
138 - return (fq->id == arg->id &&
139 + return (fq->id == arg->id && fq->user == arg->user &&
140 ipv6_addr_equal(&fq->saddr, arg->src) &&
141 ipv6_addr_equal(&fq->daddr, arg->dst));
142 }
143 @@ -163,6 +164,7 @@ void ip6_frag_init(struct inet_frag_queu
144 struct ip6_create_arg *arg = a;
145
146 fq->id = arg->id;
147 + fq->user = arg->user;
148 ipv6_addr_copy(&fq->saddr, arg->src);
149 ipv6_addr_copy(&fq->daddr, arg->dst);
150 }
151 @@ -244,6 +246,7 @@ fq_find(struct net *net, __be32 id, stru
152 unsigned int hash;
153
154 arg.id = id;
155 + arg.user = IP6_DEFRAG_LOCAL_DELIVER;
156 arg.src = src;
157 arg.dst = dst;
158