diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-09-16 19:22:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-09-16 19:22:13 -0400 |
commit | 2a38b775b77f99308a4e571c13d908df78ac5e57 (patch) | |
tree | 10f7bbe1d1a35c7383b7aa7fa865119a8bc0ae65 /drivers/net/ppp_generic.c | |
parent | 7b797d5b150775d717cb03b5ada28b8bad99afab (diff) |
[PPP] generic: Fix receive path data clobbering & non-linear handling
This patch adds missing pskb_may_pull calls to deal with non-linear
packets that may arrive from pppoe or pppol2tp.
It also copies cloned packets before writing over them.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
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 | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 7e21342becb2..4b49d0e8c7eb 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c | |||
@@ -1525,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code) | |||
1525 | static void | 1525 | static void |
1526 | ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) | 1526 | ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) |
1527 | { | 1527 | { |
1528 | if (skb->len >= 2) { | 1528 | if (pskb_may_pull(skb, 2)) { |
1529 | #ifdef CONFIG_PPP_MULTILINK | 1529 | #ifdef CONFIG_PPP_MULTILINK |
1530 | /* XXX do channel-level decompression here */ | 1530 | /* XXX do channel-level decompression here */ |
1531 | if (PPP_PROTO(skb) == PPP_MP) | 1531 | if (PPP_PROTO(skb) == PPP_MP) |
@@ -1577,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) | |||
1577 | if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) | 1577 | if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) |
1578 | goto err; | 1578 | goto err; |
1579 | 1579 | ||
1580 | if (skb_tailroom(skb) < 124) { | 1580 | if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { |
1581 | /* copy to a new sk_buff with more tailroom */ | 1581 | /* copy to a new sk_buff with more tailroom */ |
1582 | ns = dev_alloc_skb(skb->len + 128); | 1582 | ns = dev_alloc_skb(skb->len + 128); |
1583 | if (ns == 0) { | 1583 | if (ns == 0) { |
@@ -1648,23 +1648,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) | |||
1648 | /* check if the packet passes the pass and active filters */ | 1648 | /* check if the packet passes the pass and active filters */ |
1649 | /* the filter instructions are constructed assuming | 1649 | /* the filter instructions are constructed assuming |
1650 | a four-byte PPP header on each packet */ | 1650 | a four-byte PPP header on each packet */ |
1651 | *skb_push(skb, 2) = 0; | 1651 | if (ppp->pass_filter || ppp->active_filter) { |
1652 | if (ppp->pass_filter | 1652 | if (skb_cloned(skb) && |
1653 | && sk_run_filter(skb, ppp->pass_filter, | 1653 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
1654 | ppp->pass_len) == 0) { | 1654 | goto err; |
1655 | if (ppp->debug & 1) | 1655 | |
1656 | printk(KERN_DEBUG "PPP: inbound frame not passed\n"); | 1656 | *skb_push(skb, 2) = 0; |
1657 | kfree_skb(skb); | 1657 | if (ppp->pass_filter |
1658 | return; | 1658 | && sk_run_filter(skb, ppp->pass_filter, |
1659 | } | 1659 | ppp->pass_len) == 0) { |
1660 | if (!(ppp->active_filter | 1660 | if (ppp->debug & 1) |
1661 | && sk_run_filter(skb, ppp->active_filter, | 1661 | printk(KERN_DEBUG "PPP: inbound frame " |
1662 | ppp->active_len) == 0)) | 1662 | "not passed\n"); |
1663 | ppp->last_recv = jiffies; | 1663 | kfree_skb(skb); |
1664 | skb_pull(skb, 2); | 1664 | return; |
1665 | #else | 1665 | } |
1666 | ppp->last_recv = jiffies; | 1666 | if (!(ppp->active_filter |
1667 | && sk_run_filter(skb, ppp->active_filter, | ||
1668 | ppp->active_len) == 0)) | ||
1669 | ppp->last_recv = jiffies; | ||
1670 | __skb_pull(skb, 2); | ||
1671 | } else | ||
1667 | #endif /* CONFIG_PPP_FILTER */ | 1672 | #endif /* CONFIG_PPP_FILTER */ |
1673 | ppp->last_recv = jiffies; | ||
1668 | 1674 | ||
1669 | if ((ppp->dev->flags & IFF_UP) == 0 | 1675 | if ((ppp->dev->flags & IFF_UP) == 0 |
1670 | || ppp->npmode[npi] != NPMODE_PASS) { | 1676 | || ppp->npmode[npi] != NPMODE_PASS) { |
@@ -1762,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) | |||
1762 | struct channel *ch; | 1768 | struct channel *ch; |
1763 | int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; | 1769 | int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; |
1764 | 1770 | ||
1765 | if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) | 1771 | if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) |
1766 | goto err; /* no good, throw it away */ | 1772 | goto err; /* no good, throw it away */ |
1767 | 1773 | ||
1768 | /* Decode sequence number and begin/end bits */ | 1774 | /* Decode sequence number and begin/end bits */ |