Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netlink: fix policy dump leak

[ Upstream commit a95bc734e60449e7b073ff7ff70c35083b290ae9 ]

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

Fixes: d07dcf9aadd6 ("netlink: add infrastructure to expose policies to userspace")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Reviewed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Johannes Berg and committed by
David S. Miller
949ca6b8 360f8987

+20 -16
+2 -1
include/net/netlink.h
··· 1938 1938 int netlink_policy_dump_start(const struct nla_policy *policy, 1939 1939 unsigned int maxtype, 1940 1940 unsigned long *state); 1941 - bool netlink_policy_dump_loop(unsigned long *state); 1941 + bool netlink_policy_dump_loop(unsigned long state); 1942 1942 int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state); 1943 + void netlink_policy_dump_free(unsigned long state); 1943 1944 1944 1945 #endif
+8 -1
net/netlink/genetlink.c
··· 1079 1079 if (err) 1080 1080 return err; 1081 1081 1082 - while (netlink_policy_dump_loop(&cb->args[1])) { 1082 + while (netlink_policy_dump_loop(cb->args[1])) { 1083 1083 void *hdr; 1084 1084 struct nlattr *nest; 1085 1085 ··· 1113 1113 return skb->len; 1114 1114 } 1115 1115 1116 + static int ctrl_dumppolicy_done(struct netlink_callback *cb) 1117 + { 1118 + netlink_policy_dump_free(cb->args[1]); 1119 + return 0; 1120 + } 1121 + 1116 1122 static const struct genl_ops genl_ctrl_ops[] = { 1117 1123 { 1118 1124 .cmd = CTRL_CMD_GETFAMILY, ··· 1129 1123 { 1130 1124 .cmd = CTRL_CMD_GETPOLICY, 1131 1125 .dumpit = ctrl_dumppolicy, 1126 + .done = ctrl_dumppolicy_done, 1132 1127 }, 1133 1128 }; 1134 1129
+10 -14
net/netlink/policy.c
··· 84 84 unsigned int policy_idx; 85 85 int err; 86 86 87 - /* also returns 0 if "*_state" is our ERR_PTR() end marker */ 88 87 if (*_state) 89 88 return 0; 90 89 ··· 139 140 !state->policies[state->policy_idx].policy; 140 141 } 141 142 142 - bool netlink_policy_dump_loop(unsigned long *_state) 143 + bool netlink_policy_dump_loop(unsigned long _state) 143 144 { 144 - struct nl_policy_dump *state = (void *)*_state; 145 + struct nl_policy_dump *state = (void *)_state; 145 146 146 - if (IS_ERR(state)) 147 - return false; 148 - 149 - if (netlink_policy_dump_finished(state)) { 150 - kfree(state); 151 - /* store end marker instead of freed state */ 152 - *_state = (unsigned long)ERR_PTR(-ENOENT); 153 - return false; 154 - } 155 - 156 - return true; 147 + return !netlink_policy_dump_finished(state); 157 148 } 158 149 159 150 int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state) ··· 304 315 nla_put_failure: 305 316 nla_nest_cancel(skb, policy); 306 317 return -ENOBUFS; 318 + } 319 + 320 + void netlink_policy_dump_free(unsigned long _state) 321 + { 322 + struct nl_policy_dump *state = (void *)_state; 323 + 324 + kfree(state); 307 325 }