0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/types.h>
0018 #include <linux/socket.h>
0019 #include <linux/string.h>
0020 #include <linux/skbuff.h>
0021 #include <linux/audit.h>
0022 #include <linux/slab.h>
0023 #include <net/sock.h>
0024 #include <net/netlink.h>
0025 #include <net/genetlink.h>
0026 #include <net/netlabel.h>
0027 #include <net/calipso.h>
0028 #include <linux/atomic.h>
0029
0030 #include "netlabel_user.h"
0031 #include "netlabel_calipso.h"
0032 #include "netlabel_mgmt.h"
0033 #include "netlabel_domainhash.h"
0034
0035
0036 struct netlbl_calipso_doiwalk_arg {
0037 struct netlink_callback *nl_cb;
0038 struct sk_buff *skb;
0039 u32 seq;
0040 };
0041
0042
0043 struct netlbl_domhsh_walk_arg {
0044 struct netlbl_audit *audit_info;
0045 u32 doi;
0046 };
0047
0048
0049 static struct genl_family netlbl_calipso_gnl_family;
0050
0051
0052 static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
0053 [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },
0054 [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
0055 };
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 static int netlbl_calipso_add_pass(struct genl_info *info,
0071 struct netlbl_audit *audit_info)
0072 {
0073 int ret_val;
0074 struct calipso_doi *doi_def = NULL;
0075
0076 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
0077 if (!doi_def)
0078 return -ENOMEM;
0079 doi_def->type = CALIPSO_MAP_PASS;
0080 doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
0081 ret_val = calipso_doi_add(doi_def, audit_info);
0082 if (ret_val != 0)
0083 calipso_doi_free(doi_def);
0084
0085 return ret_val;
0086 }
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
0099
0100 {
0101 int ret_val = -EINVAL;
0102 struct netlbl_audit audit_info;
0103
0104 if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
0105 !info->attrs[NLBL_CALIPSO_A_MTYPE])
0106 return -EINVAL;
0107
0108 netlbl_netlink_auditinfo(&audit_info);
0109 switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
0110 case CALIPSO_MAP_PASS:
0111 ret_val = netlbl_calipso_add_pass(info, &audit_info);
0112 break;
0113 }
0114 if (ret_val == 0)
0115 atomic_inc(&netlabel_mgmt_protocount);
0116
0117 return ret_val;
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130 static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)
0131 {
0132 int ret_val;
0133 struct sk_buff *ans_skb = NULL;
0134 void *data;
0135 u32 doi;
0136 struct calipso_doi *doi_def;
0137
0138 if (!info->attrs[NLBL_CALIPSO_A_DOI]) {
0139 ret_val = -EINVAL;
0140 goto list_failure;
0141 }
0142
0143 doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
0144
0145 doi_def = calipso_doi_getdef(doi);
0146 if (!doi_def) {
0147 ret_val = -EINVAL;
0148 goto list_failure;
0149 }
0150
0151 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0152 if (!ans_skb) {
0153 ret_val = -ENOMEM;
0154 goto list_failure_put;
0155 }
0156 data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,
0157 0, NLBL_CALIPSO_C_LIST);
0158 if (!data) {
0159 ret_val = -ENOMEM;
0160 goto list_failure_put;
0161 }
0162
0163 ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);
0164 if (ret_val != 0)
0165 goto list_failure_put;
0166
0167 calipso_doi_putdef(doi_def);
0168
0169 genlmsg_end(ans_skb, data);
0170 return genlmsg_reply(ans_skb, info);
0171
0172 list_failure_put:
0173 calipso_doi_putdef(doi_def);
0174 list_failure:
0175 kfree_skb(ans_skb);
0176 return ret_val;
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)
0192 {
0193 int ret_val = -ENOMEM;
0194 struct netlbl_calipso_doiwalk_arg *cb_arg = arg;
0195 void *data;
0196
0197 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
0198 cb_arg->seq, &netlbl_calipso_gnl_family,
0199 NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);
0200 if (!data)
0201 goto listall_cb_failure;
0202
0203 ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);
0204 if (ret_val != 0)
0205 goto listall_cb_failure;
0206 ret_val = nla_put_u32(cb_arg->skb,
0207 NLBL_CALIPSO_A_MTYPE,
0208 doi_def->type);
0209 if (ret_val != 0)
0210 goto listall_cb_failure;
0211
0212 genlmsg_end(cb_arg->skb, data);
0213 return 0;
0214
0215 listall_cb_failure:
0216 genlmsg_cancel(cb_arg->skb, data);
0217 return ret_val;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 static int netlbl_calipso_listall(struct sk_buff *skb,
0231 struct netlink_callback *cb)
0232 {
0233 struct netlbl_calipso_doiwalk_arg cb_arg;
0234 u32 doi_skip = cb->args[0];
0235
0236 cb_arg.nl_cb = cb;
0237 cb_arg.skb = skb;
0238 cb_arg.seq = cb->nlh->nlmsg_seq;
0239
0240 calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);
0241
0242 cb->args[0] = doi_skip;
0243 return skb->len;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)
0259 {
0260 struct netlbl_domhsh_walk_arg *cb_arg = arg;
0261
0262 if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&
0263 entry->def.calipso->doi == cb_arg->doi)
0264 return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
0265
0266 return 0;
0267 }
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279 static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
0280 {
0281 int ret_val = -EINVAL;
0282 struct netlbl_domhsh_walk_arg cb_arg;
0283 struct netlbl_audit audit_info;
0284 u32 skip_bkt = 0;
0285 u32 skip_chain = 0;
0286
0287 if (!info->attrs[NLBL_CALIPSO_A_DOI])
0288 return -EINVAL;
0289
0290 netlbl_netlink_auditinfo(&audit_info);
0291 cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
0292 cb_arg.audit_info = &audit_info;
0293 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
0294 netlbl_calipso_remove_cb, &cb_arg);
0295 if (ret_val == 0 || ret_val == -ENOENT) {
0296 ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);
0297 if (ret_val == 0)
0298 atomic_dec(&netlabel_mgmt_protocount);
0299 }
0300
0301 return ret_val;
0302 }
0303
0304
0305
0306
0307 static const struct genl_small_ops netlbl_calipso_ops[] = {
0308 {
0309 .cmd = NLBL_CALIPSO_C_ADD,
0310 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0311 .flags = GENL_ADMIN_PERM,
0312 .doit = netlbl_calipso_add,
0313 .dumpit = NULL,
0314 },
0315 {
0316 .cmd = NLBL_CALIPSO_C_REMOVE,
0317 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0318 .flags = GENL_ADMIN_PERM,
0319 .doit = netlbl_calipso_remove,
0320 .dumpit = NULL,
0321 },
0322 {
0323 .cmd = NLBL_CALIPSO_C_LIST,
0324 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0325 .flags = 0,
0326 .doit = netlbl_calipso_list,
0327 .dumpit = NULL,
0328 },
0329 {
0330 .cmd = NLBL_CALIPSO_C_LISTALL,
0331 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0332 .flags = 0,
0333 .doit = NULL,
0334 .dumpit = netlbl_calipso_listall,
0335 },
0336 };
0337
0338 static struct genl_family netlbl_calipso_gnl_family __ro_after_init = {
0339 .hdrsize = 0,
0340 .name = NETLBL_NLTYPE_CALIPSO_NAME,
0341 .version = NETLBL_PROTO_VERSION,
0342 .maxattr = NLBL_CALIPSO_A_MAX,
0343 .policy = calipso_genl_policy,
0344 .module = THIS_MODULE,
0345 .small_ops = netlbl_calipso_ops,
0346 .n_small_ops = ARRAY_SIZE(netlbl_calipso_ops),
0347 };
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360 int __init netlbl_calipso_genl_init(void)
0361 {
0362 return genl_register_family(&netlbl_calipso_gnl_family);
0363 }
0364
0365 static const struct netlbl_calipso_ops *calipso_ops;
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375 const struct netlbl_calipso_ops *
0376 netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
0377 {
0378 return xchg(&calipso_ops, ops);
0379 }
0380 EXPORT_SYMBOL(netlbl_calipso_ops_register);
0381
0382 static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
0383 {
0384 return READ_ONCE(calipso_ops);
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 int calipso_doi_add(struct calipso_doi *doi_def,
0401 struct netlbl_audit *audit_info)
0402 {
0403 int ret_val = -ENOMSG;
0404 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0405
0406 if (ops)
0407 ret_val = ops->doi_add(doi_def, audit_info);
0408 return ret_val;
0409 }
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419 void calipso_doi_free(struct calipso_doi *doi_def)
0420 {
0421 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0422
0423 if (ops)
0424 ops->doi_free(doi_def);
0425 }
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438 int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
0439 {
0440 int ret_val = -ENOMSG;
0441 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0442
0443 if (ops)
0444 ret_val = ops->doi_remove(doi, audit_info);
0445 return ret_val;
0446 }
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458 struct calipso_doi *calipso_doi_getdef(u32 doi)
0459 {
0460 struct calipso_doi *ret_val = NULL;
0461 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0462
0463 if (ops)
0464 ret_val = ops->doi_getdef(doi);
0465 return ret_val;
0466 }
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476 void calipso_doi_putdef(struct calipso_doi *doi_def)
0477 {
0478 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0479
0480 if (ops)
0481 ops->doi_putdef(doi_def);
0482 }
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 int calipso_doi_walk(u32 *skip_cnt,
0498 int (*callback)(struct calipso_doi *doi_def, void *arg),
0499 void *cb_arg)
0500 {
0501 int ret_val = -ENOMSG;
0502 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0503
0504 if (ops)
0505 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
0506 return ret_val;
0507 }
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521 int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
0522 {
0523 int ret_val = -ENOMSG;
0524 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0525
0526 if (ops)
0527 ret_val = ops->sock_getattr(sk, secattr);
0528 return ret_val;
0529 }
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545 int calipso_sock_setattr(struct sock *sk,
0546 const struct calipso_doi *doi_def,
0547 const struct netlbl_lsm_secattr *secattr)
0548 {
0549 int ret_val = -ENOMSG;
0550 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0551
0552 if (ops)
0553 ret_val = ops->sock_setattr(sk, doi_def, secattr);
0554 return ret_val;
0555 }
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565 void calipso_sock_delattr(struct sock *sk)
0566 {
0567 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0568
0569 if (ops)
0570 ops->sock_delattr(sk);
0571 }
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585 int calipso_req_setattr(struct request_sock *req,
0586 const struct calipso_doi *doi_def,
0587 const struct netlbl_lsm_secattr *secattr)
0588 {
0589 int ret_val = -ENOMSG;
0590 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0591
0592 if (ops)
0593 ret_val = ops->req_setattr(req, doi_def, secattr);
0594 return ret_val;
0595 }
0596
0597
0598
0599
0600
0601
0602
0603
0604
0605 void calipso_req_delattr(struct request_sock *req)
0606 {
0607 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0608
0609 if (ops)
0610 ops->req_delattr(req);
0611 }
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622 unsigned char *calipso_optptr(const struct sk_buff *skb)
0623 {
0624 unsigned char *ret_val = NULL;
0625 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0626
0627 if (ops)
0628 ret_val = ops->skbuff_optptr(skb);
0629 return ret_val;
0630 }
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642 int calipso_getattr(const unsigned char *calipso,
0643 struct netlbl_lsm_secattr *secattr)
0644 {
0645 int ret_val = -ENOMSG;
0646 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0647
0648 if (ops)
0649 ret_val = ops->opt_getattr(calipso, secattr);
0650 return ret_val;
0651 }
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664 int calipso_skbuff_setattr(struct sk_buff *skb,
0665 const struct calipso_doi *doi_def,
0666 const struct netlbl_lsm_secattr *secattr)
0667 {
0668 int ret_val = -ENOMSG;
0669 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0670
0671 if (ops)
0672 ret_val = ops->skbuff_setattr(skb, doi_def, secattr);
0673 return ret_val;
0674 }
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685 int calipso_skbuff_delattr(struct sk_buff *skb)
0686 {
0687 int ret_val = -ENOMSG;
0688 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0689
0690 if (ops)
0691 ret_val = ops->skbuff_delattr(skb);
0692 return ret_val;
0693 }
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 void calipso_cache_invalidate(void)
0704 {
0705 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0706
0707 if (ops)
0708 ops->cache_invalidate();
0709 }
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721 int calipso_cache_add(const unsigned char *calipso_ptr,
0722 const struct netlbl_lsm_secattr *secattr)
0723
0724 {
0725 int ret_val = -ENOMSG;
0726 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
0727
0728 if (ops)
0729 ret_val = ops->cache_add(calipso_ptr, secattr);
0730 return ret_val;
0731 }