Commit a107e538 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[PKT_SCHED]: Fix scheduler/classifier module unload race.

This patch fixes an scheduler/classifier module unload race.
struct Qdisc_ops which includes the owner field is also part
of the module's memory, so ops might already be freed when
try_module_get(ops->owner) is called outside of the locked
section.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab3fc8a0
...@@ -60,9 +60,12 @@ static struct tcf_proto_ops * tcf_proto_lookup_ops(struct rtattr *kind) ...@@ -60,9 +60,12 @@ static struct tcf_proto_ops * tcf_proto_lookup_ops(struct rtattr *kind)
if (kind) { if (kind) {
read_lock(&cls_mod_lock); read_lock(&cls_mod_lock);
for (t = tcf_proto_base; t; t = t->next) { for (t = tcf_proto_base; t; t = t->next) {
if (rtattr_strcmp(kind, t->kind) == 0) if (rtattr_strcmp(kind, t->kind) == 0) {
if (!try_module_get(t->owner))
t = NULL;
break; break;
} }
}
read_unlock(&cls_mod_lock); read_unlock(&cls_mod_lock);
} }
return t; return t;
...@@ -231,11 +234,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) ...@@ -231,11 +234,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
tp->q = q; tp->q = q;
tp->classify = tp_ops->classify; tp->classify = tp_ops->classify;
tp->classid = parent; tp->classid = parent;
err = -EBUSY;
if (!try_module_get(tp_ops->owner)) {
kfree(tp);
goto errout;
}
if ((err = tp_ops->init(tp)) != 0) { if ((err = tp_ops->init(tp)) != 0) {
module_put(tp_ops->owner); module_put(tp_ops->owner);
kfree(tp); kfree(tp);
......
...@@ -229,9 +229,12 @@ struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind) ...@@ -229,9 +229,12 @@ struct Qdisc_ops *qdisc_lookup_ops(struct rtattr *kind)
if (kind) { if (kind) {
read_lock(&qdisc_mod_lock); read_lock(&qdisc_mod_lock);
for (q = qdisc_base; q; q = q->next) { for (q = qdisc_base; q; q = q->next) {
if (rtattr_strcmp(kind, q->id) == 0) if (rtattr_strcmp(kind, q->id) == 0) {
if (!try_module_get(q->owner))
q = NULL;
break; break;
} }
}
read_unlock(&qdisc_mod_lock); read_unlock(&qdisc_mod_lock);
} }
return q; return q;
...@@ -409,9 +412,6 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) ...@@ -409,9 +412,6 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
err = -EINVAL; err = -EINVAL;
if (ops == NULL) if (ops == NULL)
goto err_out; goto err_out;
err = -EBUSY;
if (!try_module_get(ops->owner))
goto err_out;
/* ensure that the Qdisc and the private data are 32-byte aligned */ /* ensure that the Qdisc and the private data are 32-byte aligned */
size = ((sizeof(*sch) + QDISC_ALIGN_CONST) & ~QDISC_ALIGN_CONST); size = ((sizeof(*sch) + QDISC_ALIGN_CONST) & ~QDISC_ALIGN_CONST);
......
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