aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ppp_generic.c
diff options
context:
space:
mode:
authorSimon Arlott <simon@fire.lp0.eu>2010-05-03 06:19:33 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-03 16:27:00 -0400
commitea8420e9f5dff7324607671f0b7ab7fbf726339d (patch)
treedc7b905fd3a5b76f00705cd76d25e12cced842f5 /drivers/net/ppp_generic.c
parent1183f3838c588545592c042c0ce15015661ce7f2 (diff)
ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid
In ppp_input(), PPP_PROTO(skb) may refer to invalid data in the skb. If this happens and (proto >= 0xc000 || proto == PPP_CCPFRAG) then the packet is passed directly to pppd. This occurs frequently when using PPPoE with an interface MTU greater than 1500 because the skb is more likely to be non-linear. The next 2 bytes need to be pulled in ppp_input(). The pull of 2 bytes in ppp_receive_frame() has been removed as it is no longer required. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ppp_generic.c')
-rw-r--r--drivers/net/ppp_generic.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 6e281bc825e5..75e8903c3754 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1567,13 +1567,22 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
1567 struct channel *pch = chan->ppp; 1567 struct channel *pch = chan->ppp;
1568 int proto; 1568 int proto;
1569 1569
1570 if (!pch || skb->len == 0) { 1570 if (!pch) {
1571 kfree_skb(skb); 1571 kfree_skb(skb);
1572 return; 1572 return;
1573 } 1573 }
1574 1574
1575 proto = PPP_PROTO(skb);
1576 read_lock_bh(&pch->upl); 1575 read_lock_bh(&pch->upl);
1576 if (!pskb_may_pull(skb, 2)) {
1577 kfree_skb(skb);
1578 if (pch->ppp) {
1579 ++pch->ppp->dev->stats.rx_length_errors;
1580 ppp_receive_error(pch->ppp);
1581 }
1582 goto done;
1583 }
1584
1585 proto = PPP_PROTO(skb);
1577 if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) { 1586 if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
1578 /* put it on the channel queue */ 1587 /* put it on the channel queue */
1579 skb_queue_tail(&pch->file.rq, skb); 1588 skb_queue_tail(&pch->file.rq, skb);
@@ -1585,6 +1594,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
1585 } else { 1594 } else {
1586 ppp_do_recv(pch->ppp, skb, pch); 1595 ppp_do_recv(pch->ppp, skb, pch);
1587 } 1596 }
1597
1598done:
1588 read_unlock_bh(&pch->upl); 1599 read_unlock_bh(&pch->upl);
1589} 1600}
1590 1601
@@ -1617,7 +1628,8 @@ ppp_input_error(struct ppp_channel *chan, int code)
1617static void 1628static void
1618ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) 1629ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
1619{ 1630{
1620 if (pskb_may_pull(skb, 2)) { 1631 /* note: a 0-length skb is used as an error indication */
1632 if (skb->len > 0) {
1621#ifdef CONFIG_PPP_MULTILINK 1633#ifdef CONFIG_PPP_MULTILINK
1622 /* XXX do channel-level decompression here */ 1634 /* XXX do channel-level decompression here */
1623 if (PPP_PROTO(skb) == PPP_MP) 1635 if (PPP_PROTO(skb) == PPP_MP)
@@ -1625,15 +1637,10 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
1625 else 1637 else
1626#endif /* CONFIG_PPP_MULTILINK */ 1638#endif /* CONFIG_PPP_MULTILINK */
1627 ppp_receive_nonmp_frame(ppp, skb); 1639 ppp_receive_nonmp_frame(ppp, skb);
1628 return; 1640 } else {
1641 kfree_skb(skb);
1642 ppp_receive_error(ppp);
1629 } 1643 }
1630
1631 if (skb->len > 0)
1632 /* note: a 0-length skb is used as an error indication */
1633 ++ppp->dev->stats.rx_length_errors;
1634
1635 kfree_skb(skb);
1636 ppp_receive_error(ppp);
1637} 1644}
1638 1645
1639static void 1646static void