diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-11-19 09:19:39 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-19 16:39:06 -0500 |
commit | 2a94fe48f32ccf7321450a2cc07f2b724a444e5b (patch) | |
tree | e5a066d8f83d8822d448421019a4503f361295f9 /include | |
parent | 68eb55031da7c967d954e5f9415cd05f4abdb692 (diff) |
genetlink: make multicast groups const, prevent abuse
Register generic netlink multicast groups as an array with
the family and give them contiguous group IDs. Then instead
of passing the global group ID to the various functions that
send messages, pass the ID relative to the family - for most
families that's just 0 because the only have one group.
This avoids the list_head and ID in each group, adding a new
field for the mcast group ID offset to the family.
At the same time, this allows us to prevent abusing groups
again like the quota and dropmon code did, since we can now
check that a family only uses a group it owns.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/genl_magic_func.h | 49 | ||||
-rw-r--r-- | include/net/genetlink.h | 48 |
2 files changed, 51 insertions, 46 deletions
diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h index 5b9b8ae6748b..c0894dd8827b 100644 --- a/include/linux/genl_magic_func.h +++ b/include/linux/genl_magic_func.h | |||
@@ -273,49 +273,40 @@ static struct genl_family ZZZ_genl_family __read_mostly = { | |||
273 | * Magic: define multicast groups | 273 | * Magic: define multicast groups |
274 | * Magic: define multicast group registration helper | 274 | * Magic: define multicast group registration helper |
275 | */ | 275 | */ |
276 | #define ZZZ_genl_mcgrps CONCAT_(GENL_MAGIC_FAMILY, _genl_mcgrps) | ||
277 | static const struct genl_multicast_group ZZZ_genl_mcgrps[] = { | ||
278 | #undef GENL_mc_group | ||
279 | #define GENL_mc_group(group) { .name = #group, }, | ||
280 | #include GENL_MAGIC_INCLUDE_FILE | ||
281 | }; | ||
282 | |||
283 | enum CONCAT_(GENL_MAGIC_FAMILY, group_ids) { | ||
284 | #undef GENL_mc_group | ||
285 | #define GENL_mc_group(group) CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group), | ||
286 | #include GENL_MAGIC_INCLUDE_FILE | ||
287 | }; | ||
288 | |||
276 | #undef GENL_mc_group | 289 | #undef GENL_mc_group |
277 | #define GENL_mc_group(group) \ | 290 | #define GENL_mc_group(group) \ |
278 | static struct genl_multicast_group \ | ||
279 | CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group) __read_mostly = { \ | ||
280 | .name = #group, \ | ||
281 | }; \ | ||
282 | static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ | 291 | static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ |
283 | struct sk_buff *skb, gfp_t flags) \ | 292 | struct sk_buff *skb, gfp_t flags) \ |
284 | { \ | 293 | { \ |
285 | unsigned int group_id = \ | 294 | unsigned int group_id = \ |
286 | CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id; \ | 295 | CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group); \ |
287 | if (!group_id) \ | ||
288 | return -EINVAL; \ | ||
289 | return genlmsg_multicast(&ZZZ_genl_family, skb, 0, \ | 296 | return genlmsg_multicast(&ZZZ_genl_family, skb, 0, \ |
290 | group_id, flags); \ | 297 | group_id, flags); \ |
291 | } | 298 | } |
292 | 299 | ||
293 | #include GENL_MAGIC_INCLUDE_FILE | 300 | #include GENL_MAGIC_INCLUDE_FILE |
294 | 301 | ||
295 | int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) | ||
296 | { | ||
297 | int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops); | ||
298 | if (err) | ||
299 | return err; | ||
300 | #undef GENL_mc_group | ||
301 | #define GENL_mc_group(group) \ | ||
302 | err = genl_register_mc_group(&ZZZ_genl_family, \ | ||
303 | &CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group)); \ | ||
304 | if (err) \ | ||
305 | goto fail; \ | ||
306 | else \ | ||
307 | pr_info("%s: mcg %s: %u\n", #group, \ | ||
308 | __stringify(GENL_MAGIC_FAMILY), \ | ||
309 | CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id); | ||
310 | |||
311 | #include GENL_MAGIC_INCLUDE_FILE | ||
312 | |||
313 | #undef GENL_mc_group | 302 | #undef GENL_mc_group |
314 | #define GENL_mc_group(group) | 303 | #define GENL_mc_group(group) |
315 | return 0; | 304 | |
316 | fail: | 305 | int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) |
317 | genl_unregister_family(&ZZZ_genl_family); | 306 | { |
318 | return err; | 307 | return genl_register_family_with_ops_groups(&ZZZ_genl_family, \ |
308 | ZZZ_genl_ops, \ | ||
309 | ZZZ_genl_mcgrps); | ||
319 | } | 310 | } |
320 | 311 | ||
321 | void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void) | 312 | void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void) |
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 60aef0df386b..ace4abf118d7 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h | |||
@@ -10,14 +10,9 @@ | |||
10 | /** | 10 | /** |
11 | * struct genl_multicast_group - generic netlink multicast group | 11 | * struct genl_multicast_group - generic netlink multicast group |
12 | * @name: name of the multicast group, names are per-family | 12 | * @name: name of the multicast group, names are per-family |
13 | * @id: multicast group ID, assigned by the core, to use with | ||
14 | * genlmsg_multicast(). | ||
15 | * @list: list entry for linking | ||
16 | */ | 13 | */ |
17 | struct genl_multicast_group { | 14 | struct genl_multicast_group { |
18 | struct list_head list; /* private */ | ||
19 | char name[GENL_NAMSIZ]; | 15 | char name[GENL_NAMSIZ]; |
20 | u32 id; | ||
21 | }; | 16 | }; |
22 | 17 | ||
23 | struct genl_ops; | 18 | struct genl_ops; |
@@ -38,7 +33,9 @@ struct genl_info; | |||
38 | * undo operations done by pre_doit, for example release locks | 33 | * undo operations done by pre_doit, for example release locks |
39 | * @attrbuf: buffer to store parsed attributes | 34 | * @attrbuf: buffer to store parsed attributes |
40 | * @family_list: family list | 35 | * @family_list: family list |
41 | * @mcast_groups: multicast groups list | 36 | * @mcgrps: multicast groups used by this family (private) |
37 | * @n_mcgrps: number of multicast groups (private) | ||
38 | * @mcgrp_offset: starting number of multicast group IDs in this family | ||
42 | * @ops: the operations supported by this family (private) | 39 | * @ops: the operations supported by this family (private) |
43 | * @n_ops: number of operations supported by this family (private) | 40 | * @n_ops: number of operations supported by this family (private) |
44 | */ | 41 | */ |
@@ -58,9 +55,11 @@ struct genl_family { | |||
58 | struct genl_info *info); | 55 | struct genl_info *info); |
59 | struct nlattr ** attrbuf; /* private */ | 56 | struct nlattr ** attrbuf; /* private */ |
60 | const struct genl_ops * ops; /* private */ | 57 | const struct genl_ops * ops; /* private */ |
58 | const struct genl_multicast_group *mcgrps; /* private */ | ||
61 | unsigned int n_ops; /* private */ | 59 | unsigned int n_ops; /* private */ |
60 | unsigned int n_mcgrps; /* private */ | ||
61 | unsigned int mcgrp_offset; /* private */ | ||
62 | struct list_head family_list; /* private */ | 62 | struct list_head family_list; /* private */ |
63 | struct list_head mcast_groups; /* private */ | ||
64 | struct module *module; | 63 | struct module *module; |
65 | }; | 64 | }; |
66 | 65 | ||
@@ -150,22 +149,30 @@ static inline int genl_register_family(struct genl_family *family) | |||
150 | * | 149 | * |
151 | * Return 0 on success or a negative error code. | 150 | * Return 0 on success or a negative error code. |
152 | */ | 151 | */ |
153 | static inline int _genl_register_family_with_ops(struct genl_family *family, | 152 | static inline int |
154 | const struct genl_ops *ops, | 153 | _genl_register_family_with_ops_grps(struct genl_family *family, |
155 | size_t n_ops) | 154 | const struct genl_ops *ops, size_t n_ops, |
155 | const struct genl_multicast_group *mcgrps, | ||
156 | size_t n_mcgrps) | ||
156 | { | 157 | { |
157 | family->module = THIS_MODULE; | 158 | family->module = THIS_MODULE; |
158 | family->ops = ops; | 159 | family->ops = ops; |
159 | family->n_ops = n_ops; | 160 | family->n_ops = n_ops; |
161 | family->mcgrps = mcgrps; | ||
162 | family->n_mcgrps = n_mcgrps; | ||
160 | return __genl_register_family(family); | 163 | return __genl_register_family(family); |
161 | } | 164 | } |
162 | 165 | ||
163 | #define genl_register_family_with_ops(family, ops) \ | 166 | #define genl_register_family_with_ops(family, ops) \ |
164 | _genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops)) | 167 | _genl_register_family_with_ops_grps((family), \ |
168 | (ops), ARRAY_SIZE(ops), \ | ||
169 | NULL, 0) | ||
170 | #define genl_register_family_with_ops_groups(family, ops, grps) \ | ||
171 | _genl_register_family_with_ops_grps((family), \ | ||
172 | (ops), ARRAY_SIZE(ops), \ | ||
173 | (grps), ARRAY_SIZE(grps)) | ||
165 | 174 | ||
166 | int genl_unregister_family(struct genl_family *family); | 175 | int genl_unregister_family(struct genl_family *family); |
167 | int genl_register_mc_group(struct genl_family *family, | ||
168 | struct genl_multicast_group *grp); | ||
169 | void genl_notify(struct genl_family *family, | 176 | void genl_notify(struct genl_family *family, |
170 | struct sk_buff *skb, struct net *net, u32 portid, | 177 | struct sk_buff *skb, struct net *net, u32 portid, |
171 | u32 group, struct nlmsghdr *nlh, gfp_t flags); | 178 | u32 group, struct nlmsghdr *nlh, gfp_t flags); |
@@ -251,13 +258,16 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) | |||
251 | * @net: the net namespace | 258 | * @net: the net namespace |
252 | * @skb: netlink message as socket buffer | 259 | * @skb: netlink message as socket buffer |
253 | * @portid: own netlink portid to avoid sending to yourself | 260 | * @portid: own netlink portid to avoid sending to yourself |
254 | * @group: multicast group id | 261 | * @group: offset of multicast group in groups array |
255 | * @flags: allocation flags | 262 | * @flags: allocation flags |
256 | */ | 263 | */ |
257 | static inline int genlmsg_multicast_netns(struct genl_family *family, | 264 | static inline int genlmsg_multicast_netns(struct genl_family *family, |
258 | struct net *net, struct sk_buff *skb, | 265 | struct net *net, struct sk_buff *skb, |
259 | u32 portid, unsigned int group, gfp_t flags) | 266 | u32 portid, unsigned int group, gfp_t flags) |
260 | { | 267 | { |
268 | if (group >= family->n_mcgrps) | ||
269 | return -EINVAL; | ||
270 | group = family->mcgrp_offset + group; | ||
261 | return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); | 271 | return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); |
262 | } | 272 | } |
263 | 273 | ||
@@ -266,13 +276,16 @@ static inline int genlmsg_multicast_netns(struct genl_family *family, | |||
266 | * @family: the generic netlink family | 276 | * @family: the generic netlink family |
267 | * @skb: netlink message as socket buffer | 277 | * @skb: netlink message as socket buffer |
268 | * @portid: own netlink portid to avoid sending to yourself | 278 | * @portid: own netlink portid to avoid sending to yourself |
269 | * @group: multicast group id | 279 | * @group: offset of multicast group in groups array |
270 | * @flags: allocation flags | 280 | * @flags: allocation flags |
271 | */ | 281 | */ |
272 | static inline int genlmsg_multicast(struct genl_family *family, | 282 | static inline int genlmsg_multicast(struct genl_family *family, |
273 | struct sk_buff *skb, u32 portid, | 283 | struct sk_buff *skb, u32 portid, |
274 | unsigned int group, gfp_t flags) | 284 | unsigned int group, gfp_t flags) |
275 | { | 285 | { |
286 | if (group >= family->n_mcgrps) | ||
287 | return -EINVAL; | ||
288 | group = family->mcgrp_offset + group; | ||
276 | return genlmsg_multicast_netns(family, &init_net, skb, | 289 | return genlmsg_multicast_netns(family, &init_net, skb, |
277 | portid, group, flags); | 290 | portid, group, flags); |
278 | } | 291 | } |
@@ -282,7 +295,7 @@ static inline int genlmsg_multicast(struct genl_family *family, | |||
282 | * @family: the generic netlink family | 295 | * @family: the generic netlink family |
283 | * @skb: netlink message as socket buffer | 296 | * @skb: netlink message as socket buffer |
284 | * @portid: own netlink portid to avoid sending to yourself | 297 | * @portid: own netlink portid to avoid sending to yourself |
285 | * @group: multicast group id | 298 | * @group: offset of multicast group in groups array |
286 | * @flags: allocation flags | 299 | * @flags: allocation flags |
287 | * | 300 | * |
288 | * This function must hold the RTNL or rcu_read_lock(). | 301 | * This function must hold the RTNL or rcu_read_lock(). |
@@ -365,6 +378,7 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) | |||
365 | * @net: the network namespace to report the error to | 378 | * @net: the network namespace to report the error to |
366 | * @portid: the PORTID of a process that we want to skip (if any) | 379 | * @portid: the PORTID of a process that we want to skip (if any) |
367 | * @group: the broadcast group that will notice the error | 380 | * @group: the broadcast group that will notice the error |
381 | * (this is the offset of the multicast group in the groups array) | ||
368 | * @code: error code, must be negative (as usual in kernelspace) | 382 | * @code: error code, must be negative (as usual in kernelspace) |
369 | * | 383 | * |
370 | * This function returns the number of broadcast listeners that have set the | 384 | * This function returns the number of broadcast listeners that have set the |