diff options
author | Patrick McHardy <kaber@trash.net> | 2008-02-25 15:01:01 +0100 |
---|---|---|
committer | Chris Wright <chrisw@sous-sol.org> | 2008-03-24 11:47:22 -0700 |
commit | ca02fcbe2193c3947466f5659fc7ac7b851ea20b (patch) | |
tree | 1e001172e1359a97853f73e1fc60fa0bdfefd113 | |
parent | d8d644bcd0e46dc2a354ffce219a788630a0cdcc (diff) |
NETFILTER: nfnetlink_queue: fix SKB_LINEAR_ASSERT when mangling packet data
Upstream commit e2b58a67:
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>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 12 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 10 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 10 |
3 files changed, 19 insertions, 13 deletions
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 14d64a383db1..16d0fb37c4c6 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -336,8 +336,8 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; - int err; struct iphdr *user_iph = (struct iphdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -349,14 +349,16 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip_queue: error " - "in mangle, dropping packet: %d\n", -err); - return err; + "in mangle, dropping packet\n"); + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e273605eef85..710a04ff7712 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -333,8 +333,8 @@ static int ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; - int err; struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; + struct sk_buff *nskb; if (v->data_len < sizeof(*user_iph)) return 0; @@ -346,14 +346,16 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "ip6_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 3ceeffcf6f9d..561c974cf63d 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -616,8 +616,8 @@ err_out_put: static int nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) { + struct sk_buff *nskb; int diff; - int err; diff = data_len - e->skb->len; if (diff < 0) { @@ -627,14 +627,16 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - err = pskb_expand_head(e->skb, 0, + nskb = skb_copy_expand(e->skb, 0, diff - skb_tailroom(e->skb), GFP_ATOMIC); - if (err) { + if (!nskb) { printk(KERN_WARNING "nf_queue: OOM " "in mangle, dropping packet\n"); - return err; + return -ENOMEM; } + kfree_skb(e->skb); + e->skb = nskb; } skb_put(e->skb, diff); } |