diff options
author | Patrick McHardy <kaber@trash.net> | 2008-02-19 20:17:52 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-19 20:17:52 -0500 |
commit | e2b58a67b91dec07dfb40ca2056c64011ce8489d (patch) | |
tree | 46e258092c2401b9cf6bc232ecfe96248a51982e /net/ipv6 | |
parent | 94cb1503c799c0197e7ef5bad606fee5c84b99d8 (diff) |
[NETFILTER]: {ip,ip6,nfnetlink}_queue: fix SKB_LINEAR_ASSERT when mangling packet data
As reported by Tomas Simonaitis <tomas.simonaitis@gmail.com>,
inserting new data in skbs queued over {ip,ip6,nfnetlink}_queue
triggers a SKB_LINEAR_ASSERT in skb_put().
Going back through the git history, it seems this bug is present since
at least 2.6.12-rc2, probably even since the removal of
skb_linearize() for netfilter.
Linearize non-linear skbs through skb_copy_expand() when enlarging
them. Tested by Thomas, fixes bugzilla #9933.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e869916b05f1..cc2f9afcf808 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -285,8 +285,8 @@ static int | |||
285 | ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) | 285 | ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) |
286 | { | 286 | { |
287 | int diff; | 287 | int diff; |
288 | int err; | ||
289 | struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; | 288 | struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; |
289 | struct sk_buff *nskb; | ||
290 | 290 | ||
291 | if (v->data_len < sizeof(*user_iph)) | 291 | if (v->data_len < sizeof(*user_iph)) |
292 | return 0; | 292 | return 0; |
@@ -298,14 +298,16 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) | |||
298 | if (v->data_len > 0xFFFF) | 298 | if (v->data_len > 0xFFFF) |
299 | return -EINVAL; | 299 | return -EINVAL; |
300 | if (diff > skb_tailroom(e->skb)) { | 300 | if (diff > skb_tailroom(e->skb)) { |
301 | err = pskb_expand_head(e->skb, 0, | 301 | nskb = skb_copy_expand(e->skb, 0, |
302 | diff - skb_tailroom(e->skb), | 302 | diff - skb_tailroom(e->skb), |
303 | GFP_ATOMIC); | 303 | GFP_ATOMIC); |
304 | if (err) { | 304 | if (!nskb) { |
305 | printk(KERN_WARNING "ip6_queue: OOM " | 305 | printk(KERN_WARNING "ip6_queue: OOM " |
306 | "in mangle, dropping packet\n"); | 306 | "in mangle, dropping packet\n"); |
307 | return err; | 307 | return -ENOMEM; |
308 | } | 308 | } |
309 | kfree_skb(e->skb); | ||
310 | e->skb = nskb; | ||
309 | } | 311 | } |
310 | skb_put(e->skb, diff); | 312 | skb_put(e->skb, diff); |
311 | } | 313 | } |