diff options
-rw-r--r-- | net/netfilter/core.c | 7 | ||||
-rw-r--r-- | net/netfilter/nf_queue.c | 17 |
2 files changed, 15 insertions, 9 deletions
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 91d66d2f8cd9..0c5b796ef527 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -181,8 +181,11 @@ next_hook: | |||
181 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { | 181 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { |
182 | ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, | 182 | ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, |
183 | verdict >> NF_VERDICT_BITS); | 183 | verdict >> NF_VERDICT_BITS); |
184 | if (ret == -ECANCELED) | 184 | if (ret < 0) { |
185 | goto next_hook; | 185 | if (ret == -ECANCELED) |
186 | goto next_hook; | ||
187 | kfree_skb(skb); | ||
188 | } | ||
186 | ret = 0; | 189 | ret = 0; |
187 | } | 190 | } |
188 | rcu_read_unlock(); | 191 | rcu_read_unlock(); |
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index ad25c7e726bc..5c4b730a2e68 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c | |||
@@ -163,9 +163,8 @@ static int __nf_queue(struct sk_buff *skb, | |||
163 | 163 | ||
164 | /* If it's going away, ignore hook. */ | 164 | /* If it's going away, ignore hook. */ |
165 | if (!try_module_get(entry->elem->owner)) { | 165 | if (!try_module_get(entry->elem->owner)) { |
166 | rcu_read_unlock(); | 166 | status = -ECANCELED; |
167 | kfree(entry); | 167 | goto err_unlock; |
168 | return -ECANCELED; | ||
169 | } | 168 | } |
170 | /* Bump dev refs so they don't vanish while packet is out */ | 169 | /* Bump dev refs so they don't vanish while packet is out */ |
171 | if (indev) | 170 | if (indev) |
@@ -198,7 +197,6 @@ static int __nf_queue(struct sk_buff *skb, | |||
198 | err_unlock: | 197 | err_unlock: |
199 | rcu_read_unlock(); | 198 | rcu_read_unlock(); |
200 | err: | 199 | err: |
201 | kfree_skb(skb); | ||
202 | kfree(entry); | 200 | kfree(entry); |
203 | return status; | 201 | return status; |
204 | } | 202 | } |
@@ -229,7 +227,6 @@ int nf_queue(struct sk_buff *skb, | |||
229 | } | 227 | } |
230 | 228 | ||
231 | segs = skb_gso_segment(skb, 0); | 229 | segs = skb_gso_segment(skb, 0); |
232 | kfree_skb(skb); | ||
233 | /* Does not use PTR_ERR to limit the number of error codes that can be | 230 | /* Does not use PTR_ERR to limit the number of error codes that can be |
234 | * returned by nf_queue. For instance, callers rely on -ECANCELED to mean | 231 | * returned by nf_queue. For instance, callers rely on -ECANCELED to mean |
235 | * 'ignore this hook'. | 232 | * 'ignore this hook'. |
@@ -253,8 +250,11 @@ int nf_queue(struct sk_buff *skb, | |||
253 | segs = nskb; | 250 | segs = nskb; |
254 | } while (segs); | 251 | } while (segs); |
255 | 252 | ||
253 | /* also free orig skb if only some segments were queued */ | ||
256 | if (unlikely(err && queued)) | 254 | if (unlikely(err && queued)) |
257 | err = 0; | 255 | err = 0; |
256 | if (err == 0) | ||
257 | kfree_skb(skb); | ||
258 | return err; | 258 | return err; |
259 | } | 259 | } |
260 | 260 | ||
@@ -300,8 +300,11 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) | |||
300 | err = __nf_queue(skb, elem, entry->pf, entry->hook, | 300 | err = __nf_queue(skb, elem, entry->pf, entry->hook, |
301 | entry->indev, entry->outdev, entry->okfn, | 301 | entry->indev, entry->outdev, entry->okfn, |
302 | verdict >> NF_VERDICT_BITS); | 302 | verdict >> NF_VERDICT_BITS); |
303 | if (err == -ECANCELED) | 303 | if (err < 0) { |
304 | goto next_hook; | 304 | if (err == -ECANCELED) |
305 | goto next_hook; | ||
306 | kfree_skb(skb); | ||
307 | } | ||
305 | break; | 308 | break; |
306 | case NF_STOLEN: | 309 | case NF_STOLEN: |
307 | default: | 310 | default: |