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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'genetlink-per-op-type-policies'

Jakub Kicinski says:

====================
genetlink: support per op type policies

While writing new genetlink families I was increasingly annoyed by the fact
that we don't support different policies for do and dump callbacks.
This makes it hard to do proper input validation for dumps which usually
have a lot more narrow range of accepted attributes.

There is also a minor inconvenience of not supporting different per_doit
and post_doit callbacks per op.

This series addresses those problems by introducing another op format.

v3:
- minor fixes to patch 12 after I took it for a spin with a real family
- adjust commit msg in patch 8
v2: https://lore.kernel.org/all/20221102213338.194672-1-kuba@kernel.org/
- wait for net changes to propagate
- restore the missing comment in patch 1
- drop extra space in patch 3
- improve commit message in patch 4
v1: https://lore.kernel.org/all/20221018230728.1039524-1-kuba@kernel.org/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+446 -143
+67 -9
include/net/genetlink.h
··· 18 18 u8 flags; 19 19 }; 20 20 21 - struct genl_ops; 21 + struct genl_split_ops; 22 22 struct genl_info; 23 23 24 24 /** 25 25 * struct genl_family - generic netlink family 26 - * @id: protocol family identifier (private) 27 26 * @hdrsize: length of user specific header in bytes 28 27 * @name: name of family 29 28 * @version: protocol version ··· 42 43 * @resv_start_op: first operation for which reserved fields of the header 43 44 * can be validated and policies are required (see below); 44 45 * new families should leave this field at zero 45 - * @mcgrp_offset: starting number of multicast group IDs in this family 46 - * (private) 47 46 * @ops: the operations supported by this family 48 47 * @n_ops: number of operations supported by this family 49 48 * @small_ops: the small-struct operations supported by this family 50 49 * @n_small_ops: number of small-struct operations supported by this family 50 + * @split_ops: the split do/dump form of operation definition 51 + * @n_split_ops: number of entries in @split_ops, not that with split do/dump 52 + * ops the number of entries is not the same as number of commands 51 53 * 52 54 * Attribute policies (the combination of @policy and @maxattr fields) 53 55 * can be attached at the family level or at the operation level. ··· 58 58 * if policy is not provided core will reject all TLV attributes. 59 59 */ 60 60 struct genl_family { 61 - int id; /* private */ 62 61 unsigned int hdrsize; 63 62 char name[GENL_NAMSIZ]; 64 63 unsigned int version; 65 64 unsigned int maxattr; 66 - unsigned int mcgrp_offset; /* private */ 67 65 u8 netnsok:1; 68 66 u8 parallel_ops:1; 69 67 u8 n_ops; 70 68 u8 n_small_ops; 69 + u8 n_split_ops; 71 70 u8 n_mcgrps; 72 71 u8 resv_start_op; 73 72 const struct nla_policy *policy; 74 - int (*pre_doit)(const struct genl_ops *ops, 73 + int (*pre_doit)(const struct genl_split_ops *ops, 75 74 struct sk_buff *skb, 76 75 struct genl_info *info); 77 - void (*post_doit)(const struct genl_ops *ops, 76 + void (*post_doit)(const struct genl_split_ops *ops, 78 77 struct sk_buff *skb, 79 78 struct genl_info *info); 80 79 const struct genl_ops * ops; 81 80 const struct genl_small_ops *small_ops; 81 + const struct genl_split_ops *split_ops; 82 82 const struct genl_multicast_group *mcgrps; 83 83 struct module *module; 84 + 85 + /* private: internal use only */ 86 + /* protocol family identifier */ 87 + int id; 88 + /* starting number of multicast group IDs in this family */ 89 + unsigned int mcgrp_offset; 84 90 }; 85 91 86 92 /** ··· 188 182 }; 189 183 190 184 /** 185 + * struct genl_split_ops - generic netlink operations (do/dump split version) 186 + * @cmd: command identifier 187 + * @internal_flags: flags used by the family 188 + * @flags: GENL_* flags (%GENL_ADMIN_PERM or %GENL_UNS_ADMIN_PERM) 189 + * @validate: validation flags from enum genl_validate_flags 190 + * @policy: netlink policy (takes precedence over family policy) 191 + * @maxattr: maximum number of attributes supported 192 + * 193 + * Do callbacks: 194 + * @pre_doit: called before an operation's @doit callback, it may 195 + * do additional, common, filtering and return an error 196 + * @doit: standard command callback 197 + * @post_doit: called after an operation's @doit callback, it may 198 + * undo operations done by pre_doit, for example release locks 199 + * 200 + * Dump callbacks: 201 + * @start: start callback for dumps 202 + * @dumpit: callback for dumpers 203 + * @done: completion callback for dumps 204 + * 205 + * Do callbacks can be used if %GENL_CMD_CAP_DO is set in @flags. 206 + * Dump callbacks can be used if %GENL_CMD_CAP_DUMP is set in @flags. 207 + * Exactly one of those flags must be set. 208 + */ 209 + struct genl_split_ops { 210 + union { 211 + struct { 212 + int (*pre_doit)(const struct genl_split_ops *ops, 213 + struct sk_buff *skb, 214 + struct genl_info *info); 215 + int (*doit)(struct sk_buff *skb, 216 + struct genl_info *info); 217 + void (*post_doit)(const struct genl_split_ops *ops, 218 + struct sk_buff *skb, 219 + struct genl_info *info); 220 + }; 221 + struct { 222 + int (*start)(struct netlink_callback *cb); 223 + int (*dumpit)(struct sk_buff *skb, 224 + struct netlink_callback *cb); 225 + int (*done)(struct netlink_callback *cb); 226 + }; 227 + }; 228 + const struct nla_policy *policy; 229 + unsigned int maxattr; 230 + u8 cmd; 231 + u8 internal_flags; 232 + u8 flags; 233 + u8 validate; 234 + }; 235 + 236 + /** 191 237 * struct genl_dumpit_info - info that is available during dumpit op call 192 238 * @family: generic netlink family - for internal genl code usage 193 239 * @op: generic netlink ops - for internal genl code usage ··· 247 189 */ 248 190 struct genl_dumpit_info { 249 191 const struct genl_family *family; 250 - struct genl_ops op; 192 + struct genl_split_ops op; 251 193 struct nlattr **attrs; 252 194 }; 253 195
+4 -2
net/batman-adv/netlink.c
··· 1267 1267 * 1268 1268 * Return: 0 on success or negative error number in case of failure 1269 1269 */ 1270 - static int batadv_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 1270 + static int batadv_pre_doit(const struct genl_split_ops *ops, 1271 + struct sk_buff *skb, 1271 1272 struct genl_info *info) 1272 1273 { 1273 1274 struct net *net = genl_info_net(info); ··· 1333 1332 * @skb: Netlink message with request data 1334 1333 * @info: receiver information 1335 1334 */ 1336 - static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 1335 + static void batadv_post_doit(const struct genl_split_ops *ops, 1336 + struct sk_buff *skb, 1337 1337 struct genl_info *info) 1338 1338 { 1339 1339 struct batadv_hard_iface *hard_iface;
+2 -2
net/core/devlink.c
··· 770 770 #define DEVLINK_NL_FLAG_NEED_RATE_NODE BIT(3) 771 771 #define DEVLINK_NL_FLAG_NEED_LINECARD BIT(4) 772 772 773 - static int devlink_nl_pre_doit(const struct genl_ops *ops, 773 + static int devlink_nl_pre_doit(const struct genl_split_ops *ops, 774 774 struct sk_buff *skb, struct genl_info *info) 775 775 { 776 776 struct devlink_linecard *linecard; ··· 828 828 return err; 829 829 } 830 830 831 - static void devlink_nl_post_doit(const struct genl_ops *ops, 831 + static void devlink_nl_post_doit(const struct genl_split_ops *ops, 832 832 struct sk_buff *skb, struct genl_info *info) 833 833 { 834 834 struct devlink_linecard *linecard;
+2 -2
net/core/drop_monitor.c
··· 1620 1620 }, 1621 1621 }; 1622 1622 1623 - static int net_dm_nl_pre_doit(const struct genl_ops *ops, 1623 + static int net_dm_nl_pre_doit(const struct genl_split_ops *ops, 1624 1624 struct sk_buff *skb, struct genl_info *info) 1625 1625 { 1626 1626 mutex_lock(&net_dm_mutex); ··· 1628 1628 return 0; 1629 1629 } 1630 1630 1631 - static void net_dm_nl_post_doit(const struct genl_ops *ops, 1631 + static void net_dm_nl_post_doit(const struct genl_split_ops *ops, 1632 1632 struct sk_buff *skb, struct genl_info *info) 1633 1633 { 1634 1634 mutex_unlock(&net_dm_mutex);
+4 -2
net/ieee802154/nl802154.c
··· 2157 2157 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08 2158 2158 #define NL802154_FLAG_NEED_WPAN_DEV 0x10 2159 2159 2160 - static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 2160 + static int nl802154_pre_doit(const struct genl_split_ops *ops, 2161 + struct sk_buff *skb, 2161 2162 struct genl_info *info) 2162 2163 { 2163 2164 struct cfg802154_registered_device *rdev; ··· 2220 2219 return 0; 2221 2220 } 2222 2221 2223 - static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 2222 + static void nl802154_post_doit(const struct genl_split_ops *ops, 2223 + struct sk_buff *skb, 2224 2224 struct genl_info *info) 2225 2225 { 2226 2226 if (info->user_ptr[1]) {
+363 -124
net/netlink/genetlink.c
··· 101 101 op->maxattr = 1; 102 102 } 103 103 104 + static void 105 + genl_op_fill_in_reject_policy_split(const struct genl_family *family, 106 + struct genl_split_ops *op) 107 + { 108 + if (op->policy) 109 + return; 110 + 111 + op->policy = genl_policy_reject_all; 112 + op->maxattr = 1; 113 + } 114 + 104 115 static const struct genl_family *genl_family_find_byid(unsigned int id) 105 116 { 106 117 return idr_find(&genl_fam_idr, id); ··· 129 118 return NULL; 130 119 } 131 120 132 - static int genl_get_cmd_cnt(const struct genl_family *family) 133 - { 134 - return family->n_ops + family->n_small_ops; 135 - } 121 + struct genl_op_iter { 122 + const struct genl_family *family; 123 + struct genl_split_ops doit; 124 + struct genl_split_ops dumpit; 125 + int cmd_idx; 126 + int entry_idx; 127 + u32 cmd; 128 + u8 flags; 129 + }; 136 130 137 131 static void genl_op_from_full(const struct genl_family *family, 138 132 unsigned int i, struct genl_ops *op) ··· 197 181 return -ENOENT; 198 182 } 199 183 200 - static int genl_get_cmd(u32 cmd, const struct genl_family *family, 201 - struct genl_ops *op) 184 + static void genl_op_from_split(struct genl_op_iter *iter) 202 185 { 203 - if (!genl_get_cmd_full(cmd, family, op)) 204 - return 0; 205 - return genl_get_cmd_small(cmd, family, op); 186 + const struct genl_family *family = iter->family; 187 + int i, cnt = 0; 188 + 189 + i = iter->entry_idx - family->n_ops - family->n_small_ops; 190 + 191 + if (family->split_ops[i + cnt].flags & GENL_CMD_CAP_DO) { 192 + iter->doit = family->split_ops[i + cnt]; 193 + genl_op_fill_in_reject_policy_split(family, &iter->doit); 194 + cnt++; 195 + } else { 196 + memset(&iter->doit, 0, sizeof(iter->doit)); 197 + } 198 + 199 + if (i + cnt < family->n_split_ops && 200 + family->split_ops[i + cnt].flags & GENL_CMD_CAP_DUMP) { 201 + iter->dumpit = family->split_ops[i + cnt]; 202 + genl_op_fill_in_reject_policy_split(family, &iter->dumpit); 203 + cnt++; 204 + } else { 205 + memset(&iter->dumpit, 0, sizeof(iter->dumpit)); 206 + } 207 + 208 + WARN_ON(!cnt); 209 + iter->entry_idx += cnt; 206 210 } 207 211 208 - static void genl_get_cmd_by_index(unsigned int i, 209 - const struct genl_family *family, 210 - struct genl_ops *op) 212 + static int 213 + genl_get_cmd_split(u32 cmd, u8 flag, const struct genl_family *family, 214 + struct genl_split_ops *op) 211 215 { 212 - if (i < family->n_ops) 213 - genl_op_from_full(family, i, op); 214 - else if (i < family->n_ops + family->n_small_ops) 215 - genl_op_from_small(family, i - family->n_ops, op); 216 - else 217 - WARN_ON_ONCE(1); 216 + int i; 217 + 218 + for (i = 0; i < family->n_split_ops; i++) 219 + if (family->split_ops[i].cmd == cmd && 220 + family->split_ops[i].flags & flag) { 221 + *op = family->split_ops[i]; 222 + return 0; 223 + } 224 + 225 + return -ENOENT; 226 + } 227 + 228 + static int 229 + genl_cmd_full_to_split(struct genl_split_ops *op, 230 + const struct genl_family *family, 231 + const struct genl_ops *full, u8 flags) 232 + { 233 + if ((flags & GENL_CMD_CAP_DO && !full->doit) || 234 + (flags & GENL_CMD_CAP_DUMP && !full->dumpit)) { 235 + memset(op, 0, sizeof(*op)); 236 + return -ENOENT; 237 + } 238 + 239 + if (flags & GENL_CMD_CAP_DUMP) { 240 + op->start = full->start; 241 + op->dumpit = full->dumpit; 242 + op->done = full->done; 243 + } else { 244 + op->pre_doit = family->pre_doit; 245 + op->doit = full->doit; 246 + op->post_doit = family->post_doit; 247 + } 248 + 249 + if (flags & GENL_CMD_CAP_DUMP && 250 + full->validate & GENL_DONT_VALIDATE_DUMP) { 251 + op->policy = NULL; 252 + op->maxattr = 0; 253 + } else { 254 + op->policy = full->policy; 255 + op->maxattr = full->maxattr; 256 + } 257 + 258 + op->cmd = full->cmd; 259 + op->internal_flags = full->internal_flags; 260 + op->flags = full->flags; 261 + op->validate = full->validate; 262 + 263 + /* Make sure flags include the GENL_CMD_CAP_DO / GENL_CMD_CAP_DUMP */ 264 + op->flags |= flags; 265 + 266 + return 0; 267 + } 268 + 269 + static int 270 + genl_get_cmd(u32 cmd, u8 flags, const struct genl_family *family, 271 + struct genl_split_ops *op) 272 + { 273 + struct genl_ops full; 274 + int err; 275 + 276 + err = genl_get_cmd_full(cmd, family, &full); 277 + if (err == -ENOENT) 278 + err = genl_get_cmd_small(cmd, family, &full); 279 + /* Found one of legacy forms */ 280 + if (err == 0) 281 + return genl_cmd_full_to_split(op, family, &full, flags); 282 + 283 + err = genl_get_cmd_split(cmd, flags, family, op); 284 + if (err) 285 + memset(op, 0, sizeof(*op)); 286 + return err; 287 + } 288 + 289 + static bool 290 + genl_op_iter_init(const struct genl_family *family, struct genl_op_iter *iter) 291 + { 292 + iter->family = family; 293 + iter->cmd_idx = 0; 294 + iter->entry_idx = 0; 295 + 296 + iter->flags = 0; 297 + 298 + return iter->family->n_ops + 299 + iter->family->n_small_ops + 300 + iter->family->n_split_ops; 301 + } 302 + 303 + static bool genl_op_iter_next(struct genl_op_iter *iter) 304 + { 305 + const struct genl_family *family = iter->family; 306 + bool legacy_op = true; 307 + struct genl_ops op; 308 + 309 + if (iter->entry_idx < family->n_ops) { 310 + genl_op_from_full(family, iter->entry_idx, &op); 311 + } else if (iter->entry_idx < family->n_ops + family->n_small_ops) { 312 + genl_op_from_small(family, iter->entry_idx - family->n_ops, 313 + &op); 314 + } else if (iter->entry_idx < 315 + family->n_ops + family->n_small_ops + family->n_split_ops) { 316 + legacy_op = false; 317 + /* updates entry_idx */ 318 + genl_op_from_split(iter); 319 + } else { 320 + return false; 321 + } 322 + 323 + iter->cmd_idx++; 324 + 325 + if (legacy_op) { 326 + iter->entry_idx++; 327 + 328 + genl_cmd_full_to_split(&iter->doit, family, 329 + &op, GENL_CMD_CAP_DO); 330 + genl_cmd_full_to_split(&iter->dumpit, family, 331 + &op, GENL_CMD_CAP_DUMP); 332 + } 333 + 334 + iter->cmd = iter->doit.cmd | iter->dumpit.cmd; 335 + iter->flags = iter->doit.flags | iter->dumpit.flags; 336 + 337 + return true; 338 + } 339 + 340 + static void 341 + genl_op_iter_copy(struct genl_op_iter *dst, struct genl_op_iter *src) 342 + { 343 + *dst = *src; 344 + } 345 + 346 + static unsigned int genl_op_iter_idx(struct genl_op_iter *iter) 347 + { 348 + return iter->cmd_idx; 218 349 } 219 350 220 351 static int genl_allocate_reserve_groups(int n_groups, int *first_id) ··· 529 366 } 530 367 } 531 368 369 + static bool genl_split_op_check(const struct genl_split_ops *op) 370 + { 371 + if (WARN_ON(hweight8(op->flags & (GENL_CMD_CAP_DO | 372 + GENL_CMD_CAP_DUMP)) != 1)) 373 + return true; 374 + return false; 375 + } 376 + 532 377 static int genl_validate_ops(const struct genl_family *family) 533 378 { 534 - int i, j; 379 + struct genl_op_iter i, j; 380 + unsigned int s; 535 381 536 382 if (WARN_ON(family->n_ops && !family->ops) || 537 - WARN_ON(family->n_small_ops && !family->small_ops)) 383 + WARN_ON(family->n_small_ops && !family->small_ops) || 384 + WARN_ON(family->n_split_ops && !family->split_ops)) 538 385 return -EINVAL; 539 386 540 - for (i = 0; i < genl_get_cmd_cnt(family); i++) { 541 - struct genl_ops op; 542 - 543 - genl_get_cmd_by_index(i, family, &op); 544 - if (op.dumpit == NULL && op.doit == NULL) 387 + for (genl_op_iter_init(family, &i); genl_op_iter_next(&i); ) { 388 + if (!(i.flags & (GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP))) 545 389 return -EINVAL; 546 - if (WARN_ON(op.cmd >= family->resv_start_op && op.validate)) 547 - return -EINVAL; 548 - for (j = i + 1; j < genl_get_cmd_cnt(family); j++) { 549 - struct genl_ops op2; 550 390 551 - genl_get_cmd_by_index(j, family, &op2); 552 - if (op.cmd == op2.cmd) 391 + if (WARN_ON(i.cmd >= family->resv_start_op && 392 + (i.doit.validate || i.dumpit.validate))) 393 + return -EINVAL; 394 + 395 + genl_op_iter_copy(&j, &i); 396 + while (genl_op_iter_next(&j)) { 397 + if (i.cmd == j.cmd) 553 398 return -EINVAL; 554 399 } 400 + } 401 + 402 + if (family->n_split_ops) { 403 + if (genl_split_op_check(&family->split_ops[0])) 404 + return -EINVAL; 405 + } 406 + 407 + for (s = 1; s < family->n_split_ops; s++) { 408 + const struct genl_split_ops *a, *b; 409 + 410 + a = &family->split_ops[s - 1]; 411 + b = &family->split_ops[s]; 412 + 413 + if (genl_split_op_check(b)) 414 + return -EINVAL; 415 + 416 + /* Check sort order */ 417 + if (a->cmd < b->cmd) 418 + continue; 419 + 420 + if (a->internal_flags != b->internal_flags || 421 + ((a->flags ^ b->flags) & ~(GENL_CMD_CAP_DO | 422 + GENL_CMD_CAP_DUMP))) { 423 + WARN_ON(1); 424 + return -EINVAL; 425 + } 426 + 427 + if ((a->flags & GENL_CMD_CAP_DO) && 428 + (b->flags & GENL_CMD_CAP_DUMP)) 429 + continue; 430 + 431 + WARN_ON(1); 432 + return -EINVAL; 555 433 } 556 434 557 435 return 0; ··· 748 544 genl_family_rcv_msg_attrs_parse(const struct genl_family *family, 749 545 struct nlmsghdr *nlh, 750 546 struct netlink_ext_ack *extack, 751 - const struct genl_ops *ops, 547 + const struct genl_split_ops *ops, 752 548 int hdrlen, 753 549 enum genl_validate_flags no_strict_flag) 754 550 { ··· 784 580 const struct genl_family *family; 785 581 struct nlmsghdr *nlh; 786 582 struct netlink_ext_ack *extack; 787 - const struct genl_ops *ops; 583 + const struct genl_split_ops *ops; 788 584 int hdrlen; 789 585 }; 790 586 791 587 static int genl_start(struct netlink_callback *cb) 792 588 { 793 589 struct genl_start_context *ctx = cb->data; 794 - const struct genl_ops *ops = ctx->ops; 590 + const struct genl_split_ops *ops; 795 591 struct genl_dumpit_info *info; 796 592 struct nlattr **attrs = NULL; 797 593 int rc = 0; 798 594 799 - if (ops->validate & GENL_DONT_VALIDATE_DUMP) 800 - goto no_attrs; 801 - 802 - if (ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen)) 595 + ops = ctx->ops; 596 + if (!(ops->validate & GENL_DONT_VALIDATE_DUMP) && 597 + ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen)) 803 598 return -EINVAL; 804 599 805 600 attrs = genl_family_rcv_msg_attrs_parse(ctx->family, ctx->nlh, ctx->extack, ··· 807 604 if (IS_ERR(attrs)) 808 605 return PTR_ERR(attrs); 809 606 810 - no_attrs: 811 607 info = genl_dumpit_info_alloc(); 812 608 if (!info) { 813 609 genl_family_rcv_msg_attrs_free(attrs); ··· 835 633 836 634 static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 837 635 { 838 - const struct genl_ops *ops = &genl_dumpit_info(cb)->op; 636 + const struct genl_split_ops *ops = &genl_dumpit_info(cb)->op; 839 637 int rc; 840 638 841 639 genl_lock(); ··· 847 645 static int genl_lock_done(struct netlink_callback *cb) 848 646 { 849 647 const struct genl_dumpit_info *info = genl_dumpit_info(cb); 850 - const struct genl_ops *ops = &info->op; 648 + const struct genl_split_ops *ops = &info->op; 851 649 int rc = 0; 852 650 853 651 if (ops->done) { ··· 863 661 static int genl_parallel_done(struct netlink_callback *cb) 864 662 { 865 663 const struct genl_dumpit_info *info = genl_dumpit_info(cb); 866 - const struct genl_ops *ops = &info->op; 664 + const struct genl_split_ops *ops = &info->op; 867 665 int rc = 0; 868 666 869 667 if (ops->done) ··· 877 675 struct sk_buff *skb, 878 676 struct nlmsghdr *nlh, 879 677 struct netlink_ext_ack *extack, 880 - const struct genl_ops *ops, 678 + const struct genl_split_ops *ops, 881 679 int hdrlen, struct net *net) 882 680 { 883 681 struct genl_start_context ctx; 884 682 int err; 885 - 886 - if (!ops->dumpit) 887 - return -EOPNOTSUPP; 888 683 889 684 ctx.family = family; 890 685 ctx.nlh = nlh; ··· 920 721 struct sk_buff *skb, 921 722 struct nlmsghdr *nlh, 922 723 struct netlink_ext_ack *extack, 923 - const struct genl_ops *ops, 724 + const struct genl_split_ops *ops, 924 725 int hdrlen, struct net *net) 925 726 { 926 727 struct nlattr **attrbuf; 927 728 struct genl_info info; 928 729 int err; 929 - 930 - if (!ops->doit) 931 - return -EOPNOTSUPP; 932 730 933 731 attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack, 934 732 ops, hdrlen, ··· 943 747 genl_info_net_set(&info, net); 944 748 memset(&info.user_ptr, 0, sizeof(info.user_ptr)); 945 749 946 - if (family->pre_doit) { 947 - err = family->pre_doit(ops, skb, &info); 750 + if (ops->pre_doit) { 751 + err = ops->pre_doit(ops, skb, &info); 948 752 if (err) 949 753 goto out; 950 754 } 951 755 952 756 err = ops->doit(skb, &info); 953 757 954 - if (family->post_doit) 955 - family->post_doit(ops, skb, &info); 758 + if (ops->post_doit) 759 + ops->post_doit(ops, skb, &info); 956 760 957 761 out: 958 762 genl_family_rcv_msg_attrs_free(attrbuf); ··· 997 801 { 998 802 struct net *net = sock_net(skb->sk); 999 803 struct genlmsghdr *hdr = nlmsg_data(nlh); 1000 - struct genl_ops op; 804 + struct genl_split_ops op; 1001 805 int hdrlen; 806 + u8 flags; 1002 807 1003 808 /* this family doesn't exist in this netns */ 1004 809 if (!family->netnsok && !net_eq(net, &init_net)) ··· 1012 815 if (genl_header_check(family, nlh, hdr, extack)) 1013 816 return -EINVAL; 1014 817 1015 - if (genl_get_cmd(hdr->cmd, family, &op)) 818 + flags = (nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP ? 819 + GENL_CMD_CAP_DUMP : GENL_CMD_CAP_DO; 820 + if (genl_get_cmd(hdr->cmd, flags, family, &op)) 1016 821 return -EOPNOTSUPP; 1017 822 1018 823 if ((op.flags & GENL_ADMIN_PERM) && ··· 1025 826 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) 1026 827 return -EPERM; 1027 828 1028 - if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) 829 + if (flags & GENL_CMD_CAP_DUMP) 1029 830 return genl_family_rcv_msg_dumpit(family, skb, nlh, extack, 1030 831 &op, hdrlen, net); 1031 832 else ··· 1070 871 static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq, 1071 872 u32 flags, struct sk_buff *skb, u8 cmd) 1072 873 { 874 + struct genl_op_iter i; 1073 875 void *hdr; 1074 876 1075 877 hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd); ··· 1084 884 nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) 1085 885 goto nla_put_failure; 1086 886 1087 - if (genl_get_cmd_cnt(family)) { 887 + if (genl_op_iter_init(family, &i)) { 1088 888 struct nlattr *nla_ops; 1089 - int i; 1090 889 1091 890 nla_ops = nla_nest_start_noflag(skb, CTRL_ATTR_OPS); 1092 891 if (nla_ops == NULL) 1093 892 goto nla_put_failure; 1094 893 1095 - for (i = 0; i < genl_get_cmd_cnt(family); i++) { 894 + while (genl_op_iter_next(&i)) { 1096 895 struct nlattr *nest; 1097 - struct genl_ops op; 1098 896 u32 op_flags; 1099 897 1100 - genl_get_cmd_by_index(i, family, &op); 1101 - op_flags = op.flags; 1102 - if (op.dumpit) 1103 - op_flags |= GENL_CMD_CAP_DUMP; 1104 - if (op.doit) 1105 - op_flags |= GENL_CMD_CAP_DO; 1106 - if (op.policy) 898 + op_flags = i.flags; 899 + if (i.doit.policy || i.dumpit.policy) 1107 900 op_flags |= GENL_CMD_CAP_HASPOL; 1108 901 1109 - nest = nla_nest_start_noflag(skb, i + 1); 902 + nest = nla_nest_start_noflag(skb, genl_op_iter_idx(&i)); 1110 903 if (nest == NULL) 1111 904 goto nla_put_failure; 1112 905 1113 - if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) || 906 + if (nla_put_u32(skb, CTRL_ATTR_OP_ID, i.cmd) || 1114 907 nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags)) 1115 908 goto nla_put_failure; 1116 909 ··· 1356 1163 struct ctrl_dump_policy_ctx { 1357 1164 struct netlink_policy_dump_state *state; 1358 1165 const struct genl_family *rt; 1359 - unsigned int opidx; 1166 + struct genl_op_iter *op_iter; 1360 1167 u32 op; 1361 1168 u16 fam_id; 1362 - u8 policies:1, 1169 + u8 dump_map:1, 1363 1170 single_op:1; 1364 1171 }; 1365 1172 ··· 1376 1183 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx; 1377 1184 struct nlattr **tb = info->attrs; 1378 1185 const struct genl_family *rt; 1379 - struct genl_ops op; 1380 - int err, i; 1186 + struct genl_op_iter i; 1187 + int err; 1381 1188 1382 1189 BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); 1383 1190 ··· 1401 1208 ctx->rt = rt; 1402 1209 1403 1210 if (tb[CTRL_ATTR_OP]) { 1211 + struct genl_split_ops doit, dump; 1212 + 1404 1213 ctx->single_op = true; 1405 1214 ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]); 1406 1215 1407 - err = genl_get_cmd(ctx->op, rt, &op); 1408 - if (err) { 1216 + if (genl_get_cmd(ctx->op, GENL_CMD_CAP_DO, rt, &doit) && 1217 + genl_get_cmd(ctx->op, GENL_CMD_CAP_DUMP, rt, &dump)) { 1409 1218 NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]); 1410 - return err; 1219 + return -ENOENT; 1411 1220 } 1412 1221 1413 - if (!op.policy) 1222 + if (doit.policy) { 1223 + err = netlink_policy_dump_add_policy(&ctx->state, 1224 + doit.policy, 1225 + doit.maxattr); 1226 + if (err) 1227 + goto err_free_state; 1228 + } 1229 + if (dump.policy) { 1230 + err = netlink_policy_dump_add_policy(&ctx->state, 1231 + dump.policy, 1232 + dump.maxattr); 1233 + if (err) 1234 + goto err_free_state; 1235 + } 1236 + 1237 + if (!ctx->state) 1414 1238 return -ENODATA; 1415 1239 1416 - return netlink_policy_dump_add_policy(&ctx->state, op.policy, 1417 - op.maxattr); 1240 + ctx->dump_map = 1; 1241 + return 0; 1418 1242 } 1419 1243 1420 - for (i = 0; i < genl_get_cmd_cnt(rt); i++) { 1421 - genl_get_cmd_by_index(i, rt, &op); 1244 + ctx->op_iter = kmalloc(sizeof(*ctx->op_iter), GFP_KERNEL); 1245 + if (!ctx->op_iter) 1246 + return -ENOMEM; 1247 + ctx->dump_map = genl_op_iter_init(rt, ctx->op_iter); 1422 1248 1423 - if (op.policy) { 1249 + for (genl_op_iter_init(rt, &i); genl_op_iter_next(&i); ) { 1250 + if (i.doit.policy) { 1424 1251 err = netlink_policy_dump_add_policy(&ctx->state, 1425 - op.policy, 1426 - op.maxattr); 1252 + i.doit.policy, 1253 + i.doit.maxattr); 1254 + if (err) 1255 + goto err_free_state; 1256 + } 1257 + if (i.dumpit.policy) { 1258 + err = netlink_policy_dump_add_policy(&ctx->state, 1259 + i.dumpit.policy, 1260 + i.dumpit.maxattr); 1427 1261 if (err) 1428 1262 goto err_free_state; 1429 1263 } 1430 1264 } 1431 1265 1432 - if (!ctx->state) 1433 - return -ENODATA; 1266 + if (!ctx->state) { 1267 + err = -ENODATA; 1268 + goto err_free_op_iter; 1269 + } 1434 1270 return 0; 1435 1271 1436 1272 err_free_state: 1437 1273 netlink_policy_dump_free(ctx->state); 1274 + err_free_op_iter: 1275 + kfree(ctx->op_iter); 1438 1276 return err; 1439 1277 } 1440 1278 ··· 1489 1265 1490 1266 static int ctrl_dumppolicy_put_op(struct sk_buff *skb, 1491 1267 struct netlink_callback *cb, 1492 - struct genl_ops *op) 1268 + struct genl_split_ops *doit, 1269 + struct genl_split_ops *dumpit) 1493 1270 { 1494 1271 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx; 1495 1272 struct nlattr *nest_pol, *nest_op; ··· 1498 1273 int idx; 1499 1274 1500 1275 /* skip if we have nothing to show */ 1501 - if (!op->policy) 1502 - return 0; 1503 - if (!op->doit && 1504 - (!op->dumpit || op->validate & GENL_DONT_VALIDATE_DUMP)) 1276 + if (!doit->policy && !dumpit->policy) 1505 1277 return 0; 1506 1278 1507 1279 hdr = ctrl_dumppolicy_prep(skb, cb); ··· 1509 1287 if (!nest_pol) 1510 1288 goto err; 1511 1289 1512 - nest_op = nla_nest_start(skb, op->cmd); 1290 + nest_op = nla_nest_start(skb, doit->cmd); 1513 1291 if (!nest_op) 1514 1292 goto err; 1515 1293 1516 - /* for now both do/dump are always the same */ 1517 - idx = netlink_policy_dump_get_policy_idx(ctx->state, 1518 - op->policy, 1519 - op->maxattr); 1294 + if (doit->policy) { 1295 + idx = netlink_policy_dump_get_policy_idx(ctx->state, 1296 + doit->policy, 1297 + doit->maxattr); 1520 1298 1521 - if (op->doit && nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx)) 1522 - goto err; 1299 + if (nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx)) 1300 + goto err; 1301 + } 1302 + if (dumpit->policy) { 1303 + idx = netlink_policy_dump_get_policy_idx(ctx->state, 1304 + dumpit->policy, 1305 + dumpit->maxattr); 1523 1306 1524 - if (op->dumpit && !(op->validate & GENL_DONT_VALIDATE_DUMP) && 1525 - nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx)) 1526 - goto err; 1307 + if (nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx)) 1308 + goto err; 1309 + } 1527 1310 1528 1311 nla_nest_end(skb, nest_op); 1529 1312 nla_nest_end(skb, nest_pol); ··· 1545 1318 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx; 1546 1319 void *hdr; 1547 1320 1548 - if (!ctx->policies) { 1549 - while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) { 1550 - struct genl_ops op; 1321 + if (ctx->dump_map) { 1322 + if (ctx->single_op) { 1323 + struct genl_split_ops doit, dumpit; 1551 1324 1552 - if (ctx->single_op) { 1553 - int err; 1554 - 1555 - err = genl_get_cmd(ctx->op, ctx->rt, &op); 1556 - if (WARN_ON(err)) 1557 - return skb->len; 1558 - 1559 - /* break out of the loop after this one */ 1560 - ctx->opidx = genl_get_cmd_cnt(ctx->rt); 1561 - } else { 1562 - genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op); 1325 + if (genl_get_cmd(ctx->op, GENL_CMD_CAP_DO, 1326 + ctx->rt, &doit) && 1327 + genl_get_cmd(ctx->op, GENL_CMD_CAP_DUMP, 1328 + ctx->rt, &dumpit)) { 1329 + WARN_ON(1); 1330 + return -ENOENT; 1563 1331 } 1564 1332 1565 - if (ctrl_dumppolicy_put_op(skb, cb, &op)) 1333 + if (ctrl_dumppolicy_put_op(skb, cb, &doit, &dumpit)) 1566 1334 return skb->len; 1567 1335 1568 - ctx->opidx++; 1336 + /* done with the per-op policy index list */ 1337 + ctx->dump_map = 0; 1569 1338 } 1570 1339 1571 - /* completed with the per-op policy index list */ 1572 - ctx->policies = true; 1340 + while (ctx->dump_map) { 1341 + if (ctrl_dumppolicy_put_op(skb, cb, 1342 + &ctx->op_iter->doit, 1343 + &ctx->op_iter->dumpit)) 1344 + return skb->len; 1345 + 1346 + ctx->dump_map = genl_op_iter_next(ctx->op_iter); 1347 + } 1573 1348 } 1574 1349 1575 1350 while (netlink_policy_dump_loop(ctx->state)) { ··· 1604 1375 { 1605 1376 struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx; 1606 1377 1378 + kfree(ctx->op_iter); 1607 1379 netlink_policy_dump_free(ctx->state); 1608 1380 return 0; 1609 1381 } 1610 1382 1611 - static const struct genl_ops genl_ctrl_ops[] = { 1383 + static const struct genl_split_ops genl_ctrl_ops[] = { 1612 1384 { 1613 1385 .cmd = CTRL_CMD_GETFAMILY, 1614 - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 1386 + .validate = GENL_DONT_VALIDATE_STRICT, 1615 1387 .policy = ctrl_policy_family, 1616 1388 .maxattr = ARRAY_SIZE(ctrl_policy_family) - 1, 1617 1389 .doit = ctrl_getfamily, 1390 + .flags = GENL_CMD_CAP_DO, 1391 + }, 1392 + { 1393 + .cmd = CTRL_CMD_GETFAMILY, 1394 + .validate = GENL_DONT_VALIDATE_DUMP, 1395 + .policy = ctrl_policy_family, 1396 + .maxattr = ARRAY_SIZE(ctrl_policy_family) - 1, 1618 1397 .dumpit = ctrl_dumpfamily, 1398 + .flags = GENL_CMD_CAP_DUMP, 1619 1399 }, 1620 1400 { 1621 1401 .cmd = CTRL_CMD_GETPOLICY, ··· 1633 1395 .start = ctrl_dumppolicy_start, 1634 1396 .dumpit = ctrl_dumppolicy, 1635 1397 .done = ctrl_dumppolicy_done, 1398 + .flags = GENL_CMD_CAP_DUMP, 1636 1399 }, 1637 1400 }; 1638 1401 ··· 1643 1404 1644 1405 static struct genl_family genl_ctrl __ro_after_init = { 1645 1406 .module = THIS_MODULE, 1646 - .ops = genl_ctrl_ops, 1647 - .n_ops = ARRAY_SIZE(genl_ctrl_ops), 1407 + .split_ops = genl_ctrl_ops, 1408 + .n_split_ops = ARRAY_SIZE(genl_ctrl_ops), 1648 1409 .resv_start_op = CTRL_CMD_GETPOLICY + 1, 1649 1410 .mcgrps = genl_ctrl_groups, 1650 1411 .n_mcgrps = ARRAY_SIZE(genl_ctrl_groups),
+4 -2
net/wireless/nl80211.c
··· 16140 16140 #undef SELECTOR 16141 16141 }; 16142 16142 16143 - static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 16143 + static int nl80211_pre_doit(const struct genl_split_ops *ops, 16144 + struct sk_buff *skb, 16144 16145 struct genl_info *info) 16145 16146 { 16146 16147 struct cfg80211_registered_device *rdev = NULL; ··· 16242 16241 return err; 16243 16242 } 16244 16243 16245 - static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 16244 + static void nl80211_post_doit(const struct genl_split_ops *ops, 16245 + struct sk_buff *skb, 16246 16246 struct genl_info *info) 16247 16247 { 16248 16248 u32 internal_flags = nl80211_internal_flags[ops->internal_flags];