summaryrefslogtreecommitdiff
path: root/net/netlink/genetlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/genetlink.c')
-rw-r--r--net/netlink/genetlink.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index d251d894afd4..5cc1037d4917 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1513,6 +1513,7 @@ struct ctrl_dump_policy_ctx {
struct netlink_policy_dump_state *state;
const struct genl_family *rt;
struct genl_op_iter *op_iter;
+ struct module *owner;
u32 op;
u16 fam_id;
u8 dump_map:1,
@@ -1555,6 +1556,9 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
return -ENOENT;
ctx->rt = rt;
+ ctx->owner = rt->module;
+ if (!try_module_get(ctx->owner))
+ return -ENOENT;
if (tb[CTRL_ATTR_OP]) {
struct genl_split_ops doit, dump;
@@ -1565,7 +1569,7 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
err = genl_get_cmd_both(ctx->op, rt, &doit, &dump);
if (err) {
NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
- return err;
+ goto err_put_owner;
}
if (doit.policy) {
@@ -1583,16 +1587,20 @@ static int ctrl_dumppolicy_start(struct netlink_callback *cb)
goto err_free_state;
}
- if (!ctx->state)
- return -ENODATA;
+ if (!ctx->state) {
+ err = -ENODATA;
+ goto err_put_owner;
+ }
ctx->dump_map = 1;
return 0;
}
ctx->op_iter = kmalloc_obj(*ctx->op_iter);
- if (!ctx->op_iter)
- return -ENOMEM;
+ if (!ctx->op_iter) {
+ err = -ENOMEM;
+ goto err_put_owner;
+ }
genl_op_iter_init(rt, ctx->op_iter);
ctx->dump_map = genl_op_iter_next(ctx->op_iter);
@@ -1624,6 +1632,8 @@ err_free_state:
netlink_policy_dump_free(ctx->state);
err_free_op_iter:
kfree(ctx->op_iter);
+err_put_owner:
+ module_put(ctx->owner);
return err;
}
@@ -1646,7 +1656,7 @@ static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
}
static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
- struct netlink_callback *cb,
+ struct netlink_callback *cb, u32 cmd,
struct genl_split_ops *doit,
struct genl_split_ops *dumpit)
{
@@ -1667,7 +1677,7 @@ static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
if (!nest_pol)
goto err;
- nest_op = nla_nest_start(skb, doit->cmd);
+ nest_op = nla_nest_start(skb, cmd);
if (!nest_op)
goto err;
@@ -1711,7 +1721,8 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
&doit, &dumpit)))
return -ENOENT;
- if (ctrl_dumppolicy_put_op(skb, cb, &doit, &dumpit))
+ if (ctrl_dumppolicy_put_op(skb, cb, ctx->op,
+ &doit, &dumpit))
return skb->len;
/* done with the per-op policy index list */
@@ -1720,6 +1731,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
while (ctx->dump_map) {
if (ctrl_dumppolicy_put_op(skb, cb,
+ ctx->op_iter->cmd,
&ctx->op_iter->doit,
&ctx->op_iter->dumpit))
return skb->len;
@@ -1760,6 +1772,7 @@ static int ctrl_dumppolicy_done(struct netlink_callback *cb)
kfree(ctx->op_iter);
netlink_policy_dump_free(ctx->state);
+ module_put(ctx->owner);
return 0;
}
@@ -1972,8 +1985,10 @@ int genlmsg_multicast_allns(const struct genl_family *family,
struct sk_buff *skb, u32 portid,
unsigned int group)
{
- if (WARN_ON_ONCE(group >= family->n_mcgrps))
+ if (WARN_ON_ONCE(group >= family->n_mcgrps)) {
+ kfree_skb(skb);
return -EINVAL;
+ }
group = family->mcgrp_offset + group;
return genlmsg_mcast(skb, portid, group);
@@ -1986,8 +2001,10 @@ void genl_notify(const struct genl_family *family, struct sk_buff *skb,
struct net *net = genl_info_net(info);
struct sock *sk = net->genl_sock;
- if (WARN_ON_ONCE(group >= family->n_mcgrps))
+ if (WARN_ON_ONCE(group >= family->n_mcgrps)) {
+ kfree_skb(skb);
return;
+ }
group = family->mcgrp_offset + group;
nlmsg_notify(sk, skb, info->snd_portid, group,