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/netfilter | |
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/netfilter')
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index a48b20fe9cd6..0043d3a9f87e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -443,8 +443,8 @@ err_out: | |||
443 | static int | 443 | static int |
444 | nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) | 444 | nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) |
445 | { | 445 | { |
446 | struct sk_buff *nskb; | ||
446 | int diff; | 447 | int diff; |
447 | int err; | ||
448 | 448 | ||
449 | diff = data_len - e->skb->len; | 449 | diff = data_len - e->skb->len; |
450 | if (diff < 0) { | 450 | if (diff < 0) { |
@@ -454,14 +454,16 @@ nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e) | |||
454 | if (data_len > 0xFFFF) | 454 | if (data_len > 0xFFFF) |
455 | return -EINVAL; | 455 | return -EINVAL; |
456 | if (diff > skb_tailroom(e->skb)) { | 456 | if (diff > skb_tailroom(e->skb)) { |
457 | err = pskb_expand_head(e->skb, 0, | 457 | nskb = skb_copy_expand(e->skb, 0, |
458 | diff - skb_tailroom(e->skb), | 458 | diff - skb_tailroom(e->skb), |
459 | GFP_ATOMIC); | 459 | GFP_ATOMIC); |
460 | if (err) { | 460 | if (!nskb) { |
461 | printk(KERN_WARNING "nf_queue: OOM " | 461 | printk(KERN_WARNING "nf_queue: OOM " |
462 | "in mangle, dropping packet\n"); | 462 | "in mangle, dropping packet\n"); |
463 | return err; | 463 | return -ENOMEM; |
464 | } | 464 | } |
465 | kfree_skb(e->skb); | ||
466 | e->skb = nskb; | ||
465 | } | 467 | } |
466 | skb_put(e->skb, diff); | 468 | skb_put(e->skb, diff); |
467 | } | 469 | } |