diff options
Diffstat (limited to 'drivers/net/pppol2tp.c')
| -rw-r--r-- | drivers/net/pppol2tp.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index f8904fd92369..a7556cd2df79 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
| @@ -488,7 +488,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
| 488 | { | 488 | { |
| 489 | struct pppol2tp_session *session = NULL; | 489 | struct pppol2tp_session *session = NULL; |
| 490 | struct pppol2tp_tunnel *tunnel; | 490 | struct pppol2tp_tunnel *tunnel; |
| 491 | unsigned char *ptr; | 491 | unsigned char *ptr, *optr; |
| 492 | u16 hdrflags; | 492 | u16 hdrflags; |
| 493 | u16 tunnel_id, session_id; | 493 | u16 tunnel_id, session_id; |
| 494 | int length; | 494 | int length; |
| @@ -496,7 +496,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
| 496 | 496 | ||
| 497 | tunnel = pppol2tp_sock_to_tunnel(sock); | 497 | tunnel = pppol2tp_sock_to_tunnel(sock); |
| 498 | if (tunnel == NULL) | 498 | if (tunnel == NULL) |
| 499 | goto error; | 499 | goto no_tunnel; |
| 500 | 500 | ||
| 501 | /* UDP always verifies the packet length. */ | 501 | /* UDP always verifies the packet length. */ |
| 502 | __skb_pull(skb, sizeof(struct udphdr)); | 502 | __skb_pull(skb, sizeof(struct udphdr)); |
| @@ -509,7 +509,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | /* Point to L2TP header */ | 511 | /* Point to L2TP header */ |
| 512 | ptr = skb->data; | 512 | optr = ptr = skb->data; |
| 513 | 513 | ||
| 514 | /* Get L2TP header flags */ | 514 | /* Get L2TP header flags */ |
| 515 | hdrflags = ntohs(*(__be16*)ptr); | 515 | hdrflags = ntohs(*(__be16*)ptr); |
| @@ -637,12 +637,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
| 637 | /* If offset bit set, skip it. */ | 637 | /* If offset bit set, skip it. */ |
| 638 | if (hdrflags & L2TP_HDRFLAG_O) { | 638 | if (hdrflags & L2TP_HDRFLAG_O) { |
| 639 | offset = ntohs(*(__be16 *)ptr); | 639 | offset = ntohs(*(__be16 *)ptr); |
| 640 | skb->transport_header += 2 + offset; | 640 | ptr += 2 + offset; |
| 641 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) | ||
| 642 | goto discard; | ||
| 643 | } | 641 | } |
| 644 | 642 | ||
| 645 | __skb_pull(skb, skb_transport_offset(skb)); | 643 | offset = ptr - optr; |
| 644 | if (!pskb_may_pull(skb, offset)) | ||
| 645 | goto discard; | ||
| 646 | |||
| 647 | __skb_pull(skb, offset); | ||
| 646 | 648 | ||
| 647 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients | 649 | /* Skip PPP header, if present. In testing, Microsoft L2TP clients |
| 648 | * don't send the PPP header (PPP header compression enabled), but | 650 | * don't send the PPP header (PPP header compression enabled), but |
| @@ -652,6 +654,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) | |||
| 652 | * Note that skb->data[] isn't dereferenced from a u16 ptr here since | 654 | * Note that skb->data[] isn't dereferenced from a u16 ptr here since |
| 653 | * the field may be unaligned. | 655 | * the field may be unaligned. |
| 654 | */ | 656 | */ |
| 657 | if (!pskb_may_pull(skb, 2)) | ||
| 658 | goto discard; | ||
| 659 | |||
| 655 | if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) | 660 | if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) |
| 656 | skb_pull(skb, 2); | 661 | skb_pull(skb, 2); |
| 657 | 662 | ||
| @@ -709,6 +714,10 @@ discard: | |||
| 709 | return 0; | 714 | return 0; |
| 710 | 715 | ||
| 711 | error: | 716 | error: |
| 717 | /* Put UDP header back */ | ||
| 718 | __skb_push(skb, sizeof(struct udphdr)); | ||
| 719 | |||
| 720 | no_tunnel: | ||
| 712 | return 1; | 721 | return 1; |
| 713 | } | 722 | } |
| 714 | 723 | ||
| @@ -1050,6 +1059,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | |||
| 1050 | /* Get routing info from the tunnel socket */ | 1059 | /* Get routing info from the tunnel socket */ |
| 1051 | dst_release(skb->dst); | 1060 | dst_release(skb->dst); |
| 1052 | skb->dst = sk_dst_get(sk_tun); | 1061 | skb->dst = sk_dst_get(sk_tun); |
| 1062 | skb_orphan(skb); | ||
| 1063 | skb->sk = sk_tun; | ||
| 1053 | 1064 | ||
| 1054 | /* Queue the packet to IP for output */ | 1065 | /* Queue the packet to IP for output */ |
| 1055 | len = skb->len; | 1066 | len = skb->len; |
