提交 91781004 编写于 作者: J James Chapman 提交者: David S. Miller

[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: NJames Chapman <jchapman@katalix.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 6a9fb947
...@@ -488,7 +488,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册