Commit 4fab6412 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net/sched: fix error recovery in qdisc_create()

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: 1f62879e ("net/sched: make stab available before ops->init() call")
Reported-by: syzbot+d44d88f1d11e6ca8576b@syzkaller.appspotmail.com
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Vladimir Oltean <vladimir.oltean@nxp.com>
Cc: Kurt Kanzenbach <kurt@linutronix.de>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cafc3662
...@@ -1286,7 +1286,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1286,7 +1286,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
stab = qdisc_get_stab(tca[TCA_STAB], extack); stab = qdisc_get_stab(tca[TCA_STAB], extack);
if (IS_ERR(stab)) { if (IS_ERR(stab)) {
err = PTR_ERR(stab); err = PTR_ERR(stab);
goto err_out4; goto err_out3;
} }
rcu_assign_pointer(sch->stab, stab); rcu_assign_pointer(sch->stab, stab);
} }
...@@ -1294,14 +1294,14 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1294,14 +1294,14 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
if (ops->init) { if (ops->init) {
err = ops->init(sch, tca[TCA_OPTIONS], extack); err = ops->init(sch, tca[TCA_OPTIONS], extack);
if (err != 0) if (err != 0)
goto err_out5; goto err_out4;
} }
if (tca[TCA_RATE]) { if (tca[TCA_RATE]) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (sch->flags & TCQ_F_MQROOT) { if (sch->flags & TCQ_F_MQROOT) {
NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc"); 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, err = gen_new_estimator(&sch->bstats,
...@@ -1312,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1312,7 +1312,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
tca[TCA_RATE]); tca[TCA_RATE]);
if (err) { if (err) {
NL_SET_ERR_MSG(extack, "Failed to generate new estimator"); NL_SET_ERR_MSG(extack, "Failed to generate new estimator");
goto err_out5; goto err_out4;
} }
} }
...@@ -1321,12 +1321,13 @@ static struct Qdisc *qdisc_create(struct net_device *dev, ...@@ -1321,12 +1321,13 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
return sch; return sch;
err_out5:
qdisc_put_stab(rtnl_dereference(sch->stab));
err_out4: 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) if (ops->destroy)
ops->destroy(sch); ops->destroy(sch);
qdisc_put_stab(rtnl_dereference(sch->stab));
err_out3: err_out3:
netdev_put(dev, &sch->dev_tracker); netdev_put(dev, &sch->dev_tracker);
qdisc_free(sch); qdisc_free(sch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment