diff mbox series

[net] net: sched: prevent a use after free

Message ID 20200131065647.joonbg3wzcw26x3b@kili.mountain
State Changes Requested
Delegated to: David Miller
Headers show
Series [net] net: sched: prevent a use after free | expand

Commit Message

Dan Carpenter Jan. 31, 2020, 6:56 a.m. UTC
The code calls kfree_skb(skb); and then re-uses "skb" on the next line.
Let's re-order these lines to solve the problem.

Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 net/sched/sch_fq_pie.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Cong Wang Feb. 1, 2020, 7:38 p.m. UTC | #1
On Thu, Jan 30, 2020 at 10:57 PM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> The code calls kfree_skb(skb); and then re-uses "skb" on the next line.
> Let's re-order these lines to solve the problem.
>
> Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  net/sched/sch_fq_pie.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
> index bbd0dea6b6b9..78472e0773e9 100644
> --- a/net/sched/sch_fq_pie.c
> +++ b/net/sched/sch_fq_pie.c
> @@ -349,9 +349,9 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
>         while (sch->q.qlen > sch->limit) {
>                 struct sk_buff *skb = fq_pie_qdisc_dequeue(sch);
>
> -               kfree_skb(skb);
>                 len_dropped += qdisc_pkt_len(skb);
>                 num_dropped += 1;
> +               kfree_skb(skb);

Or even better: use rtnl_kfree_skbs().

Thanks.
Dan Carpenter Feb. 3, 2020, 8:38 a.m. UTC | #2
On Sat, Feb 01, 2020 at 11:38:43AM -0800, Cong Wang wrote:
> On Thu, Jan 30, 2020 at 10:57 PM Dan Carpenter <dan.carpenter@oracle.com> wrote:
> >
> > The code calls kfree_skb(skb); and then re-uses "skb" on the next line.
> > Let's re-order these lines to solve the problem.
> >
> > Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler")
> > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> > ---
> >  net/sched/sch_fq_pie.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
> > index bbd0dea6b6b9..78472e0773e9 100644
> > --- a/net/sched/sch_fq_pie.c
> > +++ b/net/sched/sch_fq_pie.c
> > @@ -349,9 +349,9 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
> >         while (sch->q.qlen > sch->limit) {
> >                 struct sk_buff *skb = fq_pie_qdisc_dequeue(sch);
> >
> > -               kfree_skb(skb);
> >                 len_dropped += qdisc_pkt_len(skb);
> >                 num_dropped += 1;
> > +               kfree_skb(skb);
> 
> Or even better: use rtnl_kfree_skbs().

Why is that better?

regards,
dan carpenter
Cong Wang Feb. 3, 2020, 7:58 p.m. UTC | #3
On Mon, Feb 3, 2020 at 12:39 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> On Sat, Feb 01, 2020 at 11:38:43AM -0800, Cong Wang wrote:
> > On Thu, Jan 30, 2020 at 10:57 PM Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > >
> > > The code calls kfree_skb(skb); and then re-uses "skb" on the next line.
> > > Let's re-order these lines to solve the problem.
> > >
> > > Fixes: ec97ecf1ebe4 ("net: sched: add Flow Queue PIE packet scheduler")
> > > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> > > ---
> > >  net/sched/sch_fq_pie.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
> > > index bbd0dea6b6b9..78472e0773e9 100644
> > > --- a/net/sched/sch_fq_pie.c
> > > +++ b/net/sched/sch_fq_pie.c
> > > @@ -349,9 +349,9 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
> > >         while (sch->q.qlen > sch->limit) {
> > >                 struct sk_buff *skb = fq_pie_qdisc_dequeue(sch);
> > >
> > > -               kfree_skb(skb);
> > >                 len_dropped += qdisc_pkt_len(skb);
> > >                 num_dropped += 1;
> > > +               kfree_skb(skb);
> >
> > Or even better: use rtnl_kfree_skbs().
>
> Why is that better?

Because it is designed to be used in this scenario,
as it defers the free after RTNL unlock which is after
sch_tree_unlock() too.

Thanks.
Cong Wang Feb. 3, 2020, 8:33 p.m. UTC | #4
On Mon, Feb 3, 2020 at 11:58 AM Cong Wang <xiyou.wangcong@gmail.com> wrote:
>
> On Mon, Feb 3, 2020 at 12:39 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > Why is that better?
>
> Because it is designed to be used in this scenario,
> as it defers the free after RTNL unlock which is after
> sch_tree_unlock() too.

Just in case of misunderstanding: I am _not_ suggesting to
use rtnl_kfree_skbs() to workaround this use-after-free,
rtnl_kfree_skbs() still has to be called after qdisc_pkt_len(),
at least for readability, despite that it could indeed
workaround the bug.

Thanks.
diff mbox series

Patch

diff --git a/net/sched/sch_fq_pie.c b/net/sched/sch_fq_pie.c
index bbd0dea6b6b9..78472e0773e9 100644
--- a/net/sched/sch_fq_pie.c
+++ b/net/sched/sch_fq_pie.c
@@ -349,9 +349,9 @@  static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt,
 	while (sch->q.qlen > sch->limit) {
 		struct sk_buff *skb = fq_pie_qdisc_dequeue(sch);
 
-		kfree_skb(skb);
 		len_dropped += qdisc_pkt_len(skb);
 		num_dropped += 1;
+		kfree_skb(skb);
 	}
 	qdisc_tree_reduce_backlog(sch, num_dropped, len_dropped);