aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-01-14 23:41:12 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-14 23:41:12 -0500
commit4e704ee3c2cd38748ca59d835435d6a7e7f6f613 (patch)
tree24d4f83bb55748fa5ae79f302b641663fa0488ba /net/ipv4/tcp.c
parentf557206800801410c30e53ce7a27219b2c4cf0ba (diff)
gso: Ensure that the packet is long enough
When we get a GSO packet from an untrusted source, we need to ensure that it is sufficiently long so that we don't end up crashing. Based on discovery and patch by Ian Campbell. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Tested-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 48ada1b2d2c4..0cd71b84e483 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2389,7 +2389,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2389 unsigned int seq; 2389 unsigned int seq;
2390 __be32 delta; 2390 __be32 delta;
2391 unsigned int oldlen; 2391 unsigned int oldlen;
2392 unsigned int len; 2392 unsigned int mss;
2393 2393
2394 if (!pskb_may_pull(skb, sizeof(*th))) 2394 if (!pskb_may_pull(skb, sizeof(*th)))
2395 goto out; 2395 goto out;
@@ -2405,10 +2405,13 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2405 oldlen = (u16)~skb->len; 2405 oldlen = (u16)~skb->len;
2406 __skb_pull(skb, thlen); 2406 __skb_pull(skb, thlen);
2407 2407
2408 mss = skb_shinfo(skb)->gso_size;
2409 if (unlikely(skb->len <= mss))
2410 goto out;
2411
2408 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { 2412 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
2409 /* Packet is from an untrusted source, reset gso_segs. */ 2413 /* Packet is from an untrusted source, reset gso_segs. */
2410 int type = skb_shinfo(skb)->gso_type; 2414 int type = skb_shinfo(skb)->gso_type;
2411 int mss;
2412 2415
2413 if (unlikely(type & 2416 if (unlikely(type &
2414 ~(SKB_GSO_TCPV4 | 2417 ~(SKB_GSO_TCPV4 |
@@ -2419,7 +2422,6 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2419 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) 2422 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
2420 goto out; 2423 goto out;
2421 2424
2422 mss = skb_shinfo(skb)->gso_size;
2423 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); 2425 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
2424 2426
2425 segs = NULL; 2427 segs = NULL;
@@ -2430,8 +2432,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2430 if (IS_ERR(segs)) 2432 if (IS_ERR(segs))
2431 goto out; 2433 goto out;
2432 2434
2433 len = skb_shinfo(skb)->gso_size; 2435 delta = htonl(oldlen + (thlen + mss));
2434 delta = htonl(oldlen + (thlen + len));
2435 2436
2436 skb = segs; 2437 skb = segs;
2437 th = tcp_hdr(skb); 2438 th = tcp_hdr(skb);
@@ -2447,7 +2448,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2447 csum_fold(csum_partial(skb_transport_header(skb), 2448 csum_fold(csum_partial(skb_transport_header(skb),
2448 thlen, skb->csum)); 2449 thlen, skb->csum));
2449 2450
2450 seq += len; 2451 seq += mss;
2451 skb = skb->next; 2452 skb = skb->next;
2452 th = tcp_hdr(skb); 2453 th = tcp_hdr(skb);
2453 2454