diff options
-rw-r--r-- | drivers/net/pppol2tp.c | 44 |
1 files changed, 24 insertions, 20 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index ed8ead432d77..440e190778a1 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
@@ -491,44 +491,46 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
491 | u16 hdrflags; | 491 | u16 hdrflags; |
492 | u16 tunnel_id, session_id; | 492 | u16 tunnel_id, session_id; |
493 | int length; | 493 | int length; |
494 | struct udphdr *uh; | 494 | int offset; |
495 | 495 | ||
496 | tunnel = pppol2tp_sock_to_tunnel(sock); | 496 | tunnel = pppol2tp_sock_to_tunnel(sock); |
497 | if (tunnel == NULL) | 497 | if (tunnel == NULL) |
498 | goto error; | 498 | goto error; |
499 | 499 | ||
500 | /* UDP always verifies the packet length. */ | ||
501 | __skb_pull(skb, sizeof(struct udphdr)); | ||
502 | |||
500 | /* Short packet? */ | 503 | /* Short packet? */ |
501 | if (skb->len < sizeof(struct udphdr)) { | 504 | if (!pskb_may_pull(skb, 12)) { |
502 | PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, | 505 | PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, |
503 | "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); | 506 | "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); |
504 | goto error; | 507 | goto error; |
505 | } | 508 | } |
506 | 509 | ||
507 | /* Point to L2TP header */ | 510 | /* Point to L2TP header */ |
508 | ptr = skb->data + sizeof(struct udphdr); | 511 | ptr = skb->data; |
509 | 512 | ||
510 | /* Get L2TP header flags */ | 513 | /* Get L2TP header flags */ |
511 | hdrflags = ntohs(*(__be16*)ptr); | 514 | hdrflags = ntohs(*(__be16*)ptr); |
512 | 515 | ||
513 | /* Trace packet contents, if enabled */ | 516 | /* Trace packet contents, if enabled */ |
514 | if (tunnel->debug & PPPOL2TP_MSG_DATA) { | 517 | if (tunnel->debug & PPPOL2TP_MSG_DATA) { |
518 | length = min(16u, skb->len); | ||
519 | if (!pskb_may_pull(skb, length)) | ||
520 | goto error; | ||
521 | |||
515 | printk(KERN_DEBUG "%s: recv: ", tunnel->name); | 522 | printk(KERN_DEBUG "%s: recv: ", tunnel->name); |
516 | 523 | ||
517 | for (length = 0; length < 16; length++) | 524 | offset = 0; |
518 | printk(" %02X", ptr[length]); | 525 | do { |
526 | printk(" %02X", ptr[offset]); | ||
527 | } while (++offset < length); | ||
528 | |||
519 | printk("\n"); | 529 | printk("\n"); |
520 | } | 530 | } |
521 | 531 | ||
522 | /* Get length of L2TP packet */ | 532 | /* Get length of L2TP packet */ |
523 | uh = (struct udphdr *) skb_transport_header(skb); | 533 | length = skb->len; |
524 | length = ntohs(uh->len) - sizeof(struct udphdr); | ||
525 | |||
526 | /* Too short? */ | ||
527 | if (length < 12) { | ||
528 | PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, | ||
529 | "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length); | ||
530 | goto error; | ||
531 | } | ||
532 | 534 | ||
533 | /* If type is control packet, it is handled by userspace. */ | 535 | /* If type is control packet, it is handled by userspace. */ |
534 | if (hdrflags & L2TP_HDRFLAG_T) { | 536 | if (hdrflags & L2TP_HDRFLAG_T) { |
@@ -606,7 +608,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
606 | "%s: recv data has no seq numbers when required. " | 608 | "%s: recv data has no seq numbers when required. " |
607 | "Discarding\n", session->name); | 609 | "Discarding\n", session->name); |
608 | session->stats.rx_seq_discards++; | 610 | session->stats.rx_seq_discards++; |
609 | session->stats.rx_errors++; | ||
610 | goto discard; | 611 | goto discard; |
611 | } | 612 | } |
612 | 613 | ||
@@ -625,7 +626,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
625 | "%s: recv data has no seq numbers when required. " | 626 | "%s: recv data has no seq numbers when required. " |
626 | "Discarding\n", session->name); | 627 | "Discarding\n", session->name); |
627 | session->stats.rx_seq_discards++; | 628 | session->stats.rx_seq_discards++; |
628 | session->stats.rx_errors++; | ||
629 | goto discard; | 629 | goto discard; |
630 | } | 630 | } |
631 | 631 | ||
@@ -634,10 +634,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
634 | } | 634 | } |
635 | 635 | ||
636 | /* If offset bit set, skip it. */ | 636 | /* If offset bit set, skip it. */ |
637 | if (hdrflags & L2TP_HDRFLAG_O) | 637 | if (hdrflags & L2TP_HDRFLAG_O) { |
638 | ptr += 2 + ntohs(*(__be16 *) ptr); | 638 | offset = ntohs(*(__be16 *)ptr); |
639 | skb->transport_header += 2 + offset; | ||
640 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) | ||
641 | goto discard; | ||
642 | } | ||
639 | 643 | ||
640 | skb_pull(skb, ptr - skb->data); | 644 | __skb_pull(skb, skb_transport_offset(skb)); |
641 | 645 | ||
642 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients | 646 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients |
643 | * don't send the PPP header (PPP header compression enabled), but | 647 | * don't send the PPP header (PPP header compression enabled), but |
@@ -673,7 +677,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
673 | */ | 677 | */ |
674 | if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { | 678 | if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { |
675 | session->stats.rx_seq_discards++; | 679 | session->stats.rx_seq_discards++; |
676 | session->stats.rx_errors++; | ||
677 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, | 680 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, |
678 | "%s: oos pkt %hu len %d discarded, " | 681 | "%s: oos pkt %hu len %d discarded, " |
679 | "waiting for %hu, reorder_q_len=%d\n", | 682 | "waiting for %hu, reorder_q_len=%d\n", |
@@ -698,6 +701,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
698 | return 0; | 701 | return 0; |
699 | 702 | ||
700 | discard: | 703 | discard: |
704 | session->stats.rx_errors++; | ||
701 | kfree_skb(skb); | 705 | kfree_skb(skb); |
702 | sock_put(session->sock); | 706 | sock_put(session->sock); |
703 | 707 | ||