Skip to content

Commit

Permalink
ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Simon Arlott authored and David S. Miller committed May 3, 2010
1 parent 1183f38 commit ea8420e
Showing 1 changed file with 18 additions and 11 deletions.
29 changes: 18 additions & 11 deletions drivers/net/ppp_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1567,13 +1567,22 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
struct channel *pch = chan->ppp;
int proto;

if (!pch || skb->len == 0) {
if (!pch) {
kfree_skb(skb);
return;
}

proto = PPP_PROTO(skb);
read_lock_bh(&pch->upl);
if (!pskb_may_pull(skb, 2)) {
kfree_skb(skb);
if (pch->ppp) {
++pch->ppp->dev->stats.rx_length_errors;
ppp_receive_error(pch->ppp);
}
goto done;
}

proto = PPP_PROTO(skb);
if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
Expand All @@ -1585,6 +1594,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
} else {
ppp_do_recv(pch->ppp, skb, pch);
}

done:
read_unlock_bh(&pch->upl);
}

Expand Down Expand Up @@ -1617,23 +1628,19 @@ 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 (pskb_may_pull(skb, 2)) {
/* note: a 0-length skb is used as an error indication */
if (skb->len > 0) {
#ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP)
ppp_receive_mp_frame(ppp, skb, pch);
else
#endif /* CONFIG_PPP_MULTILINK */
ppp_receive_nonmp_frame(ppp, skb);
return;
} else {
kfree_skb(skb);
ppp_receive_error(ppp);
}

if (skb->len > 0)
/* note: a 0-length skb is used as an error indication */
++ppp->dev->stats.rx_length_errors;

kfree_skb(skb);
ppp_receive_error(ppp);
}

static void
Expand Down

0 comments on commit ea8420e

Please sign in to comment.