* [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
@ 2020-12-16 18:33 Davide Caratti
2020-12-16 19:01 ` Vinicius Costa Gomes
2020-12-17 19:05 ` Jakub Kicinski
0 siblings, 2 replies; 7+ messages in thread
From: Davide Caratti @ 2020-12-16 18:33 UTC (permalink / raw)
To: Jamal Hadi Salim, Cong Wang, Jiri Pirko, David S. Miller, Jakub Kicinski
Cc: Vinicius Costa Gomes, netdev
syzkaller shows that packets can still be dequeued while taprio_destroy()
is running. Let sch_taprio use the reset() function to cancel the advance
timer and drop all skbs from the child qdiscs.
Fixes: 5a781ccbd19e ("tc: Add support for configuring the taprio scheduler")
Link: https://syzkaller.appspot.com/bug?id=f362872379bf8f0017fb667c1ab158f2d1e764ae
Reported-by: syzbot+8971da381fb5a31f542d@syzkaller.appspotmail.com
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
---
net/sched/sch_taprio.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 26fb8a62996b..c74817ec9964 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -1597,6 +1597,21 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
return err;
}
+static void taprio_reset(struct Qdisc *sch)
+{
+ struct taprio_sched *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ int i;
+
+ hrtimer_cancel(&q->advance_timer);
+ if (q->qdiscs) {
+ for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
+ qdisc_reset(q->qdiscs[i]);
+ }
+ sch->qstats.backlog = 0;
+ sch->q.qlen = 0;
+}
+
static void taprio_destroy(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
@@ -1607,7 +1622,6 @@ static void taprio_destroy(struct Qdisc *sch)
list_del(&q->taprio_list);
spin_unlock(&taprio_list_lock);
- hrtimer_cancel(&q->advance_timer);
taprio_disable_offload(dev, q, NULL);
@@ -1954,6 +1968,7 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = {
.init = taprio_init,
.change = taprio_change,
.destroy = taprio_destroy,
+ .reset = taprio_reset,
.peek = taprio_peek,
.dequeue = taprio_dequeue,
.enqueue = taprio_enqueue,
--
2.29.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-16 18:33 [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them Davide Caratti
@ 2020-12-16 19:01 ` Vinicius Costa Gomes
2020-12-17 19:04 ` Jakub Kicinski
2020-12-17 19:05 ` Jakub Kicinski
1 sibling, 1 reply; 7+ messages in thread
From: Vinicius Costa Gomes @ 2020-12-16 19:01 UTC (permalink / raw)
To: Davide Caratti, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
David S. Miller, Jakub Kicinski
Cc: netdev
Davide Caratti <dcaratti@redhat.com> writes:
> syzkaller shows that packets can still be dequeued while taprio_destroy()
> is running. Let sch_taprio use the reset() function to cancel the advance
> timer and drop all skbs from the child qdiscs.
>
> Fixes: 5a781ccbd19e ("tc: Add support for configuring the taprio scheduler")
> Link: https://syzkaller.appspot.com/bug?id=f362872379bf8f0017fb667c1ab158f2d1e764ae
> Reported-by: syzbot+8971da381fb5a31f542d@syzkaller.appspotmail.com
> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
> ---
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Cheers,
--
Vinicius
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-16 19:01 ` Vinicius Costa Gomes
@ 2020-12-17 19:04 ` Jakub Kicinski
0 siblings, 0 replies; 7+ messages in thread
From: Jakub Kicinski @ 2020-12-17 19:04 UTC (permalink / raw)
To: Vinicius Costa Gomes
Cc: Davide Caratti, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
David S. Miller, netdev
On Wed, 16 Dec 2020 11:01:54 -0800 Vinicius Costa Gomes wrote:
> Davide Caratti <dcaratti@redhat.com> writes:
>
> > syzkaller shows that packets can still be dequeued while taprio_destroy()
> > is running. Let sch_taprio use the reset() function to cancel the advance
> > timer and drop all skbs from the child qdiscs.
> >
> > Fixes: 5a781ccbd19e ("tc: Add support for configuring the taprio scheduler")
> > Link: https://syzkaller.appspot.com/bug?id=f362872379bf8f0017fb667c1ab158f2d1e764ae
> > Reported-by: syzbot+8971da381fb5a31f542d@syzkaller.appspotmail.com
> > Signed-off-by: Davide Caratti <dcaratti@redhat.com>
>
> Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Applied thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-16 18:33 [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them Davide Caratti
2020-12-16 19:01 ` Vinicius Costa Gomes
@ 2020-12-17 19:05 ` Jakub Kicinski
2020-12-17 20:32 ` Davide Caratti
1 sibling, 1 reply; 7+ messages in thread
From: Jakub Kicinski @ 2020-12-17 19:05 UTC (permalink / raw)
To: Davide Caratti
Cc: Jamal Hadi Salim, Cong Wang, Jiri Pirko, David S. Miller,
Vinicius Costa Gomes, netdev
On Wed, 16 Dec 2020 19:33:29 +0100 Davide Caratti wrote:
> + if (q->qdiscs) {
> + for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
> + qdisc_reset(q->qdiscs[i]);
Are you sure that we can't graft a NULL in the middle of the array?
Shouldn't this be:
for (i = 0; i < dev->num_tx_queues; i++)
if (q->qdiscs[i])
qdisc_reset(q->qdiscs[i]);
?
If this is a problem it already exists in destroy so I'll apply anyway.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-17 19:05 ` Jakub Kicinski
@ 2020-12-17 20:32 ` Davide Caratti
2020-12-17 20:45 ` Jakub Kicinski
0 siblings, 1 reply; 7+ messages in thread
From: Davide Caratti @ 2020-12-17 20:32 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Jamal Hadi Salim, Cong Wang, Jiri Pirko, David S. Miller,
Vinicius Costa Gomes, netdev
hello Jakub, and thanks for checking!
On Thu, 2020-12-17 at 11:05 -0800, Jakub Kicinski wrote:
> On Wed, 16 Dec 2020 19:33:29 +0100 Davide Caratti wrote:
> > + if (q->qdiscs) {
> > + for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
> > + qdisc_reset(q->qdiscs[i]);
>
> Are you sure that we can't graft a NULL in the middle of the array?
that should not happen, because child qdiscs are checked for being non-
NULL when they are created:
https://elixir.bootlin.com/linux/v5.10/source/net/sched/sch_taprio.c#L1674
and then assigned to q->qdiscs[i]. So, there might be NULL elements of
q->qdiscs[] in the middle of the array when taprio_reset() is called,
but it should be ok to finish the loop when we encounter the first one:
subsequent ones should be NULL as well.
> Shouldn't this be:
>
> for (i = 0; i < dev->num_tx_queues; i++)
> if (q->qdiscs[i])
> qdisc_reset(q->qdiscs[i]);
>
> ?
probably the above code is more robust, but - like you noticed - then we
should also change the same 'for' loop in taprio_destroy(), otherwise it
leaks resources. If you and Vinicius agree, I can post a follow-up patch
that makes ->reset() and ->destroy() more consistent with ->enqueue()
and ->dequeue(), and send it for net-next when it reopens. Ok?
--
davide
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-17 20:32 ` Davide Caratti
@ 2020-12-17 20:45 ` Jakub Kicinski
2020-12-17 20:49 ` Davide Caratti
0 siblings, 1 reply; 7+ messages in thread
From: Jakub Kicinski @ 2020-12-17 20:45 UTC (permalink / raw)
To: Davide Caratti
Cc: Jamal Hadi Salim, Cong Wang, Jiri Pirko, David S. Miller,
Vinicius Costa Gomes, netdev
On Thu, 17 Dec 2020 21:32:29 +0100 Davide Caratti wrote:
> hello Jakub, and thanks for checking!
>
> On Thu, 2020-12-17 at 11:05 -0800, Jakub Kicinski wrote:
> > On Wed, 16 Dec 2020 19:33:29 +0100 Davide Caratti wrote:
> > > + if (q->qdiscs) {
> > > + for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
> > > + qdisc_reset(q->qdiscs[i]);
> >
> > Are you sure that we can't graft a NULL in the middle of the array?
>
> that should not happen, because child qdiscs are checked for being non-
> NULL when they are created:
>
> https://elixir.bootlin.com/linux/v5.10/source/net/sched/sch_taprio.c#L1674
>
> and then assigned to q->qdiscs[i]. So, there might be NULL elements of
> q->qdiscs[] in the middle of the array when taprio_reset() is called,
> but it should be ok to finish the loop when we encounter the first one:
> subsequent ones should be NULL as well.
Right, but that's init, look at taprio_graft(). The child qdiscs can be
replaced at any time. And the replacement can be NULL otherwise why
would graft check "if (new)"
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them
2020-12-17 20:45 ` Jakub Kicinski
@ 2020-12-17 20:49 ` Davide Caratti
0 siblings, 0 replies; 7+ messages in thread
From: Davide Caratti @ 2020-12-17 20:49 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Jamal Hadi Salim, Cong Wang, Jiri Pirko, David S. Miller,
Vinicius Costa Gomes, netdev
On Thu, 2020-12-17 at 12:45 -0800, Jakub Kicinski wrote:
> Right, but that's init, look at taprio_graft(). The child qdiscs can be
> replaced at any time. And the replacement can be NULL otherwise why
> would graft check "if (new)"
good point, you are right. I'll send a follow-up patch right now.
thanks!
--
davide
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-12-17 20:51 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-16 18:33 [PATCH net] net/sched: sch_taprio: reset child qdiscs before freeing them Davide Caratti
2020-12-16 19:01 ` Vinicius Costa Gomes
2020-12-17 19:04 ` Jakub Kicinski
2020-12-17 19:05 ` Jakub Kicinski
2020-12-17 20:32 ` Davide Caratti
2020-12-17 20:45 ` Jakub Kicinski
2020-12-17 20:49 ` Davide Caratti
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.