aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-10-17 13:59:53 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-19 03:50:43 -0400
commit4ea2739ea89883ddf79980a8aa27d5e57093e464 (patch)
tree4ce1a9760251a507839c0e645dae109c036ec727 /drivers
parent58af19e387d8821927e49be3f467da5e6a0aa8fd (diff)
pptp: pptp_rcv_core() misses pskb_may_pull() call
e1000e uses paged frags, so any layer incorrectly pulling bytes from skb can trigger a BUG in skb_pull() [951.142737] [<ffffffff813d2f36>] skb_pull+0x15/0x17 [951.142737] [<ffffffffa0286824>] pptp_rcv_core+0x126/0x19a [pptp] [951.152725] [<ffffffff813d17c4>] sk_receive_skb+0x69/0x105 [951.163558] [<ffffffffa0286993>] pptp_rcv+0xc8/0xdc [pptp] [951.165092] [<ffffffffa02800a3>] gre_rcv+0x62/0x75 [gre] [951.165092] [<ffffffff81410784>] ip_local_deliver_finish+0x150/0x1c1 [951.177599] [<ffffffff81410634>] ? ip_local_deliver_finish+0x0/0x1c1 [951.177599] [<ffffffff81410846>] NF_HOOK.clone.7+0x51/0x58 [951.177599] [<ffffffff81410996>] ip_local_deliver+0x51/0x55 [951.177599] [<ffffffff814105b9>] ip_rcv_finish+0x31a/0x33e [951.177599] [<ffffffff8141029f>] ? ip_rcv_finish+0x0/0x33e [951.204898] [<ffffffff81410846>] NF_HOOK.clone.7+0x51/0x58 [951.214651] [<ffffffff81410bb5>] ip_rcv+0x21b/0x246 pptp_rcv_core() is a nice example of a function assuming everything it needs is available in skb head. Reported-by: Bradley Peterson <despite@gmail.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/pptp.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
index 9c0403d0107c..89f829f5f725 100644
--- a/drivers/net/pptp.c
+++ b/drivers/net/pptp.c
@@ -307,11 +307,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
307 } 307 }
308 308
309 header = (struct pptp_gre_header *)(skb->data); 309 header = (struct pptp_gre_header *)(skb->data);
310 headersize = sizeof(*header);
310 311
311 /* test if acknowledgement present */ 312 /* test if acknowledgement present */
312 if (PPTP_GRE_IS_A(header->ver)) { 313 if (PPTP_GRE_IS_A(header->ver)) {
313 __u32 ack = (PPTP_GRE_IS_S(header->flags)) ? 314 __u32 ack;
314 header->ack : header->seq; /* ack in different place if S = 0 */ 315
316 if (!pskb_may_pull(skb, headersize))
317 goto drop;
318 header = (struct pptp_gre_header *)(skb->data);
319
320 /* ack in different place if S = 0 */
321 ack = PPTP_GRE_IS_S(header->flags) ? header->ack : header->seq;
315 322
316 ack = ntohl(ack); 323 ack = ntohl(ack);
317 324
@@ -320,21 +327,18 @@ static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb)
320 /* also handle sequence number wrap-around */ 327 /* also handle sequence number wrap-around */
321 if (WRAPPED(ack, opt->ack_recv)) 328 if (WRAPPED(ack, opt->ack_recv))
322 opt->ack_recv = ack; 329 opt->ack_recv = ack;
330 } else {
331 headersize -= sizeof(header->ack);
323 } 332 }
324
325 /* test if payload present */ 333 /* test if payload present */
326 if (!PPTP_GRE_IS_S(header->flags)) 334 if (!PPTP_GRE_IS_S(header->flags))
327 goto drop; 335 goto drop;
328 336
329 headersize = sizeof(*header);
330 payload_len = ntohs(header->payload_len); 337 payload_len = ntohs(header->payload_len);
331 seq = ntohl(header->seq); 338 seq = ntohl(header->seq);
332 339
333 /* no ack present? */
334 if (!PPTP_GRE_IS_A(header->ver))
335 headersize -= sizeof(header->ack);
336 /* check for incomplete packet (length smaller than expected) */ 340 /* check for incomplete packet (length smaller than expected) */
337 if (skb->len - headersize < payload_len) 341 if (!pskb_may_pull(skb, headersize + payload_len))
338 goto drop; 342 goto drop;
339 343
340 payload = skb->data + headersize; 344 payload = skb->data + headersize;