diff options
author | Simon Arlott <simon@fire.lp0.eu> | 2010-05-03 06:19:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-03 16:27:00 -0400 |
commit | ea8420e9f5dff7324607671f0b7ab7fbf726339d (patch) | |
tree | dc7b905fd3a5b76f00705cd76d25e12cced842f5 /drivers/net/ppp_generic.c | |
parent | 1183f3838c588545592c042c0ce15015661ce7f2 (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.c | 29 |
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 | |||
1598 | done: | ||
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) | |||
1617 | static void | 1628 | static void |
1618 | ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) | 1629 | ppp_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 | ||
1639 | static void | 1646 | static void |