Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Eric Dumazet and committed by
David S. Miller
4ea2739e 58af19e3

+12 -8
+12 -8
drivers/net/pptp.c
··· 307 307 } 308 308 309 309 header = (struct pptp_gre_header *)(skb->data); 310 + headersize = sizeof(*header); 310 311 311 312 /* test if acknowledgement present */ 312 313 if (PPTP_GRE_IS_A(header->ver)) { 313 - __u32 ack = (PPTP_GRE_IS_S(header->flags)) ? 314 - header->ack : header->seq; /* ack in different place if S = 0 */ 314 + __u32 ack; 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 323 ack = ntohl(ack); 317 324 ··· 327 320 /* also handle sequence number wrap-around */ 328 321 if (WRAPPED(ack, opt->ack_recv)) 329 322 opt->ack_recv = ack; 323 + } else { 324 + headersize -= sizeof(header->ack); 330 325 } 331 - 332 326 /* test if payload present */ 333 327 if (!PPTP_GRE_IS_S(header->flags)) 334 328 goto drop; 335 329 336 - headersize = sizeof(*header); 337 330 payload_len = ntohs(header->payload_len); 338 331 seq = ntohl(header->seq); 339 332 340 - /* no ack present? */ 341 - if (!PPTP_GRE_IS_A(header->ver)) 342 - headersize -= sizeof(header->ack); 343 333 /* check for incomplete packet (length smaller than expected) */ 344 - if (skb->len - headersize < payload_len) 334 + if (!pskb_may_pull(skb, headersize + payload_len)) 345 335 goto drop; 346 336 347 337 payload = skb->data + headersize;