Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a38b775 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7b797d5b
Loading
Loading
Loading
Loading
+25 −19
Original line number Diff line number Diff line
@@ -1525,7 +1525,7 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
	if (skb->len >= 2) {
	if (pskb_may_pull(skb, 2)) {
#ifdef CONFIG_PPP_MULTILINK
		/* XXX do channel-level decompression here */
		if (PPP_PROTO(skb) == PPP_MP)
@@ -1577,7 +1577,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
		if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
			goto err;

		if (skb_tailroom(skb) < 124) {
		if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
			/* copy to a new sk_buff with more tailroom */
			ns = dev_alloc_skb(skb->len + 128);
			if (ns == 0) {
@@ -1648,12 +1648,18 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
		/* check if the packet passes the pass and active filters */
		/* the filter instructions are constructed assuming
		   a four-byte PPP header on each packet */
		if (ppp->pass_filter || ppp->active_filter) {
			if (skb_cloned(skb) &&
			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
				goto err;

			*skb_push(skb, 2) = 0;
			if (ppp->pass_filter
			    && sk_run_filter(skb, ppp->pass_filter,
					     ppp->pass_len) == 0) {
				if (ppp->debug & 1)
				printk(KERN_DEBUG "PPP: inbound frame not passed\n");
					printk(KERN_DEBUG "PPP: inbound frame "
					       "not passed\n");
				kfree_skb(skb);
				return;
			}
@@ -1661,10 +1667,10 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
			      && sk_run_filter(skb, ppp->active_filter,
					       ppp->active_len) == 0))
				ppp->last_recv = jiffies;
		skb_pull(skb, 2);
#else
		ppp->last_recv = jiffies;
			__skb_pull(skb, 2);
		} else
#endif /* CONFIG_PPP_FILTER */
			ppp->last_recv = jiffies;

		if ((ppp->dev->flags & IFF_UP) == 0
		    || ppp->npmode[npi] != NPMODE_PASS) {
@@ -1762,7 +1768,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
	struct channel *ch;
	int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;

	if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
	if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
		goto err;		/* no good, throw it away */

	/* Decode sequence number and begin/end bits */