Commit 949ca6b8 authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller

netlink: fix policy dump leak

[ Upstream commit a95bc734 ]

If userspace doesn't complete the policy dump, we leak the
allocated state. Fix this.

Fixes: d07dcf9a ("netlink: add infrastructure to expose policies to userspace")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Reviewed-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 360f8987
...@@ -1938,7 +1938,8 @@ void nla_get_range_signed(const struct nla_policy *pt, ...@@ -1938,7 +1938,8 @@ void nla_get_range_signed(const struct nla_policy *pt,
int netlink_policy_dump_start(const struct nla_policy *policy, int netlink_policy_dump_start(const struct nla_policy *policy,
unsigned int maxtype, unsigned int maxtype,
unsigned long *state); unsigned long *state);
bool netlink_policy_dump_loop(unsigned long *state); bool netlink_policy_dump_loop(unsigned long state);
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state); int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state);
void netlink_policy_dump_free(unsigned long state);
#endif #endif
...@@ -1079,7 +1079,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1079,7 +1079,7 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
if (err) if (err)
return err; return err;
while (netlink_policy_dump_loop(&cb->args[1])) { while (netlink_policy_dump_loop(cb->args[1])) {
void *hdr; void *hdr;
struct nlattr *nest; struct nlattr *nest;
...@@ -1113,6 +1113,12 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1113,6 +1113,12 @@ static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static int ctrl_dumppolicy_done(struct netlink_callback *cb)
{
netlink_policy_dump_free(cb->args[1]);
return 0;
}
static const struct genl_ops genl_ctrl_ops[] = { static const struct genl_ops genl_ctrl_ops[] = {
{ {
.cmd = CTRL_CMD_GETFAMILY, .cmd = CTRL_CMD_GETFAMILY,
...@@ -1123,6 +1129,7 @@ static const struct genl_ops genl_ctrl_ops[] = { ...@@ -1123,6 +1129,7 @@ static const struct genl_ops genl_ctrl_ops[] = {
{ {
.cmd = CTRL_CMD_GETPOLICY, .cmd = CTRL_CMD_GETPOLICY,
.dumpit = ctrl_dumppolicy, .dumpit = ctrl_dumppolicy,
.done = ctrl_dumppolicy_done,
}, },
}; };
......
...@@ -84,7 +84,6 @@ int netlink_policy_dump_start(const struct nla_policy *policy, ...@@ -84,7 +84,6 @@ int netlink_policy_dump_start(const struct nla_policy *policy,
unsigned int policy_idx; unsigned int policy_idx;
int err; int err;
/* also returns 0 if "*_state" is our ERR_PTR() end marker */
if (*_state) if (*_state)
return 0; return 0;
...@@ -140,21 +139,11 @@ static bool netlink_policy_dump_finished(struct nl_policy_dump *state) ...@@ -140,21 +139,11 @@ static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
!state->policies[state->policy_idx].policy; !state->policies[state->policy_idx].policy;
} }
bool netlink_policy_dump_loop(unsigned long *_state) bool netlink_policy_dump_loop(unsigned long _state)
{ {
struct nl_policy_dump *state = (void *)*_state; struct nl_policy_dump *state = (void *)_state;
if (IS_ERR(state))
return false;
if (netlink_policy_dump_finished(state)) {
kfree(state);
/* store end marker instead of freed state */
*_state = (unsigned long)ERR_PTR(-ENOENT);
return false;
}
return true; return !netlink_policy_dump_finished(state);
} }
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state) int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
...@@ -316,3 +305,10 @@ int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state) ...@@ -316,3 +305,10 @@ int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
nla_nest_cancel(skb, policy); nla_nest_cancel(skb, policy);
return -ENOBUFS; return -ENOBUFS;
} }
void netlink_policy_dump_free(unsigned long _state)
{
struct nl_policy_dump *state = (void *)_state;
kfree(state);
}
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