[PPP]: L2TP: Fix oops in transmit and receive paths
Changes made on 18-sep to fix skb handling in the pppol2tp driver broke the transmit and receive paths. Users are only running into this now because distros are now using 2.6.23 and I must have messed up when I tested the change. For receive, we now do our own calculation of how much to pull from the skb (variable length L2TP header) rather than using skb_transport_offset(). Also, if the skb isn't a data packet, it must be passed back to UDP with skb->data pointing to the UDP header. For transmit, make sure skb->sk is set up because ip_queue_xmit() needs it. Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6a9fb9479f
commit
91781004b9
1 changed files with 18 additions and 7 deletions
|
@ -488,7 +488,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct pppol2tp_session *session = NULL;
|
struct pppol2tp_session *session = NULL;
|
||||||
struct pppol2tp_tunnel *tunnel;
|
struct pppol2tp_tunnel *tunnel;
|
||||||
unsigned char *ptr;
|
unsigned char *ptr, *optr;
|
||||||
u16 hdrflags;
|
u16 hdrflags;
|
||||||
u16 tunnel_id, session_id;
|
u16 tunnel_id, session_id;
|
||||||
int length;
|
int length;
|
||||||
|
@ -496,7 +496,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
|
||||||
|
|
||||||
tunnel = pppol2tp_sock_to_tunnel(sock);
|
tunnel = pppol2tp_sock_to_tunnel(sock);
|
||||||
if (tunnel == NULL)
|
if (tunnel == NULL)
|
||||||
goto error;
|
goto no_tunnel;
|
||||||
|
|
||||||
/* UDP always verifies the packet length. */
|
/* UDP always verifies the packet length. */
|
||||||
__skb_pull(skb, sizeof(struct udphdr));
|
__skb_pull(skb, sizeof(struct udphdr));
|
||||||
|
@ -509,7 +509,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Point to L2TP header */
|
/* Point to L2TP header */
|
||||||
ptr = skb->data;
|
optr = ptr = skb->data;
|
||||||
|
|
||||||
/* Get L2TP header flags */
|
/* Get L2TP header flags */
|
||||||
hdrflags = ntohs(*(__be16*)ptr);
|
hdrflags = ntohs(*(__be16*)ptr);
|
||||||
|
@ -637,12 +637,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
|
||||||
/* If offset bit set, skip it. */
|
/* If offset bit set, skip it. */
|
||||||
if (hdrflags & L2TP_HDRFLAG_O) {
|
if (hdrflags & L2TP_HDRFLAG_O) {
|
||||||
offset = ntohs(*(__be16 *)ptr);
|
offset = ntohs(*(__be16 *)ptr);
|
||||||
skb->transport_header += 2 + offset;
|
ptr += 2 + offset;
|
||||||
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2))
|
|
||||||
goto discard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__skb_pull(skb, skb_transport_offset(skb));
|
offset = ptr - optr;
|
||||||
|
if (!pskb_may_pull(skb, offset))
|
||||||
|
goto discard;
|
||||||
|
|
||||||
|
__skb_pull(skb, offset);
|
||||||
|
|
||||||
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
|
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
|
||||||
* don't send the PPP header (PPP header compression enabled), but
|
* 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)
|
||||||
* Note that skb->data[] isn't dereferenced from a u16 ptr here since
|
* Note that skb->data[] isn't dereferenced from a u16 ptr here since
|
||||||
* the field may be unaligned.
|
* the field may be unaligned.
|
||||||
*/
|
*/
|
||||||
|
if (!pskb_may_pull(skb, 2))
|
||||||
|
goto discard;
|
||||||
|
|
||||||
if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
|
if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
|
||||||
skb_pull(skb, 2);
|
skb_pull(skb, 2);
|
||||||
|
|
||||||
|
@ -709,6 +714,10 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
/* Put UDP header back */
|
||||||
|
__skb_push(skb, sizeof(struct udphdr));
|
||||||
|
|
||||||
|
no_tunnel:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,6 +1059,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
|
||||||
/* Get routing info from the tunnel socket */
|
/* Get routing info from the tunnel socket */
|
||||||
dst_release(skb->dst);
|
dst_release(skb->dst);
|
||||||
skb->dst = sk_dst_get(sk_tun);
|
skb->dst = sk_dst_get(sk_tun);
|
||||||
|
skb_orphan(skb);
|
||||||
|
skb->sk = sk_tun;
|
||||||
|
|
||||||
/* Queue the packet to IP for output */
|
/* Queue the packet to IP for output */
|
||||||
len = skb->len;
|
len = skb->len;
|
||||||
|
|
Loading…
Reference in a new issue