diff options
author | Changli Gao <xiaosuo@gmail.com> | 2010-08-03 17:39:18 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-08-04 21:53:14 -0700 |
commit | 36d12690a2e9bcacae5a2a7e0fb6345a3caad625 (patch) | |
tree | f3e451b268d498af9ec171f6b454538091010f71 /net | |
parent | c33788b45f754bd5dd8adc520e37fa38ac1849c7 (diff) | |
download | lwn-36d12690a2e9bcacae5a2a7e0fb6345a3caad625.tar.gz lwn-36d12690a2e9bcacae5a2a7e0fb6345a3caad625.zip |
act_nat: fix on the TX path
On the TX path, skb->data points to the ethernet header, not the network
header. So when validating the packet length for accessing we should
take the ethernet header into account.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/sched/act_nat.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index d0386a413e8d..509a2d53a99d 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -114,6 +114,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, int egress; int action; int ihl; + int noff; spin_lock(&p->tcf_lock); @@ -132,7 +133,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, if (unlikely(action == TC_ACT_SHOT)) goto drop; - if (!pskb_may_pull(skb, sizeof(*iph))) + noff = skb_network_offset(skb); + if (!pskb_may_pull(skb, sizeof(*iph) + noff)) goto drop; iph = ip_hdr(skb); @@ -144,7 +146,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, if (!((old_addr ^ addr) & mask)) { if (skb_cloned(skb) && - !skb_clone_writable(skb, sizeof(*iph)) && + !skb_clone_writable(skb, sizeof(*iph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto drop; @@ -172,9 +174,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct tcphdr *tcph; - if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) || + if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || (skb_cloned(skb) && - !skb_clone_writable(skb, ihl + sizeof(*tcph)) && + !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto drop; @@ -186,9 +188,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct udphdr *udph; - if (!pskb_may_pull(skb, ihl + sizeof(*udph)) || + if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || (skb_cloned(skb) && - !skb_clone_writable(skb, ihl + sizeof(*udph)) && + !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto drop; @@ -205,7 +207,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct icmphdr *icmph; - if (!pskb_may_pull(skb, ihl + sizeof(*icmph))) + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) goto drop; icmph = (void *)(skb_network_header(skb) + ihl); @@ -215,7 +217,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, (icmph->type != ICMP_PARAMETERPROB)) break; - if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + + noff)) goto drop; icmph = (void *)(skb_network_header(skb) + ihl); @@ -229,8 +232,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, break; if (skb_cloned(skb) && - !skb_clone_writable(skb, - ihl + sizeof(*icmph) + sizeof(*iph)) && + !skb_clone_writable(skb, ihl + sizeof(*icmph) + + sizeof(*iph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto drop; |