* [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid @ 2010-04-30 18:41 Simon Arlott 2010-04-30 18:41 ` [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd Simon Arlott 2010-05-03 6:25 ` [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid David Miller 0 siblings, 2 replies; 7+ messages in thread From: Simon Arlott @ 2010-04-30 18:41 UTC (permalink / raw) To: netdev; +Cc: paulus, linux-ppp 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> --- Tested with PPPoE over e1000 at MTU 16110. drivers/net/ppp_generic.c | 28 ++++++++++++++++++---------- 1 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 6e281bc..fdd8deb 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1572,8 +1572,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *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); @@ -1585,6 +1595,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); } @@ -1617,7 +1629,8 @@ 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) @@ -1625,15 +1638,10 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *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 -- 1.7.0.4 -- Simon Arlott ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd 2010-04-30 18:41 [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid Simon Arlott @ 2010-04-30 18:41 ` Simon Arlott 2010-05-03 6:27 ` David Miller 2010-05-03 6:25 ` [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid David Miller 1 sibling, 1 reply; 7+ messages in thread From: Simon Arlott @ 2010-04-30 18:41 UTC (permalink / raw) To: netdev; +Cc: paulus, linux-ppp Frequently when using PPPoE with an interface MTU greater than 1500, the skb is likely to be non-linear. If the skb needs to be passed to pppd then the skb must be linearised first. The previous commit fixes an issue with accidentally sending skbs to pppd based on an invalid read of the protocol type. When that error occurred pppd was reading invalid skb data too. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> --- Tested with PPPoE over e1000 at MTU 16110. drivers/net/ppp_generic.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index fdd8deb..6855a7b 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1222,6 +1222,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) if (ppp->flags & SC_LOOP_TRAFFIC) { if (ppp->file.rq.qlen > PPP_MAX_RQLEN) goto drop; + if (skb_linearize(skb)) + goto drop; skb_queue_tail(&ppp->file.rq, skb); wake_up_interruptible(&ppp->file.rwait); return; @@ -1586,6 +1588,12 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) proto = PPP_PROTO(skb); if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) { /* put it on the channel queue */ + if (skb_linearise(skb)) { + kfree_skb(skb); + if (pch->ppp) + ppp_receive_error(pch->ppp); + goto done; + } skb_queue_tail(&pch->file.rq, skb); /* drop old frames if queue too long */ while (pch->file.rq.qlen > PPP_MAX_RQLEN && @@ -1733,6 +1741,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) npi = proto_to_npindex(proto); if (npi < 0) { /* control or unknown frame - pass it to pppd */ + if (skb_linearize(skb)) + goto err; skb_queue_tail(&ppp->file.rq, skb); /* limit queue length by dropping old frames */ while (ppp->file.rq.qlen > PPP_MAX_RQLEN && -- 1.7.0.4 -- Simon Arlott ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd 2010-04-30 18:41 ` [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd Simon Arlott @ 2010-05-03 6:27 ` David Miller 2010-05-03 16:51 ` [PATCH 2/2] ppp_generic: handle non-linear skbs when " Simon Arlott 0 siblings, 1 reply; 7+ messages in thread From: David Miller @ 2010-05-03 6:27 UTC (permalink / raw) To: simon; +Cc: netdev, paulus, linux-ppp From: Simon Arlott <simon@fire.lp0.eu> Date: Fri, 30 Apr 2010 19:41:45 +0100 > Frequently when using PPPoE with an interface MTU greater than 1500, > the skb is likely to be non-linear. If the skb needs to be passed to > pppd then the skb must be linearised first. > > The previous commit fixes an issue with accidentally sending skbs > to pppd based on an invalid read of the protocol type. When that > error occurred pppd was reading invalid skb data too. > > Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Don't propagate stupidity. The real problem is that ppp_read() can't handle non-linear SKBs, so fix that instead. The easiest way to do that is to put a "struct iovec iov;" on ppp_read()'s stack, fill it in with ther user buffer pointer and length, then use that to call skb_copy_datagram_const_iovec(). ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] ppp_generic: handle non-linear skbs when passing them to pppd 2010-05-03 6:27 ` David Miller @ 2010-05-03 16:51 ` Simon Arlott 0 siblings, 0 replies; 7+ messages in thread From: Simon Arlott @ 2010-05-03 16:51 UTC (permalink / raw) To: David Miller; +Cc: netdev, paulus, linux-ppp Frequently when using PPPoE with an interface MTU greater than 1500, the skb is likely to be non-linear. If the skb needs to be passed to pppd then the skb data must be read correctly. The previous commit fixes an issue with accidentally sending skbs to pppd based on an invalid read of the protocol type. When that error occurred pppd was reading invalid skb data too. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> --- On 03/05/10 07:27, David Miller wrote: > From: Simon Arlott <simon@fire.lp0.eu> > Date: Fri, 30 Apr 2010 19:41:45 +0100 > >> Frequently when using PPPoE with an interface MTU greater than 1500, >> the skb is likely to be non-linear. If the skb needs to be passed to >> pppd then the skb must be linearised first. > > Don't propagate stupidity. > > The real problem is that ppp_read() can't handle non-linear SKBs, so > fix that instead. The easiest way to do that is to put a "struct > iovec iov;" on ppp_read()'s stack, fill it in with ther user buffer > pointer and length, then use that to call > skb_copy_datagram_const_iovec(). I've updated it to use skb_copy_datagram_iovec(): drivers/net/ppp_generic.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 75e8903..8518a2e 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -405,6 +405,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf, DECLARE_WAITQUEUE(wait, current); ssize_t ret; struct sk_buff *skb = NULL; + struct iovec iov; ret = count; @@ -448,7 +449,9 @@ static ssize_t ppp_read(struct file *file, char __user *buf, if (skb->len > count) goto outf; ret = -EFAULT; - if (copy_to_user(buf, skb->data, skb->len)) + iov.iov_base = buf; + iov.iov_len = count; + if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len)) goto outf; ret = skb->len; -- 1.7.0.4 -- Simon Arlott ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid 2010-04-30 18:41 [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid Simon Arlott 2010-04-30 18:41 ` [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd Simon Arlott @ 2010-05-03 6:25 ` David Miller 2010-05-03 11:50 ` Simon Arlott 1 sibling, 1 reply; 7+ messages in thread From: David Miller @ 2010-05-03 6:25 UTC (permalink / raw) To: simon; +Cc: netdev, paulus, linux-ppp From: Simon Arlott <simon@fire.lp0.eu> Date: Fri, 30 Apr 2010 19:41:17 +0100 > @@ -1572,8 +1572,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *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); This makes the skb->len == 0 test at the beginning completely redundant. Put your pskb_may_pull(skb, 2) call there and remove the skb->len==0 check entirely. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid 2010-05-03 6:25 ` [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid David Miller @ 2010-05-03 11:50 ` Simon Arlott 2010-05-03 19:49 ` David Miller 0 siblings, 1 reply; 7+ messages in thread From: Simon Arlott @ 2010-05-03 11:50 UTC (permalink / raw) To: David Miller; +Cc: netdev, paulus, linux-ppp [-- Attachment #1: Type: text/plain, Size: 781 bytes --] On Mon, May 3, 2010 07:25, David Miller wrote: > From: Simon Arlott <simon@fire.lp0.eu> > Date: Fri, 30 Apr 2010 19:41:17 +0100 >> @@ -1572,8 +1572,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) >> return; >> } >> >> - proto = PPP_PROTO(skb); >> + >> read_lock_bh(&pch->upl); >> + if (!pskb_may_pull(skb, 2)) { > > This makes the skb->len == 0 test at the beginning completely redundant. > > Put your pskb_may_pull(skb, 2) call there and remove the skb->len==0 > check entirely. If I move pskb_may_pull(skb, 2) up to where skb->len == 0 is then it can't increment rx_length_errors because it doesn't have the read lock on pch->upl, so I can only remove the redundant skb->len == 0 if that error count is to remain. Updated patch attached. -- Simon Arlott [-- Attachment #2: 0001-ppp_generic-pull-2-bytes-so-that-PPP_PROTO-skb-is-va.patch --] [-- Type: application/octet-stream, Size: 2627 bytes --] From f6d225971143db1ff5353008d20579e1de75f00d Mon Sep 17 00:00:00 2001 From: Simon Arlott <simon@fire.lp0.eu> Date: Fri, 30 Apr 2010 19:04:33 +0100 Subject: [PATCH 1/2] 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> --- 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 6e281bc..75e8903 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) 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); @@ -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); } @@ -1617,7 +1628,8 @@ 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) @@ -1625,15 +1637,10 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *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 -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid 2010-05-03 11:50 ` Simon Arlott @ 2010-05-03 19:49 ` David Miller 0 siblings, 0 replies; 7+ messages in thread From: David Miller @ 2010-05-03 19:49 UTC (permalink / raw) To: simon; +Cc: netdev, paulus, linux-ppp From: "Simon Arlott" <simon@fire.lp0.eu> Date: Mon, 3 May 2010 12:50:04 +0100 > Updated patch attached. Two things: 1) Please don't post patches as binary attachments, it doesn't get queued up properly into patchwork if you post it that way. 2) Always make a fresh email posting for new versions of your patch when possible, as this way what to include in the commit log message is clear and always applies to the patch posted rather than bits and pieces of quoted material from previous postings that may or may not apply to the current version of the patch. So please repost this, and your new 2/2 patch, as clean new submissions. Thanks. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2010-05-03 19:49 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-04-30 18:41 [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid Simon Arlott 2010-04-30 18:41 ` [PATCH 2/2] ppp_generic: linearise skbs before passing them to pppd Simon Arlott 2010-05-03 6:27 ` David Miller 2010-05-03 16:51 ` [PATCH 2/2] ppp_generic: handle non-linear skbs when " Simon Arlott 2010-05-03 6:25 ` [PATCH 1/2] ppp_generic: pull 2 bytes so that PPP_PROTO(skb) is valid David Miller 2010-05-03 11:50 ` Simon Arlott 2010-05-03 19:49 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).