1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/types.h>
32#include <linux/socket.h>
33#include <linux/string.h>
34#include <linux/skbuff.h>
35#include <linux/audit.h>
36#include <linux/slab.h>
37#include <net/sock.h>
38#include <net/netlink.h>
39#include <net/genetlink.h>
40#include <net/netlabel.h>
41#include <net/calipso.h>
42#include <linux/atomic.h>
43
44#include "netlabel_user.h"
45#include "netlabel_calipso.h"
46#include "netlabel_mgmt.h"
47#include "netlabel_domainhash.h"
48
49
50struct netlbl_calipso_doiwalk_arg {
51 struct netlink_callback *nl_cb;
52 struct sk_buff *skb;
53 u32 seq;
54};
55
56
57struct netlbl_domhsh_walk_arg {
58 struct netlbl_audit *audit_info;
59 u32 doi;
60};
61
62
63static struct genl_family netlbl_calipso_gnl_family = {
64 .id = GENL_ID_GENERATE,
65 .hdrsize = 0,
66 .name = NETLBL_NLTYPE_CALIPSO_NAME,
67 .version = NETLBL_PROTO_VERSION,
68 .maxattr = NLBL_CALIPSO_A_MAX,
69};
70
71
72static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
73 [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },
74 [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
75};
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90static int netlbl_calipso_add_pass(struct genl_info *info,
91 struct netlbl_audit *audit_info)
92{
93 int ret_val;
94 struct calipso_doi *doi_def = NULL;
95
96 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
97 if (!doi_def)
98 return -ENOMEM;
99 doi_def->type = CALIPSO_MAP_PASS;
100 doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
101 ret_val = calipso_doi_add(doi_def, audit_info);
102 if (ret_val != 0)
103 calipso_doi_free(doi_def);
104
105 return ret_val;
106}
107
108
109
110
111
112
113
114
115
116
117
118static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
119
120{
121 int ret_val = -EINVAL;
122 struct netlbl_audit audit_info;
123
124 if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
125 !info->attrs[NLBL_CALIPSO_A_MTYPE])
126 return -EINVAL;
127
128 netlbl_netlink_auditinfo(skb, &audit_info);
129 switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
130 case CALIPSO_MAP_PASS:
131 ret_val = netlbl_calipso_add_pass(info, &audit_info);
132 break;
133 }
134 if (ret_val == 0)
135 atomic_inc(&netlabel_mgmt_protocount);
136
137 return ret_val;
138}
139
140
141
142
143
144
145
146
147
148
149
150static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)
151{
152 int ret_val;
153 struct sk_buff *ans_skb = NULL;
154 void *data;
155 u32 doi;
156 struct calipso_doi *doi_def;
157
158 if (!info->attrs[NLBL_CALIPSO_A_DOI]) {
159 ret_val = -EINVAL;
160 goto list_failure;
161 }
162
163 doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
164
165 doi_def = calipso_doi_getdef(doi);
166 if (!doi_def) {
167 ret_val = -EINVAL;
168 goto list_failure;
169 }
170
171 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
172 if (!ans_skb) {
173 ret_val = -ENOMEM;
174 goto list_failure_put;
175 }
176 data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,
177 0, NLBL_CALIPSO_C_LIST);
178 if (!data) {
179 ret_val = -ENOMEM;
180 goto list_failure_put;
181 }
182
183 ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);
184 if (ret_val != 0)
185 goto list_failure_put;
186
187 calipso_doi_putdef(doi_def);
188
189 genlmsg_end(ans_skb, data);
190 return genlmsg_reply(ans_skb, info);
191
192list_failure_put:
193 calipso_doi_putdef(doi_def);
194list_failure:
195 kfree_skb(ans_skb);
196 return ret_val;
197}
198
199
200
201
202
203
204
205
206
207
208
209
210
211static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)
212{
213 int ret_val = -ENOMEM;
214 struct netlbl_calipso_doiwalk_arg *cb_arg = arg;
215 void *data;
216
217 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
218 cb_arg->seq, &netlbl_calipso_gnl_family,
219 NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);
220 if (!data)
221 goto listall_cb_failure;
222
223 ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);
224 if (ret_val != 0)
225 goto listall_cb_failure;
226 ret_val = nla_put_u32(cb_arg->skb,
227 NLBL_CALIPSO_A_MTYPE,
228 doi_def->type);
229 if (ret_val != 0)
230 goto listall_cb_failure;
231
232 genlmsg_end(cb_arg->skb, data);
233 return 0;
234
235listall_cb_failure:
236 genlmsg_cancel(cb_arg->skb, data);
237 return ret_val;
238}
239
240
241
242
243
244
245
246
247
248
249
250static int netlbl_calipso_listall(struct sk_buff *skb,
251 struct netlink_callback *cb)
252{
253 struct netlbl_calipso_doiwalk_arg cb_arg;
254 u32 doi_skip = cb->args[0];
255
256 cb_arg.nl_cb = cb;
257 cb_arg.skb = skb;
258 cb_arg.seq = cb->nlh->nlmsg_seq;
259
260 calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);
261
262 cb->args[0] = doi_skip;
263 return skb->len;
264}
265
266
267
268
269
270
271
272
273
274
275
276
277
278static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)
279{
280 struct netlbl_domhsh_walk_arg *cb_arg = arg;
281
282 if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&
283 entry->def.calipso->doi == cb_arg->doi)
284 return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
285
286 return 0;
287}
288
289
290
291
292
293
294
295
296
297
298
299static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
300{
301 int ret_val = -EINVAL;
302 struct netlbl_domhsh_walk_arg cb_arg;
303 struct netlbl_audit audit_info;
304 u32 skip_bkt = 0;
305 u32 skip_chain = 0;
306
307 if (!info->attrs[NLBL_CALIPSO_A_DOI])
308 return -EINVAL;
309
310 netlbl_netlink_auditinfo(skb, &audit_info);
311 cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
312 cb_arg.audit_info = &audit_info;
313 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
314 netlbl_calipso_remove_cb, &cb_arg);
315 if (ret_val == 0 || ret_val == -ENOENT) {
316 ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);
317 if (ret_val == 0)
318 atomic_dec(&netlabel_mgmt_protocount);
319 }
320
321 return ret_val;
322}
323
324
325
326
327static const struct genl_ops netlbl_calipso_ops[] = {
328 {
329 .cmd = NLBL_CALIPSO_C_ADD,
330 .flags = GENL_ADMIN_PERM,
331 .policy = calipso_genl_policy,
332 .doit = netlbl_calipso_add,
333 .dumpit = NULL,
334 },
335 {
336 .cmd = NLBL_CALIPSO_C_REMOVE,
337 .flags = GENL_ADMIN_PERM,
338 .policy = calipso_genl_policy,
339 .doit = netlbl_calipso_remove,
340 .dumpit = NULL,
341 },
342 {
343 .cmd = NLBL_CALIPSO_C_LIST,
344 .flags = 0,
345 .policy = calipso_genl_policy,
346 .doit = netlbl_calipso_list,
347 .dumpit = NULL,
348 },
349 {
350 .cmd = NLBL_CALIPSO_C_LISTALL,
351 .flags = 0,
352 .policy = calipso_genl_policy,
353 .doit = NULL,
354 .dumpit = netlbl_calipso_listall,
355 },
356};
357
358
359
360
361
362
363
364
365
366
367
368
369int __init netlbl_calipso_genl_init(void)
370{
371 return genl_register_family_with_ops(&netlbl_calipso_gnl_family,
372 netlbl_calipso_ops);
373}
374
375static const struct netlbl_calipso_ops *calipso_ops;
376
377
378
379
380
381
382
383
384const struct netlbl_calipso_ops *
385netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
386{
387 return xchg(&calipso_ops, ops);
388}
389EXPORT_SYMBOL(netlbl_calipso_ops_register);
390
391static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
392{
393 return ACCESS_ONCE(calipso_ops);
394}
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409int calipso_doi_add(struct calipso_doi *doi_def,
410 struct netlbl_audit *audit_info)
411{
412 int ret_val = -ENOMSG;
413 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
414
415 if (ops)
416 ret_val = ops->doi_add(doi_def, audit_info);
417 return ret_val;
418}
419
420
421
422
423
424
425
426
427
428void calipso_doi_free(struct calipso_doi *doi_def)
429{
430 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
431
432 if (ops)
433 ops->doi_free(doi_def);
434}
435
436
437
438
439
440
441
442
443
444
445
446
447int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
448{
449 int ret_val = -ENOMSG;
450 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
451
452 if (ops)
453 ret_val = ops->doi_remove(doi, audit_info);
454 return ret_val;
455}
456
457
458
459
460
461
462
463
464
465
466
467struct calipso_doi *calipso_doi_getdef(u32 doi)
468{
469 struct calipso_doi *ret_val = NULL;
470 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
471
472 if (ops)
473 ret_val = ops->doi_getdef(doi);
474 return ret_val;
475}
476
477
478
479
480
481
482
483
484
485void calipso_doi_putdef(struct calipso_doi *doi_def)
486{
487 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
488
489 if (ops)
490 ops->doi_putdef(doi_def);
491}
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506int calipso_doi_walk(u32 *skip_cnt,
507 int (*callback)(struct calipso_doi *doi_def, void *arg),
508 void *cb_arg)
509{
510 int ret_val = -ENOMSG;
511 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
512
513 if (ops)
514 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
515 return ret_val;
516}
517
518
519
520
521
522
523
524
525
526
527
528
529
530int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
531{
532 int ret_val = -ENOMSG;
533 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
534
535 if (ops)
536 ret_val = ops->sock_getattr(sk, secattr);
537 return ret_val;
538}
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554int calipso_sock_setattr(struct sock *sk,
555 const struct calipso_doi *doi_def,
556 const struct netlbl_lsm_secattr *secattr)
557{
558 int ret_val = -ENOMSG;
559 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
560
561 if (ops)
562 ret_val = ops->sock_setattr(sk, doi_def, secattr);
563 return ret_val;
564}
565
566
567
568
569
570
571
572
573
574void calipso_sock_delattr(struct sock *sk)
575{
576 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
577
578 if (ops)
579 ops->sock_delattr(sk);
580}
581
582
583
584
585
586
587
588
589
590
591
592
593
594int calipso_req_setattr(struct request_sock *req,
595 const struct calipso_doi *doi_def,
596 const struct netlbl_lsm_secattr *secattr)
597{
598 int ret_val = -ENOMSG;
599 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
600
601 if (ops)
602 ret_val = ops->req_setattr(req, doi_def, secattr);
603 return ret_val;
604}
605
606
607
608
609
610
611
612
613
614void calipso_req_delattr(struct request_sock *req)
615{
616 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
617
618 if (ops)
619 ops->req_delattr(req);
620}
621
622
623
624
625
626
627
628
629
630
631unsigned char *calipso_optptr(const struct sk_buff *skb)
632{
633 unsigned char *ret_val = NULL;
634 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
635
636 if (ops)
637 ret_val = ops->skbuff_optptr(skb);
638 return ret_val;
639}
640
641
642
643
644
645
646
647
648
649
650
651int calipso_getattr(const unsigned char *calipso,
652 struct netlbl_lsm_secattr *secattr)
653{
654 int ret_val = -ENOMSG;
655 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
656
657 if (ops)
658 ret_val = ops->opt_getattr(calipso, secattr);
659 return ret_val;
660}
661
662
663
664
665
666
667
668
669
670
671
672
673int calipso_skbuff_setattr(struct sk_buff *skb,
674 const struct calipso_doi *doi_def,
675 const struct netlbl_lsm_secattr *secattr)
676{
677 int ret_val = -ENOMSG;
678 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
679
680 if (ops)
681 ret_val = ops->skbuff_setattr(skb, doi_def, secattr);
682 return ret_val;
683}
684
685
686
687
688
689
690
691
692
693
694int calipso_skbuff_delattr(struct sk_buff *skb)
695{
696 int ret_val = -ENOMSG;
697 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
698
699 if (ops)
700 ret_val = ops->skbuff_delattr(skb);
701 return ret_val;
702}
703
704
705
706
707
708
709
710
711
712void calipso_cache_invalidate(void)
713{
714 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
715
716 if (ops)
717 ops->cache_invalidate();
718}
719
720
721
722
723
724
725
726
727
728
729
730int calipso_cache_add(const unsigned char *calipso_ptr,
731 const struct netlbl_lsm_secattr *secattr)
732
733{
734 int ret_val = -ENOMSG;
735 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
736
737 if (ops)
738 ret_val = ops->cache_add(calipso_ptr, secattr);
739 return ret_val;
740}
741