hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/netlink/genetlink.c
....@@ -107,16 +107,83 @@
107107 return NULL;
108108 }
109109
110
-static const struct genl_ops *genl_get_cmd(u8 cmd,
111
- const struct genl_family *family)
110
+static int genl_get_cmd_cnt(const struct genl_family *family)
111
+{
112
+ return family->n_ops + family->n_small_ops;
113
+}
114
+
115
+static void genl_op_from_full(const struct genl_family *family,
116
+ unsigned int i, struct genl_ops *op)
117
+{
118
+ *op = family->ops[i];
119
+
120
+ if (!op->maxattr)
121
+ op->maxattr = family->maxattr;
122
+ if (!op->policy)
123
+ op->policy = family->policy;
124
+}
125
+
126
+static int genl_get_cmd_full(u32 cmd, const struct genl_family *family,
127
+ struct genl_ops *op)
112128 {
113129 int i;
114130
115131 for (i = 0; i < family->n_ops; i++)
116
- if (family->ops[i].cmd == cmd)
117
- return &family->ops[i];
132
+ if (family->ops[i].cmd == cmd) {
133
+ genl_op_from_full(family, i, op);
134
+ return 0;
135
+ }
118136
119
- return NULL;
137
+ return -ENOENT;
138
+}
139
+
140
+static void genl_op_from_small(const struct genl_family *family,
141
+ unsigned int i, struct genl_ops *op)
142
+{
143
+ memset(op, 0, sizeof(*op));
144
+ op->doit = family->small_ops[i].doit;
145
+ op->dumpit = family->small_ops[i].dumpit;
146
+ op->cmd = family->small_ops[i].cmd;
147
+ op->internal_flags = family->small_ops[i].internal_flags;
148
+ op->flags = family->small_ops[i].flags;
149
+ op->validate = family->small_ops[i].validate;
150
+
151
+ op->maxattr = family->maxattr;
152
+ op->policy = family->policy;
153
+}
154
+
155
+static int genl_get_cmd_small(u32 cmd, const struct genl_family *family,
156
+ struct genl_ops *op)
157
+{
158
+ int i;
159
+
160
+ for (i = 0; i < family->n_small_ops; i++)
161
+ if (family->small_ops[i].cmd == cmd) {
162
+ genl_op_from_small(family, i, op);
163
+ return 0;
164
+ }
165
+
166
+ return -ENOENT;
167
+}
168
+
169
+static int genl_get_cmd(u32 cmd, const struct genl_family *family,
170
+ struct genl_ops *op)
171
+{
172
+ if (!genl_get_cmd_full(cmd, family, op))
173
+ return 0;
174
+ return genl_get_cmd_small(cmd, family, op);
175
+}
176
+
177
+static void genl_get_cmd_by_index(unsigned int i,
178
+ const struct genl_family *family,
179
+ struct genl_ops *op)
180
+{
181
+ if (i < family->n_ops)
182
+ genl_op_from_full(family, i, op);
183
+ else if (i < family->n_ops + family->n_small_ops)
184
+ genl_op_from_small(family, i - family->n_ops, op);
185
+ else
186
+ WARN_ON_ONCE(1);
120187 }
121188
122189 static int genl_allocate_reserve_groups(int n_groups, int *first_id)
....@@ -222,7 +289,7 @@
222289
223290 family->mcgrp_offset = first_id;
224291
225
- /* if still initializing, can't and don't need to to realloc bitmaps */
292
+ /* if still initializing, can't and don't need to realloc bitmaps */
226293 if (!init_net.genl_sock)
227294 return 0;
228295
....@@ -286,22 +353,25 @@
286353
287354 static int genl_validate_ops(const struct genl_family *family)
288355 {
289
- const struct genl_ops *ops = family->ops;
290
- unsigned int n_ops = family->n_ops;
291356 int i, j;
292357
293
- if (WARN_ON(n_ops && !ops))
358
+ if (WARN_ON(family->n_ops && !family->ops) ||
359
+ WARN_ON(family->n_small_ops && !family->small_ops))
294360 return -EINVAL;
295361
296
- if (!n_ops)
297
- return 0;
362
+ for (i = 0; i < genl_get_cmd_cnt(family); i++) {
363
+ struct genl_ops op;
298364
299
- for (i = 0; i < n_ops; i++) {
300
- if (ops[i].dumpit == NULL && ops[i].doit == NULL)
365
+ genl_get_cmd_by_index(i, family, &op);
366
+ if (op.dumpit == NULL && op.doit == NULL)
301367 return -EINVAL;
302
- for (j = i + 1; j < n_ops; j++)
303
- if (ops[i].cmd == ops[j].cmd)
368
+ for (j = i + 1; j < genl_get_cmd_cnt(family); j++) {
369
+ struct genl_ops op2;
370
+
371
+ genl_get_cmd_by_index(j, family, &op2);
372
+ if (op.cmd == op2.cmd)
304373 return -EINVAL;
374
+ }
305375 }
306376
307377 return 0;
....@@ -351,22 +421,11 @@
351421 start = end = GENL_ID_VFS_DQUOT;
352422 }
353423
354
- if (family->maxattr && !family->parallel_ops) {
355
- family->attrbuf = kmalloc_array(family->maxattr + 1,
356
- sizeof(struct nlattr *),
357
- GFP_KERNEL);
358
- if (family->attrbuf == NULL) {
359
- err = -ENOMEM;
360
- goto errout_locked;
361
- }
362
- } else
363
- family->attrbuf = NULL;
364
-
365
- family->id = idr_alloc(&genl_fam_idr, family,
366
- start, end + 1, GFP_KERNEL);
424
+ family->id = idr_alloc_cyclic(&genl_fam_idr, family,
425
+ start, end + 1, GFP_KERNEL);
367426 if (family->id < 0) {
368427 err = family->id;
369
- goto errout_free;
428
+ goto errout_locked;
370429 }
371430
372431 err = genl_validate_assign_mc_groups(family);
....@@ -385,8 +444,6 @@
385444
386445 errout_remove:
387446 idr_remove(&genl_fam_idr, family->id);
388
-errout_free:
389
- kfree(family->attrbuf);
390447 errout_locked:
391448 genl_unlock_all();
392449 return err;
....@@ -418,8 +475,6 @@
418475 wait_event(genl_sk_destructing_waitq,
419476 atomic_read(&genl_sk_destructing_cnt) == 0);
420477 genl_unlock();
421
-
422
- kfree(family->attrbuf);
423478
424479 genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
425480
....@@ -458,24 +513,110 @@
458513 }
459514 EXPORT_SYMBOL(genlmsg_put);
460515
461
-static int genl_lock_start(struct netlink_callback *cb)
516
+static struct genl_dumpit_info *genl_dumpit_info_alloc(void)
462517 {
463
- /* our ops are always const - netlink API doesn't propagate that */
464
- const struct genl_ops *ops = cb->data;
518
+ return kmalloc(sizeof(struct genl_dumpit_info), GFP_KERNEL);
519
+}
520
+
521
+static void genl_dumpit_info_free(const struct genl_dumpit_info *info)
522
+{
523
+ kfree(info);
524
+}
525
+
526
+static struct nlattr **
527
+genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
528
+ struct nlmsghdr *nlh,
529
+ struct netlink_ext_ack *extack,
530
+ const struct genl_ops *ops,
531
+ int hdrlen,
532
+ enum genl_validate_flags no_strict_flag)
533
+{
534
+ enum netlink_validation validate = ops->validate & no_strict_flag ?
535
+ NL_VALIDATE_LIBERAL :
536
+ NL_VALIDATE_STRICT;
537
+ struct nlattr **attrbuf;
538
+ int err;
539
+
540
+ if (!ops->maxattr)
541
+ return NULL;
542
+
543
+ attrbuf = kmalloc_array(ops->maxattr + 1,
544
+ sizeof(struct nlattr *), GFP_KERNEL);
545
+ if (!attrbuf)
546
+ return ERR_PTR(-ENOMEM);
547
+
548
+ err = __nlmsg_parse(nlh, hdrlen, attrbuf, ops->maxattr, ops->policy,
549
+ validate, extack);
550
+ if (err) {
551
+ kfree(attrbuf);
552
+ return ERR_PTR(err);
553
+ }
554
+ return attrbuf;
555
+}
556
+
557
+static void genl_family_rcv_msg_attrs_free(struct nlattr **attrbuf)
558
+{
559
+ kfree(attrbuf);
560
+}
561
+
562
+struct genl_start_context {
563
+ const struct genl_family *family;
564
+ struct nlmsghdr *nlh;
565
+ struct netlink_ext_ack *extack;
566
+ const struct genl_ops *ops;
567
+ int hdrlen;
568
+};
569
+
570
+static int genl_start(struct netlink_callback *cb)
571
+{
572
+ struct genl_start_context *ctx = cb->data;
573
+ const struct genl_ops *ops = ctx->ops;
574
+ struct genl_dumpit_info *info;
575
+ struct nlattr **attrs = NULL;
465576 int rc = 0;
466577
578
+ if (ops->validate & GENL_DONT_VALIDATE_DUMP)
579
+ goto no_attrs;
580
+
581
+ if (ctx->nlh->nlmsg_len < nlmsg_msg_size(ctx->hdrlen))
582
+ return -EINVAL;
583
+
584
+ attrs = genl_family_rcv_msg_attrs_parse(ctx->family, ctx->nlh, ctx->extack,
585
+ ops, ctx->hdrlen,
586
+ GENL_DONT_VALIDATE_DUMP_STRICT);
587
+ if (IS_ERR(attrs))
588
+ return PTR_ERR(attrs);
589
+
590
+no_attrs:
591
+ info = genl_dumpit_info_alloc();
592
+ if (!info) {
593
+ genl_family_rcv_msg_attrs_free(attrs);
594
+ return -ENOMEM;
595
+ }
596
+ info->family = ctx->family;
597
+ info->op = *ops;
598
+ info->attrs = attrs;
599
+
600
+ cb->data = info;
467601 if (ops->start) {
468
- genl_lock();
602
+ if (!ctx->family->parallel_ops)
603
+ genl_lock();
469604 rc = ops->start(cb);
470
- genl_unlock();
605
+ if (!ctx->family->parallel_ops)
606
+ genl_unlock();
607
+ }
608
+
609
+ if (rc) {
610
+ genl_family_rcv_msg_attrs_free(info->attrs);
611
+ genl_dumpit_info_free(info);
612
+ cb->data = NULL;
471613 }
472614 return rc;
473615 }
474616
475617 static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
476618 {
477
- /* our ops are always const - netlink API doesn't propagate that */
478
- const struct genl_ops *ops = cb->data;
619
+ const struct genl_ops *ops = &genl_dumpit_info(cb)->op;
479620 int rc;
480621
481622 genl_lock();
....@@ -486,8 +627,8 @@
486627
487628 static int genl_lock_done(struct netlink_callback *cb)
488629 {
489
- /* our ops are always const - netlink API doesn't propagate that */
490
- const struct genl_ops *ops = cb->data;
630
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
631
+ const struct genl_ops *ops = &info->op;
491632 int rc = 0;
492633
493634 if (ops->done) {
....@@ -495,93 +636,89 @@
495636 rc = ops->done(cb);
496637 genl_unlock();
497638 }
639
+ genl_family_rcv_msg_attrs_free(info->attrs);
640
+ genl_dumpit_info_free(info);
498641 return rc;
499642 }
500643
501
-static int genl_family_rcv_msg(const struct genl_family *family,
502
- struct sk_buff *skb,
503
- struct nlmsghdr *nlh,
504
- struct netlink_ext_ack *extack)
644
+static int genl_parallel_done(struct netlink_callback *cb)
505645 {
506
- const struct genl_ops *ops;
507
- struct net *net = sock_net(skb->sk);
508
- struct genl_info info;
509
- struct genlmsghdr *hdr = nlmsg_data(nlh);
646
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
647
+ const struct genl_ops *ops = &info->op;
648
+ int rc = 0;
649
+
650
+ if (ops->done)
651
+ rc = ops->done(cb);
652
+ genl_family_rcv_msg_attrs_free(info->attrs);
653
+ genl_dumpit_info_free(info);
654
+ return rc;
655
+}
656
+
657
+static int genl_family_rcv_msg_dumpit(const struct genl_family *family,
658
+ struct sk_buff *skb,
659
+ struct nlmsghdr *nlh,
660
+ struct netlink_ext_ack *extack,
661
+ const struct genl_ops *ops,
662
+ int hdrlen, struct net *net)
663
+{
664
+ struct genl_start_context ctx;
665
+ int err;
666
+
667
+ if (!ops->dumpit)
668
+ return -EOPNOTSUPP;
669
+
670
+ ctx.family = family;
671
+ ctx.nlh = nlh;
672
+ ctx.extack = extack;
673
+ ctx.ops = ops;
674
+ ctx.hdrlen = hdrlen;
675
+
676
+ if (!family->parallel_ops) {
677
+ struct netlink_dump_control c = {
678
+ .module = family->module,
679
+ .data = &ctx,
680
+ .start = genl_start,
681
+ .dump = genl_lock_dumpit,
682
+ .done = genl_lock_done,
683
+ };
684
+
685
+ genl_unlock();
686
+ err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
687
+ genl_lock();
688
+ } else {
689
+ struct netlink_dump_control c = {
690
+ .module = family->module,
691
+ .data = &ctx,
692
+ .start = genl_start,
693
+ .dump = ops->dumpit,
694
+ .done = genl_parallel_done,
695
+ };
696
+
697
+ err = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
698
+ }
699
+
700
+ return err;
701
+}
702
+
703
+static int genl_family_rcv_msg_doit(const struct genl_family *family,
704
+ struct sk_buff *skb,
705
+ struct nlmsghdr *nlh,
706
+ struct netlink_ext_ack *extack,
707
+ const struct genl_ops *ops,
708
+ int hdrlen, struct net *net)
709
+{
510710 struct nlattr **attrbuf;
511
- int hdrlen, err;
711
+ struct genl_info info;
712
+ int err;
512713
513
- /* this family doesn't exist in this netns */
514
- if (!family->netnsok && !net_eq(net, &init_net))
515
- return -ENOENT;
516
-
517
- hdrlen = GENL_HDRLEN + family->hdrsize;
518
- if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
519
- return -EINVAL;
520
-
521
- ops = genl_get_cmd(hdr->cmd, family);
522
- if (ops == NULL)
714
+ if (!ops->doit)
523715 return -EOPNOTSUPP;
524716
525
- if ((ops->flags & GENL_ADMIN_PERM) &&
526
- !netlink_capable(skb, CAP_NET_ADMIN))
527
- return -EPERM;
528
-
529
- if ((ops->flags & GENL_UNS_ADMIN_PERM) &&
530
- !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
531
- return -EPERM;
532
-
533
- if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
534
- int rc;
535
-
536
- if (ops->dumpit == NULL)
537
- return -EOPNOTSUPP;
538
-
539
- if (!family->parallel_ops) {
540
- struct netlink_dump_control c = {
541
- .module = family->module,
542
- /* we have const, but the netlink API doesn't */
543
- .data = (void *)ops,
544
- .start = genl_lock_start,
545
- .dump = genl_lock_dumpit,
546
- .done = genl_lock_done,
547
- };
548
-
549
- genl_unlock();
550
- rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
551
- genl_lock();
552
-
553
- } else {
554
- struct netlink_dump_control c = {
555
- .module = family->module,
556
- .start = ops->start,
557
- .dump = ops->dumpit,
558
- .done = ops->done,
559
- };
560
-
561
- rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
562
- }
563
-
564
- return rc;
565
- }
566
-
567
- if (ops->doit == NULL)
568
- return -EOPNOTSUPP;
569
-
570
- if (family->maxattr && family->parallel_ops) {
571
- attrbuf = kmalloc_array(family->maxattr + 1,
572
- sizeof(struct nlattr *),
573
- GFP_KERNEL);
574
- if (attrbuf == NULL)
575
- return -ENOMEM;
576
- } else
577
- attrbuf = family->attrbuf;
578
-
579
- if (attrbuf) {
580
- err = nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
581
- ops->policy, extack);
582
- if (err < 0)
583
- goto out;
584
- }
717
+ attrbuf = genl_family_rcv_msg_attrs_parse(family, nlh, extack,
718
+ ops, hdrlen,
719
+ GENL_DONT_VALIDATE_STRICT);
720
+ if (IS_ERR(attrbuf))
721
+ return PTR_ERR(attrbuf);
585722
586723 info.snd_seq = nlh->nlmsg_seq;
587724 info.snd_portid = NETLINK_CB(skb).portid;
....@@ -605,10 +742,46 @@
605742 family->post_doit(ops, skb, &info);
606743
607744 out:
608
- if (family->parallel_ops)
609
- kfree(attrbuf);
745
+ genl_family_rcv_msg_attrs_free(attrbuf);
610746
611747 return err;
748
+}
749
+
750
+static int genl_family_rcv_msg(const struct genl_family *family,
751
+ struct sk_buff *skb,
752
+ struct nlmsghdr *nlh,
753
+ struct netlink_ext_ack *extack)
754
+{
755
+ struct net *net = sock_net(skb->sk);
756
+ struct genlmsghdr *hdr = nlmsg_data(nlh);
757
+ struct genl_ops op;
758
+ int hdrlen;
759
+
760
+ /* this family doesn't exist in this netns */
761
+ if (!family->netnsok && !net_eq(net, &init_net))
762
+ return -ENOENT;
763
+
764
+ hdrlen = GENL_HDRLEN + family->hdrsize;
765
+ if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
766
+ return -EINVAL;
767
+
768
+ if (genl_get_cmd(hdr->cmd, family, &op))
769
+ return -EOPNOTSUPP;
770
+
771
+ if ((op.flags & GENL_ADMIN_PERM) &&
772
+ !netlink_capable(skb, CAP_NET_ADMIN))
773
+ return -EPERM;
774
+
775
+ if ((op.flags & GENL_UNS_ADMIN_PERM) &&
776
+ !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
777
+ return -EPERM;
778
+
779
+ if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
780
+ return genl_family_rcv_msg_dumpit(family, skb, nlh, extack,
781
+ &op, hdrlen, net);
782
+ else
783
+ return genl_family_rcv_msg_doit(family, skb, nlh, extack,
784
+ &op, hdrlen, net);
612785 }
613786
614787 static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
....@@ -661,31 +834,33 @@
661834 nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
662835 goto nla_put_failure;
663836
664
- if (family->n_ops) {
837
+ if (genl_get_cmd_cnt(family)) {
665838 struct nlattr *nla_ops;
666839 int i;
667840
668
- nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
841
+ nla_ops = nla_nest_start_noflag(skb, CTRL_ATTR_OPS);
669842 if (nla_ops == NULL)
670843 goto nla_put_failure;
671844
672
- for (i = 0; i < family->n_ops; i++) {
845
+ for (i = 0; i < genl_get_cmd_cnt(family); i++) {
673846 struct nlattr *nest;
674
- const struct genl_ops *ops = &family->ops[i];
675
- u32 op_flags = ops->flags;
847
+ struct genl_ops op;
848
+ u32 op_flags;
676849
677
- if (ops->dumpit)
850
+ genl_get_cmd_by_index(i, family, &op);
851
+ op_flags = op.flags;
852
+ if (op.dumpit)
678853 op_flags |= GENL_CMD_CAP_DUMP;
679
- if (ops->doit)
854
+ if (op.doit)
680855 op_flags |= GENL_CMD_CAP_DO;
681
- if (ops->policy)
856
+ if (op.policy)
682857 op_flags |= GENL_CMD_CAP_HASPOL;
683858
684
- nest = nla_nest_start(skb, i + 1);
859
+ nest = nla_nest_start_noflag(skb, i + 1);
685860 if (nest == NULL)
686861 goto nla_put_failure;
687862
688
- if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
863
+ if (nla_put_u32(skb, CTRL_ATTR_OP_ID, op.cmd) ||
689864 nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags))
690865 goto nla_put_failure;
691866
....@@ -699,7 +874,7 @@
699874 struct nlattr *nla_grps;
700875 int i;
701876
702
- nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
877
+ nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
703878 if (nla_grps == NULL)
704879 goto nla_put_failure;
705880
....@@ -709,7 +884,7 @@
709884
710885 grp = &family->mcgrps[i];
711886
712
- nest = nla_nest_start(skb, i + 1);
887
+ nest = nla_nest_start_noflag(skb, i + 1);
713888 if (nest == NULL)
714889 goto nla_put_failure;
715890
....@@ -749,11 +924,11 @@
749924 nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id))
750925 goto nla_put_failure;
751926
752
- nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
927
+ nla_grps = nla_nest_start_noflag(skb, CTRL_ATTR_MCAST_GROUPS);
753928 if (nla_grps == NULL)
754929 goto nla_put_failure;
755930
756
- nest = nla_nest_start(skb, 1);
931
+ nest = nla_nest_start_noflag(skb, 1);
757932 if (nest == NULL)
758933 goto nla_put_failure;
759934
....@@ -841,7 +1016,7 @@
8411016 return skb;
8421017 }
8431018
844
-static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
1019
+static const struct nla_policy ctrl_policy_family[] = {
8451020 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
8461021 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
8471022 .len = GENL_NAMSIZ - 1 },
....@@ -935,12 +1110,241 @@
9351110 return 0;
9361111 }
9371112
1113
+struct ctrl_dump_policy_ctx {
1114
+ struct netlink_policy_dump_state *state;
1115
+ const struct genl_family *rt;
1116
+ unsigned int opidx;
1117
+ u32 op;
1118
+ u16 fam_id;
1119
+ u8 policies:1,
1120
+ single_op:1;
1121
+};
1122
+
1123
+static const struct nla_policy ctrl_policy_policy[] = {
1124
+ [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
1125
+ [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
1126
+ .len = GENL_NAMSIZ - 1 },
1127
+ [CTRL_ATTR_OP] = { .type = NLA_U32 },
1128
+};
1129
+
1130
+static int ctrl_dumppolicy_start(struct netlink_callback *cb)
1131
+{
1132
+ const struct genl_dumpit_info *info = genl_dumpit_info(cb);
1133
+ struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1134
+ struct nlattr **tb = info->attrs;
1135
+ const struct genl_family *rt;
1136
+ struct genl_ops op;
1137
+ int err, i;
1138
+
1139
+ BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx));
1140
+
1141
+ if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
1142
+ return -EINVAL;
1143
+
1144
+ if (tb[CTRL_ATTR_FAMILY_ID]) {
1145
+ ctx->fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
1146
+ } else {
1147
+ rt = genl_family_find_byname(
1148
+ nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
1149
+ if (!rt)
1150
+ return -ENOENT;
1151
+ ctx->fam_id = rt->id;
1152
+ }
1153
+
1154
+ rt = genl_family_find_byid(ctx->fam_id);
1155
+ if (!rt)
1156
+ return -ENOENT;
1157
+
1158
+ ctx->rt = rt;
1159
+
1160
+ if (tb[CTRL_ATTR_OP]) {
1161
+ ctx->single_op = true;
1162
+ ctx->op = nla_get_u32(tb[CTRL_ATTR_OP]);
1163
+
1164
+ err = genl_get_cmd(ctx->op, rt, &op);
1165
+ if (err) {
1166
+ NL_SET_BAD_ATTR(cb->extack, tb[CTRL_ATTR_OP]);
1167
+ return err;
1168
+ }
1169
+
1170
+ if (!op.policy)
1171
+ return -ENODATA;
1172
+
1173
+ return netlink_policy_dump_add_policy(&ctx->state, op.policy,
1174
+ op.maxattr);
1175
+ }
1176
+
1177
+ for (i = 0; i < genl_get_cmd_cnt(rt); i++) {
1178
+ genl_get_cmd_by_index(i, rt, &op);
1179
+
1180
+ if (op.policy) {
1181
+ err = netlink_policy_dump_add_policy(&ctx->state,
1182
+ op.policy,
1183
+ op.maxattr);
1184
+ if (err)
1185
+ goto err_free_state;
1186
+ }
1187
+ }
1188
+
1189
+ if (!ctx->state)
1190
+ return -ENODATA;
1191
+ return 0;
1192
+
1193
+err_free_state:
1194
+ netlink_policy_dump_free(ctx->state);
1195
+ return err;
1196
+}
1197
+
1198
+static void *ctrl_dumppolicy_prep(struct sk_buff *skb,
1199
+ struct netlink_callback *cb)
1200
+{
1201
+ struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1202
+ void *hdr;
1203
+
1204
+ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
1205
+ cb->nlh->nlmsg_seq, &genl_ctrl,
1206
+ NLM_F_MULTI, CTRL_CMD_GETPOLICY);
1207
+ if (!hdr)
1208
+ return NULL;
1209
+
1210
+ if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, ctx->fam_id))
1211
+ return NULL;
1212
+
1213
+ return hdr;
1214
+}
1215
+
1216
+static int ctrl_dumppolicy_put_op(struct sk_buff *skb,
1217
+ struct netlink_callback *cb,
1218
+ struct genl_ops *op)
1219
+{
1220
+ struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1221
+ struct nlattr *nest_pol, *nest_op;
1222
+ void *hdr;
1223
+ int idx;
1224
+
1225
+ /* skip if we have nothing to show */
1226
+ if (!op->policy)
1227
+ return 0;
1228
+ if (!op->doit &&
1229
+ (!op->dumpit || op->validate & GENL_DONT_VALIDATE_DUMP))
1230
+ return 0;
1231
+
1232
+ hdr = ctrl_dumppolicy_prep(skb, cb);
1233
+ if (!hdr)
1234
+ return -ENOBUFS;
1235
+
1236
+ nest_pol = nla_nest_start(skb, CTRL_ATTR_OP_POLICY);
1237
+ if (!nest_pol)
1238
+ goto err;
1239
+
1240
+ nest_op = nla_nest_start(skb, op->cmd);
1241
+ if (!nest_op)
1242
+ goto err;
1243
+
1244
+ /* for now both do/dump are always the same */
1245
+ idx = netlink_policy_dump_get_policy_idx(ctx->state,
1246
+ op->policy,
1247
+ op->maxattr);
1248
+
1249
+ if (op->doit && nla_put_u32(skb, CTRL_ATTR_POLICY_DO, idx))
1250
+ goto err;
1251
+
1252
+ if (op->dumpit && !(op->validate & GENL_DONT_VALIDATE_DUMP) &&
1253
+ nla_put_u32(skb, CTRL_ATTR_POLICY_DUMP, idx))
1254
+ goto err;
1255
+
1256
+ nla_nest_end(skb, nest_op);
1257
+ nla_nest_end(skb, nest_pol);
1258
+ genlmsg_end(skb, hdr);
1259
+
1260
+ return 0;
1261
+err:
1262
+ genlmsg_cancel(skb, hdr);
1263
+ return -ENOBUFS;
1264
+}
1265
+
1266
+static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
1267
+{
1268
+ struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1269
+ void *hdr;
1270
+
1271
+ if (!ctx->policies) {
1272
+ while (ctx->opidx < genl_get_cmd_cnt(ctx->rt)) {
1273
+ struct genl_ops op;
1274
+
1275
+ if (ctx->single_op) {
1276
+ int err;
1277
+
1278
+ err = genl_get_cmd(ctx->op, ctx->rt, &op);
1279
+ if (WARN_ON(err))
1280
+ return skb->len;
1281
+
1282
+ /* break out of the loop after this one */
1283
+ ctx->opidx = genl_get_cmd_cnt(ctx->rt);
1284
+ } else {
1285
+ genl_get_cmd_by_index(ctx->opidx, ctx->rt, &op);
1286
+ }
1287
+
1288
+ if (ctrl_dumppolicy_put_op(skb, cb, &op))
1289
+ return skb->len;
1290
+
1291
+ ctx->opidx++;
1292
+ }
1293
+
1294
+ /* completed with the per-op policy index list */
1295
+ ctx->policies = true;
1296
+ }
1297
+
1298
+ while (netlink_policy_dump_loop(ctx->state)) {
1299
+ struct nlattr *nest;
1300
+
1301
+ hdr = ctrl_dumppolicy_prep(skb, cb);
1302
+ if (!hdr)
1303
+ goto nla_put_failure;
1304
+
1305
+ nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
1306
+ if (!nest)
1307
+ goto nla_put_failure;
1308
+
1309
+ if (netlink_policy_dump_write(skb, ctx->state))
1310
+ goto nla_put_failure;
1311
+
1312
+ nla_nest_end(skb, nest);
1313
+
1314
+ genlmsg_end(skb, hdr);
1315
+ }
1316
+
1317
+ return skb->len;
1318
+
1319
+nla_put_failure:
1320
+ genlmsg_cancel(skb, hdr);
1321
+ return skb->len;
1322
+}
1323
+
1324
+static int ctrl_dumppolicy_done(struct netlink_callback *cb)
1325
+{
1326
+ struct ctrl_dump_policy_ctx *ctx = (void *)cb->ctx;
1327
+
1328
+ netlink_policy_dump_free(ctx->state);
1329
+ return 0;
1330
+}
1331
+
9381332 static const struct genl_ops genl_ctrl_ops[] = {
9391333 {
9401334 .cmd = CTRL_CMD_GETFAMILY,
1335
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
1336
+ .policy = ctrl_policy_family,
1337
+ .maxattr = ARRAY_SIZE(ctrl_policy_family) - 1,
9411338 .doit = ctrl_getfamily,
9421339 .dumpit = ctrl_dumpfamily,
943
- .policy = ctrl_policy,
1340
+ },
1341
+ {
1342
+ .cmd = CTRL_CMD_GETPOLICY,
1343
+ .policy = ctrl_policy_policy,
1344
+ .maxattr = ARRAY_SIZE(ctrl_policy_policy) - 1,
1345
+ .start = ctrl_dumppolicy_start,
1346
+ .dumpit = ctrl_dumppolicy,
1347
+ .done = ctrl_dumppolicy_done,
9441348 },
9451349 };
9461350
....@@ -957,64 +1361,14 @@
9571361 .id = GENL_ID_CTRL,
9581362 .name = "nlctrl",
9591363 .version = 0x2,
960
- .maxattr = CTRL_ATTR_MAX,
9611364 .netnsok = true,
9621365 };
963
-
964
-static int genl_bind(struct net *net, int group)
965
-{
966
- struct genl_family *f;
967
- int err = 0;
968
- unsigned int id;
969
-
970
- down_read(&cb_lock);
971
-
972
- idr_for_each_entry(&genl_fam_idr, f, id) {
973
- if (group >= f->mcgrp_offset &&
974
- group < f->mcgrp_offset + f->n_mcgrps) {
975
- int fam_grp = group - f->mcgrp_offset;
976
-
977
- if (!f->netnsok && net != &init_net)
978
- err = -ENOENT;
979
- else if (f->mcast_bind)
980
- err = f->mcast_bind(net, fam_grp);
981
- else
982
- err = 0;
983
- break;
984
- }
985
- }
986
- up_read(&cb_lock);
987
-
988
- return err;
989
-}
990
-
991
-static void genl_unbind(struct net *net, int group)
992
-{
993
- struct genl_family *f;
994
- unsigned int id;
995
-
996
- down_read(&cb_lock);
997
-
998
- idr_for_each_entry(&genl_fam_idr, f, id) {
999
- if (group >= f->mcgrp_offset &&
1000
- group < f->mcgrp_offset + f->n_mcgrps) {
1001
- int fam_grp = group - f->mcgrp_offset;
1002
-
1003
- if (f->mcast_unbind)
1004
- f->mcast_unbind(net, fam_grp);
1005
- break;
1006
- }
1007
- }
1008
- up_read(&cb_lock);
1009
-}
10101366
10111367 static int __net_init genl_pernet_init(struct net *net)
10121368 {
10131369 struct netlink_kernel_cfg cfg = {
10141370 .input = genl_rcv,
10151371 .flags = NL_CFG_F_NONROOT_RECV,
1016
- .bind = genl_bind,
1017
- .unbind = genl_unbind,
10181372 };
10191373
10201374 /* we'll bump the group number right afterwards */
....@@ -1058,26 +1412,7 @@
10581412 panic("GENL: Cannot register controller: %d\n", err);
10591413 }
10601414
1061
-subsys_initcall(genl_init);
1062
-
1063
-/**
1064
- * genl_family_attrbuf - return family's attrbuf
1065
- * @family: the family
1066
- *
1067
- * Return the family's attrbuf, while validating that it's
1068
- * actually valid to access it.
1069
- *
1070
- * You cannot use this function with a family that has parallel_ops
1071
- * and you can only use it within (pre/post) doit/dumpit callbacks.
1072
- */
1073
-struct nlattr **genl_family_attrbuf(const struct genl_family *family)
1074
-{
1075
- if (!WARN_ON(family->parallel_ops))
1076
- lockdep_assert_held(&genl_mutex);
1077
-
1078
- return family->attrbuf;
1079
-}
1080
-EXPORT_SYMBOL(genl_family_attrbuf);
1415
+core_initcall(genl_init);
10811416
10821417 static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
10831418 gfp_t flags)