Skip to content

Commit

Permalink
net/sched: fix error recovery in qdisc_create()
Browse files Browse the repository at this point in the history
If TCA_STAB attribute is malformed, qdisc_get_stab() returns
an error, and we end up calling ops->destroy() while ops->init()
has not been called yet.

While we are at it, call qdisc_put_stab() after ops->destroy().

Fixes: 1f62879 ("net/sched: make stab available before ops->init() call")
Reported-by: syzbot+d44d88f1d11e6ca8576b@syzkaller.appspotmail.com
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Vladimir Oltean <vladimir.oltean@nxp.com>
Cc: Kurt Kanzenbach <kurt@linutronix.de>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Feb 13, 2023
1 parent cafc366 commit 4fab641
Showing 1 changed file with 8 additions and 7 deletions.
15 changes: 8 additions & 7 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1286,22 +1286,22 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
stab = qdisc_get_stab(tca[TCA_STAB], extack);
if (IS_ERR(stab)) {
err = PTR_ERR(stab);
goto err_out4;
goto err_out3;
}
rcu_assign_pointer(sch->stab, stab);
}

if (ops->init) {
err = ops->init(sch, tca[TCA_OPTIONS], extack);
if (err != 0)
goto err_out5;
goto err_out4;
}

if (tca[TCA_RATE]) {
err = -EOPNOTSUPP;
if (sch->flags & TCQ_F_MQROOT) {
NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc");
goto err_out5;
goto err_out4;
}

err = gen_new_estimator(&sch->bstats,
Expand All @@ -1312,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
tca[TCA_RATE]);
if (err) {
NL_SET_ERR_MSG(extack, "Failed to generate new estimator");
goto err_out5;
goto err_out4;
}
}

Expand All @@ -1321,12 +1321,13 @@ static struct Qdisc *qdisc_create(struct net_device *dev,

return sch;

err_out5:
qdisc_put_stab(rtnl_dereference(sch->stab));
err_out4:
/* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
/* Even if ops->init() failed, we call ops->destroy()
* like qdisc_create_dflt().
*/
if (ops->destroy)
ops->destroy(sch);
qdisc_put_stab(rtnl_dereference(sch->stab));
err_out3:
netdev_put(dev, &sch->dev_tracker);
qdisc_free(sch);
Expand Down

0 comments on commit 4fab641

Please sign in to comment.