This source file includes following definitions.
- cipso_v4_cache_entry_free
- cipso_v4_map_cache_hash
- cipso_v4_cache_init
- cipso_v4_cache_invalidate
- cipso_v4_cache_check
- cipso_v4_cache_add
- cipso_v4_doi_search
- cipso_v4_doi_add
- cipso_v4_doi_free
- cipso_v4_doi_free_rcu
- cipso_v4_doi_remove
- cipso_v4_doi_getdef
- cipso_v4_doi_putdef
- cipso_v4_doi_walk
- cipso_v4_map_lvl_valid
- cipso_v4_map_lvl_hton
- cipso_v4_map_lvl_ntoh
- cipso_v4_map_cat_rbm_valid
- cipso_v4_map_cat_rbm_hton
- cipso_v4_map_cat_rbm_ntoh
- cipso_v4_map_cat_enum_valid
- cipso_v4_map_cat_enum_hton
- cipso_v4_map_cat_enum_ntoh
- cipso_v4_map_cat_rng_valid
- cipso_v4_map_cat_rng_hton
- cipso_v4_map_cat_rng_ntoh
- cipso_v4_gentag_hdr
- cipso_v4_gentag_rbm
- cipso_v4_parsetag_rbm
- cipso_v4_gentag_enum
- cipso_v4_parsetag_enum
- cipso_v4_gentag_rng
- cipso_v4_parsetag_rng
- cipso_v4_gentag_loc
- cipso_v4_parsetag_loc
- cipso_v4_optptr
- cipso_v4_validate
- cipso_v4_error
- cipso_v4_genopt
- cipso_v4_sock_setattr
- cipso_v4_req_setattr
- cipso_v4_delopt
- cipso_v4_sock_delattr
- cipso_v4_req_delattr
- cipso_v4_getattr
- cipso_v4_sock_getattr
- cipso_v4_skbuff_setattr
- cipso_v4_skbuff_delattr
- cipso_v4_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include <linux/init.h>
25 #include <linux/types.h>
26 #include <linux/rcupdate.h>
27 #include <linux/list.h>
28 #include <linux/spinlock.h>
29 #include <linux/string.h>
30 #include <linux/jhash.h>
31 #include <linux/audit.h>
32 #include <linux/slab.h>
33 #include <net/ip.h>
34 #include <net/icmp.h>
35 #include <net/tcp.h>
36 #include <net/netlabel.h>
37 #include <net/cipso_ipv4.h>
38 #include <linux/atomic.h>
39 #include <linux/bug.h>
40 #include <asm/unaligned.h>
41
42
43
44
45
46
47 static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
48 static LIST_HEAD(cipso_v4_doi_list);
49
50
51 int cipso_v4_cache_enabled = 1;
52 int cipso_v4_cache_bucketsize = 10;
53 #define CIPSO_V4_CACHE_BUCKETBITS 7
54 #define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS)
55 #define CIPSO_V4_CACHE_REORDERLIMIT 10
56 struct cipso_v4_map_cache_bkt {
57 spinlock_t lock;
58 u32 size;
59 struct list_head list;
60 };
61
62 struct cipso_v4_map_cache_entry {
63 u32 hash;
64 unsigned char *key;
65 size_t key_len;
66
67 struct netlbl_lsm_cache *lsm_data;
68
69 u32 activity;
70 struct list_head list;
71 };
72
73 static struct cipso_v4_map_cache_bkt *cipso_v4_cache;
74
75
76 int cipso_v4_rbm_optfmt = 0;
77 int cipso_v4_rbm_strictvalid = 1;
78
79
80
81
82
83
84
85 #define CIPSO_V4_OPT_LEN_MAX 40
86
87
88
89 #define CIPSO_V4_HDR_LEN 6
90
91
92 #define CIPSO_V4_TAG_RBM_BLEN 4
93
94
95 #define CIPSO_V4_TAG_ENUM_BLEN 4
96
97
98 #define CIPSO_V4_TAG_RNG_BLEN 4
99
100
101
102
103
104 #define CIPSO_V4_TAG_RNG_CAT_MAX 8
105
106
107
108
109
110
111
112
113
114
115
116
117 #define CIPSO_V4_TAG_LOC_BLEN 6
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
133 {
134 if (entry->lsm_data)
135 netlbl_secattr_cache_free(entry->lsm_data);
136 kfree(entry->key);
137 kfree(entry);
138 }
139
140
141
142
143
144
145
146
147
148
149 static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len)
150 {
151 return jhash(key, key_len, 0);
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 static int __init cipso_v4_cache_init(void)
168 {
169 u32 iter;
170
171 cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,
172 sizeof(struct cipso_v4_map_cache_bkt),
173 GFP_KERNEL);
174 if (!cipso_v4_cache)
175 return -ENOMEM;
176
177 for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
178 spin_lock_init(&cipso_v4_cache[iter].lock);
179 cipso_v4_cache[iter].size = 0;
180 INIT_LIST_HEAD(&cipso_v4_cache[iter].list);
181 }
182
183 return 0;
184 }
185
186
187
188
189
190
191
192
193
194 void cipso_v4_cache_invalidate(void)
195 {
196 struct cipso_v4_map_cache_entry *entry, *tmp_entry;
197 u32 iter;
198
199 for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
200 spin_lock_bh(&cipso_v4_cache[iter].lock);
201 list_for_each_entry_safe(entry,
202 tmp_entry,
203 &cipso_v4_cache[iter].list, list) {
204 list_del(&entry->list);
205 cipso_v4_cache_entry_free(entry);
206 }
207 cipso_v4_cache[iter].size = 0;
208 spin_unlock_bh(&cipso_v4_cache[iter].lock);
209 }
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 static int cipso_v4_cache_check(const unsigned char *key,
235 u32 key_len,
236 struct netlbl_lsm_secattr *secattr)
237 {
238 u32 bkt;
239 struct cipso_v4_map_cache_entry *entry;
240 struct cipso_v4_map_cache_entry *prev_entry = NULL;
241 u32 hash;
242
243 if (!cipso_v4_cache_enabled)
244 return -ENOENT;
245
246 hash = cipso_v4_map_cache_hash(key, key_len);
247 bkt = hash & (CIPSO_V4_CACHE_BUCKETS - 1);
248 spin_lock_bh(&cipso_v4_cache[bkt].lock);
249 list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
250 if (entry->hash == hash &&
251 entry->key_len == key_len &&
252 memcmp(entry->key, key, key_len) == 0) {
253 entry->activity += 1;
254 refcount_inc(&entry->lsm_data->refcount);
255 secattr->cache = entry->lsm_data;
256 secattr->flags |= NETLBL_SECATTR_CACHE;
257 secattr->type = NETLBL_NLTYPE_CIPSOV4;
258 if (!prev_entry) {
259 spin_unlock_bh(&cipso_v4_cache[bkt].lock);
260 return 0;
261 }
262
263 if (prev_entry->activity > 0)
264 prev_entry->activity -= 1;
265 if (entry->activity > prev_entry->activity &&
266 entry->activity - prev_entry->activity >
267 CIPSO_V4_CACHE_REORDERLIMIT) {
268 __list_del(entry->list.prev, entry->list.next);
269 __list_add(&entry->list,
270 prev_entry->list.prev,
271 &prev_entry->list);
272 }
273
274 spin_unlock_bh(&cipso_v4_cache[bkt].lock);
275 return 0;
276 }
277 prev_entry = entry;
278 }
279 spin_unlock_bh(&cipso_v4_cache[bkt].lock);
280
281 return -ENOENT;
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 int cipso_v4_cache_add(const unsigned char *cipso_ptr,
298 const struct netlbl_lsm_secattr *secattr)
299 {
300 int ret_val = -EPERM;
301 u32 bkt;
302 struct cipso_v4_map_cache_entry *entry = NULL;
303 struct cipso_v4_map_cache_entry *old_entry = NULL;
304 u32 cipso_ptr_len;
305
306 if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
307 return 0;
308
309 cipso_ptr_len = cipso_ptr[1];
310
311 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
312 if (!entry)
313 return -ENOMEM;
314 entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC);
315 if (!entry->key) {
316 ret_val = -ENOMEM;
317 goto cache_add_failure;
318 }
319 entry->key_len = cipso_ptr_len;
320 entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
321 refcount_inc(&secattr->cache->refcount);
322 entry->lsm_data = secattr->cache;
323
324 bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
325 spin_lock_bh(&cipso_v4_cache[bkt].lock);
326 if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
327 list_add(&entry->list, &cipso_v4_cache[bkt].list);
328 cipso_v4_cache[bkt].size += 1;
329 } else {
330 old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
331 struct cipso_v4_map_cache_entry, list);
332 list_del(&old_entry->list);
333 list_add(&entry->list, &cipso_v4_cache[bkt].list);
334 cipso_v4_cache_entry_free(old_entry);
335 }
336 spin_unlock_bh(&cipso_v4_cache[bkt].lock);
337
338 return 0;
339
340 cache_add_failure:
341 if (entry)
342 cipso_v4_cache_entry_free(entry);
343 return ret_val;
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
360 {
361 struct cipso_v4_doi *iter;
362
363 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
364 if (iter->doi == doi && refcount_read(&iter->refcount))
365 return iter;
366 return NULL;
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
383 struct netlbl_audit *audit_info)
384 {
385 int ret_val = -EINVAL;
386 u32 iter;
387 u32 doi;
388 u32 doi_type;
389 struct audit_buffer *audit_buf;
390
391 doi = doi_def->doi;
392 doi_type = doi_def->type;
393
394 if (doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
395 goto doi_add_return;
396 for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
397 switch (doi_def->tags[iter]) {
398 case CIPSO_V4_TAG_RBITMAP:
399 break;
400 case CIPSO_V4_TAG_RANGE:
401 case CIPSO_V4_TAG_ENUM:
402 if (doi_def->type != CIPSO_V4_MAP_PASS)
403 goto doi_add_return;
404 break;
405 case CIPSO_V4_TAG_LOCAL:
406 if (doi_def->type != CIPSO_V4_MAP_LOCAL)
407 goto doi_add_return;
408 break;
409 case CIPSO_V4_TAG_INVALID:
410 if (iter == 0)
411 goto doi_add_return;
412 break;
413 default:
414 goto doi_add_return;
415 }
416 }
417
418 refcount_set(&doi_def->refcount, 1);
419
420 spin_lock(&cipso_v4_doi_list_lock);
421 if (cipso_v4_doi_search(doi_def->doi)) {
422 spin_unlock(&cipso_v4_doi_list_lock);
423 ret_val = -EEXIST;
424 goto doi_add_return;
425 }
426 list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
427 spin_unlock(&cipso_v4_doi_list_lock);
428 ret_val = 0;
429
430 doi_add_return:
431 audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info);
432 if (audit_buf) {
433 const char *type_str;
434 switch (doi_type) {
435 case CIPSO_V4_MAP_TRANS:
436 type_str = "trans";
437 break;
438 case CIPSO_V4_MAP_PASS:
439 type_str = "pass";
440 break;
441 case CIPSO_V4_MAP_LOCAL:
442 type_str = "local";
443 break;
444 default:
445 type_str = "(unknown)";
446 }
447 audit_log_format(audit_buf,
448 " cipso_doi=%u cipso_type=%s res=%u",
449 doi, type_str, ret_val == 0 ? 1 : 0);
450 audit_log_end(audit_buf);
451 }
452
453 return ret_val;
454 }
455
456
457
458
459
460
461
462
463
464 void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
465 {
466 if (!doi_def)
467 return;
468
469 switch (doi_def->type) {
470 case CIPSO_V4_MAP_TRANS:
471 kfree(doi_def->map.std->lvl.cipso);
472 kfree(doi_def->map.std->lvl.local);
473 kfree(doi_def->map.std->cat.cipso);
474 kfree(doi_def->map.std->cat.local);
475 break;
476 }
477 kfree(doi_def);
478 }
479
480
481
482
483
484
485
486
487
488
489
490 static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
491 {
492 struct cipso_v4_doi *doi_def;
493
494 doi_def = container_of(entry, struct cipso_v4_doi, rcu);
495 cipso_v4_doi_free(doi_def);
496 }
497
498
499
500
501
502
503
504
505
506
507
508
509 int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
510 {
511 int ret_val;
512 struct cipso_v4_doi *doi_def;
513 struct audit_buffer *audit_buf;
514
515 spin_lock(&cipso_v4_doi_list_lock);
516 doi_def = cipso_v4_doi_search(doi);
517 if (!doi_def) {
518 spin_unlock(&cipso_v4_doi_list_lock);
519 ret_val = -ENOENT;
520 goto doi_remove_return;
521 }
522 if (!refcount_dec_and_test(&doi_def->refcount)) {
523 spin_unlock(&cipso_v4_doi_list_lock);
524 ret_val = -EBUSY;
525 goto doi_remove_return;
526 }
527 list_del_rcu(&doi_def->list);
528 spin_unlock(&cipso_v4_doi_list_lock);
529
530 cipso_v4_cache_invalidate();
531 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
532 ret_val = 0;
533
534 doi_remove_return:
535 audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info);
536 if (audit_buf) {
537 audit_log_format(audit_buf,
538 " cipso_doi=%u res=%u",
539 doi, ret_val == 0 ? 1 : 0);
540 audit_log_end(audit_buf);
541 }
542
543 return ret_val;
544 }
545
546
547
548
549
550
551
552
553
554
555
556
557 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
558 {
559 struct cipso_v4_doi *doi_def;
560
561 rcu_read_lock();
562 doi_def = cipso_v4_doi_search(doi);
563 if (!doi_def)
564 goto doi_getdef_return;
565 if (!refcount_inc_not_zero(&doi_def->refcount))
566 doi_def = NULL;
567
568 doi_getdef_return:
569 rcu_read_unlock();
570 return doi_def;
571 }
572
573
574
575
576
577
578
579
580
581 void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
582 {
583 if (!doi_def)
584 return;
585
586 if (!refcount_dec_and_test(&doi_def->refcount))
587 return;
588 spin_lock(&cipso_v4_doi_list_lock);
589 list_del_rcu(&doi_def->list);
590 spin_unlock(&cipso_v4_doi_list_lock);
591
592 cipso_v4_cache_invalidate();
593 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
594 }
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609 int cipso_v4_doi_walk(u32 *skip_cnt,
610 int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
611 void *cb_arg)
612 {
613 int ret_val = -ENOENT;
614 u32 doi_cnt = 0;
615 struct cipso_v4_doi *iter_doi;
616
617 rcu_read_lock();
618 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
619 if (refcount_read(&iter_doi->refcount) > 0) {
620 if (doi_cnt++ < *skip_cnt)
621 continue;
622 ret_val = callback(iter_doi, cb_arg);
623 if (ret_val < 0) {
624 doi_cnt--;
625 goto doi_walk_return;
626 }
627 }
628
629 doi_walk_return:
630 rcu_read_unlock();
631 *skip_cnt = doi_cnt;
632 return ret_val;
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650 static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
651 {
652 switch (doi_def->type) {
653 case CIPSO_V4_MAP_PASS:
654 return 0;
655 case CIPSO_V4_MAP_TRANS:
656 if ((level < doi_def->map.std->lvl.cipso_size) &&
657 (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL))
658 return 0;
659 break;
660 }
661
662 return -EFAULT;
663 }
664
665
666
667
668
669
670
671
672
673
674
675
676
677 static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
678 u32 host_lvl,
679 u32 *net_lvl)
680 {
681 switch (doi_def->type) {
682 case CIPSO_V4_MAP_PASS:
683 *net_lvl = host_lvl;
684 return 0;
685 case CIPSO_V4_MAP_TRANS:
686 if (host_lvl < doi_def->map.std->lvl.local_size &&
687 doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
688 *net_lvl = doi_def->map.std->lvl.local[host_lvl];
689 return 0;
690 }
691 return -EPERM;
692 }
693
694 return -EINVAL;
695 }
696
697
698
699
700
701
702
703
704
705
706
707
708
709 static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
710 u32 net_lvl,
711 u32 *host_lvl)
712 {
713 struct cipso_v4_std_map_tbl *map_tbl;
714
715 switch (doi_def->type) {
716 case CIPSO_V4_MAP_PASS:
717 *host_lvl = net_lvl;
718 return 0;
719 case CIPSO_V4_MAP_TRANS:
720 map_tbl = doi_def->map.std;
721 if (net_lvl < map_tbl->lvl.cipso_size &&
722 map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
723 *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
724 return 0;
725 }
726 return -EPERM;
727 }
728
729 return -EINVAL;
730 }
731
732
733
734
735
736
737
738
739
740
741
742
743
744 static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
745 const unsigned char *bitmap,
746 u32 bitmap_len)
747 {
748 int cat = -1;
749 u32 bitmap_len_bits = bitmap_len * 8;
750 u32 cipso_cat_size;
751 u32 *cipso_array;
752
753 switch (doi_def->type) {
754 case CIPSO_V4_MAP_PASS:
755 return 0;
756 case CIPSO_V4_MAP_TRANS:
757 cipso_cat_size = doi_def->map.std->cat.cipso_size;
758 cipso_array = doi_def->map.std->cat.cipso;
759 for (;;) {
760 cat = netlbl_bitmap_walk(bitmap,
761 bitmap_len_bits,
762 cat + 1,
763 1);
764 if (cat < 0)
765 break;
766 if (cat >= cipso_cat_size ||
767 cipso_array[cat] >= CIPSO_V4_INV_CAT)
768 return -EFAULT;
769 }
770
771 if (cat == -1)
772 return 0;
773 break;
774 }
775
776 return -EFAULT;
777 }
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792 static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
793 const struct netlbl_lsm_secattr *secattr,
794 unsigned char *net_cat,
795 u32 net_cat_len)
796 {
797 int host_spot = -1;
798 u32 net_spot = CIPSO_V4_INV_CAT;
799 u32 net_spot_max = 0;
800 u32 net_clen_bits = net_cat_len * 8;
801 u32 host_cat_size = 0;
802 u32 *host_cat_array = NULL;
803
804 if (doi_def->type == CIPSO_V4_MAP_TRANS) {
805 host_cat_size = doi_def->map.std->cat.local_size;
806 host_cat_array = doi_def->map.std->cat.local;
807 }
808
809 for (;;) {
810 host_spot = netlbl_catmap_walk(secattr->attr.mls.cat,
811 host_spot + 1);
812 if (host_spot < 0)
813 break;
814
815 switch (doi_def->type) {
816 case CIPSO_V4_MAP_PASS:
817 net_spot = host_spot;
818 break;
819 case CIPSO_V4_MAP_TRANS:
820 if (host_spot >= host_cat_size)
821 return -EPERM;
822 net_spot = host_cat_array[host_spot];
823 if (net_spot >= CIPSO_V4_INV_CAT)
824 return -EPERM;
825 break;
826 }
827 if (net_spot >= net_clen_bits)
828 return -ENOSPC;
829 netlbl_bitmap_setbit(net_cat, net_spot, 1);
830
831 if (net_spot > net_spot_max)
832 net_spot_max = net_spot;
833 }
834
835 if (++net_spot_max % 8)
836 return net_spot_max / 8 + 1;
837 return net_spot_max / 8;
838 }
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853 static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
854 const unsigned char *net_cat,
855 u32 net_cat_len,
856 struct netlbl_lsm_secattr *secattr)
857 {
858 int ret_val;
859 int net_spot = -1;
860 u32 host_spot = CIPSO_V4_INV_CAT;
861 u32 net_clen_bits = net_cat_len * 8;
862 u32 net_cat_size = 0;
863 u32 *net_cat_array = NULL;
864
865 if (doi_def->type == CIPSO_V4_MAP_TRANS) {
866 net_cat_size = doi_def->map.std->cat.cipso_size;
867 net_cat_array = doi_def->map.std->cat.cipso;
868 }
869
870 for (;;) {
871 net_spot = netlbl_bitmap_walk(net_cat,
872 net_clen_bits,
873 net_spot + 1,
874 1);
875 if (net_spot < 0) {
876 if (net_spot == -2)
877 return -EFAULT;
878 return 0;
879 }
880
881 switch (doi_def->type) {
882 case CIPSO_V4_MAP_PASS:
883 host_spot = net_spot;
884 break;
885 case CIPSO_V4_MAP_TRANS:
886 if (net_spot >= net_cat_size)
887 return -EPERM;
888 host_spot = net_cat_array[net_spot];
889 if (host_spot >= CIPSO_V4_INV_CAT)
890 return -EPERM;
891 break;
892 }
893 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
894 host_spot,
895 GFP_ATOMIC);
896 if (ret_val != 0)
897 return ret_val;
898 }
899
900 return -EINVAL;
901 }
902
903
904
905
906
907
908
909
910
911
912
913
914
915 static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def,
916 const unsigned char *enumcat,
917 u32 enumcat_len)
918 {
919 u16 cat;
920 int cat_prev = -1;
921 u32 iter;
922
923 if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01)
924 return -EFAULT;
925
926 for (iter = 0; iter < enumcat_len; iter += 2) {
927 cat = get_unaligned_be16(&enumcat[iter]);
928 if (cat <= cat_prev)
929 return -EFAULT;
930 cat_prev = cat;
931 }
932
933 return 0;
934 }
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950 static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
951 const struct netlbl_lsm_secattr *secattr,
952 unsigned char *net_cat,
953 u32 net_cat_len)
954 {
955 int cat = -1;
956 u32 cat_iter = 0;
957
958 for (;;) {
959 cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1);
960 if (cat < 0)
961 break;
962 if ((cat_iter + 2) > net_cat_len)
963 return -ENOSPC;
964
965 *((__be16 *)&net_cat[cat_iter]) = htons(cat);
966 cat_iter += 2;
967 }
968
969 return cat_iter;
970 }
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985 static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
986 const unsigned char *net_cat,
987 u32 net_cat_len,
988 struct netlbl_lsm_secattr *secattr)
989 {
990 int ret_val;
991 u32 iter;
992
993 for (iter = 0; iter < net_cat_len; iter += 2) {
994 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
995 get_unaligned_be16(&net_cat[iter]),
996 GFP_ATOMIC);
997 if (ret_val != 0)
998 return ret_val;
999 }
1000
1001 return 0;
1002 }
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def,
1017 const unsigned char *rngcat,
1018 u32 rngcat_len)
1019 {
1020 u16 cat_high;
1021 u16 cat_low;
1022 u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1;
1023 u32 iter;
1024
1025 if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01)
1026 return -EFAULT;
1027
1028 for (iter = 0; iter < rngcat_len; iter += 4) {
1029 cat_high = get_unaligned_be16(&rngcat[iter]);
1030 if ((iter + 4) <= rngcat_len)
1031 cat_low = get_unaligned_be16(&rngcat[iter + 2]);
1032 else
1033 cat_low = 0;
1034
1035 if (cat_high > cat_prev)
1036 return -EFAULT;
1037
1038 cat_prev = cat_low;
1039 }
1040
1041 return 0;
1042 }
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
1059 const struct netlbl_lsm_secattr *secattr,
1060 unsigned char *net_cat,
1061 u32 net_cat_len)
1062 {
1063 int iter = -1;
1064 u16 array[CIPSO_V4_TAG_RNG_CAT_MAX * 2];
1065 u32 array_cnt = 0;
1066 u32 cat_size = 0;
1067
1068
1069 if (net_cat_len >
1070 (CIPSO_V4_OPT_LEN_MAX - CIPSO_V4_HDR_LEN - CIPSO_V4_TAG_RNG_BLEN))
1071 return -ENOSPC;
1072
1073 for (;;) {
1074 iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1);
1075 if (iter < 0)
1076 break;
1077 cat_size += (iter == 0 ? 0 : sizeof(u16));
1078 if (cat_size > net_cat_len)
1079 return -ENOSPC;
1080 array[array_cnt++] = iter;
1081
1082 iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter);
1083 if (iter < 0)
1084 return -EFAULT;
1085 cat_size += sizeof(u16);
1086 if (cat_size > net_cat_len)
1087 return -ENOSPC;
1088 array[array_cnt++] = iter;
1089 }
1090
1091 for (iter = 0; array_cnt > 0;) {
1092 *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]);
1093 iter += 2;
1094 array_cnt--;
1095 if (array[array_cnt] != 0) {
1096 *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]);
1097 iter += 2;
1098 }
1099 }
1100
1101 return cat_size;
1102 }
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
1118 const unsigned char *net_cat,
1119 u32 net_cat_len,
1120 struct netlbl_lsm_secattr *secattr)
1121 {
1122 int ret_val;
1123 u32 net_iter;
1124 u16 cat_low;
1125 u16 cat_high;
1126
1127 for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
1128 cat_high = get_unaligned_be16(&net_cat[net_iter]);
1129 if ((net_iter + 4) <= net_cat_len)
1130 cat_low = get_unaligned_be16(&net_cat[net_iter + 2]);
1131 else
1132 cat_low = 0;
1133
1134 ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat,
1135 cat_low,
1136 cat_high,
1137 GFP_ATOMIC);
1138 if (ret_val != 0)
1139 return ret_val;
1140 }
1141
1142 return 0;
1143 }
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
1160 unsigned char *buf,
1161 u32 len)
1162 {
1163 buf[0] = IPOPT_CIPSO;
1164 buf[1] = CIPSO_V4_HDR_LEN + len;
1165 *(__be32 *)&buf[2] = htonl(doi_def->doi);
1166 }
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182 static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
1183 const struct netlbl_lsm_secattr *secattr,
1184 unsigned char *buffer,
1185 u32 buffer_len)
1186 {
1187 int ret_val;
1188 u32 tag_len;
1189 u32 level;
1190
1191 if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
1192 return -EPERM;
1193
1194 ret_val = cipso_v4_map_lvl_hton(doi_def,
1195 secattr->attr.mls.lvl,
1196 &level);
1197 if (ret_val != 0)
1198 return ret_val;
1199
1200 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1201 ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
1202 secattr,
1203 &buffer[4],
1204 buffer_len - 4);
1205 if (ret_val < 0)
1206 return ret_val;
1207
1208
1209
1210
1211 if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
1212 tag_len = 14;
1213 else
1214 tag_len = 4 + ret_val;
1215 } else
1216 tag_len = 4;
1217
1218 buffer[0] = CIPSO_V4_TAG_RBITMAP;
1219 buffer[1] = tag_len;
1220 buffer[3] = level;
1221
1222 return tag_len;
1223 }
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237 static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1238 const unsigned char *tag,
1239 struct netlbl_lsm_secattr *secattr)
1240 {
1241 int ret_val;
1242 u8 tag_len = tag[1];
1243 u32 level;
1244
1245 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1246 if (ret_val != 0)
1247 return ret_val;
1248 secattr->attr.mls.lvl = level;
1249 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1250
1251 if (tag_len > 4) {
1252 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
1253 &tag[4],
1254 tag_len - 4,
1255 secattr);
1256 if (ret_val != 0) {
1257 netlbl_catmap_free(secattr->attr.mls.cat);
1258 return ret_val;
1259 }
1260
1261 if (secattr->attr.mls.cat)
1262 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1263 }
1264
1265 return 0;
1266 }
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280 static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
1281 const struct netlbl_lsm_secattr *secattr,
1282 unsigned char *buffer,
1283 u32 buffer_len)
1284 {
1285 int ret_val;
1286 u32 tag_len;
1287 u32 level;
1288
1289 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1290 return -EPERM;
1291
1292 ret_val = cipso_v4_map_lvl_hton(doi_def,
1293 secattr->attr.mls.lvl,
1294 &level);
1295 if (ret_val != 0)
1296 return ret_val;
1297
1298 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1299 ret_val = cipso_v4_map_cat_enum_hton(doi_def,
1300 secattr,
1301 &buffer[4],
1302 buffer_len - 4);
1303 if (ret_val < 0)
1304 return ret_val;
1305
1306 tag_len = 4 + ret_val;
1307 } else
1308 tag_len = 4;
1309
1310 buffer[0] = CIPSO_V4_TAG_ENUM;
1311 buffer[1] = tag_len;
1312 buffer[3] = level;
1313
1314 return tag_len;
1315 }
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329 static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
1330 const unsigned char *tag,
1331 struct netlbl_lsm_secattr *secattr)
1332 {
1333 int ret_val;
1334 u8 tag_len = tag[1];
1335 u32 level;
1336
1337 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1338 if (ret_val != 0)
1339 return ret_val;
1340 secattr->attr.mls.lvl = level;
1341 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1342
1343 if (tag_len > 4) {
1344 ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
1345 &tag[4],
1346 tag_len - 4,
1347 secattr);
1348 if (ret_val != 0) {
1349 netlbl_catmap_free(secattr->attr.mls.cat);
1350 return ret_val;
1351 }
1352
1353 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1354 }
1355
1356 return 0;
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371 static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
1372 const struct netlbl_lsm_secattr *secattr,
1373 unsigned char *buffer,
1374 u32 buffer_len)
1375 {
1376 int ret_val;
1377 u32 tag_len;
1378 u32 level;
1379
1380 if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1381 return -EPERM;
1382
1383 ret_val = cipso_v4_map_lvl_hton(doi_def,
1384 secattr->attr.mls.lvl,
1385 &level);
1386 if (ret_val != 0)
1387 return ret_val;
1388
1389 if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1390 ret_val = cipso_v4_map_cat_rng_hton(doi_def,
1391 secattr,
1392 &buffer[4],
1393 buffer_len - 4);
1394 if (ret_val < 0)
1395 return ret_val;
1396
1397 tag_len = 4 + ret_val;
1398 } else
1399 tag_len = 4;
1400
1401 buffer[0] = CIPSO_V4_TAG_RANGE;
1402 buffer[1] = tag_len;
1403 buffer[3] = level;
1404
1405 return tag_len;
1406 }
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419 static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1420 const unsigned char *tag,
1421 struct netlbl_lsm_secattr *secattr)
1422 {
1423 int ret_val;
1424 u8 tag_len = tag[1];
1425 u32 level;
1426
1427 ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1428 if (ret_val != 0)
1429 return ret_val;
1430 secattr->attr.mls.lvl = level;
1431 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1432
1433 if (tag_len > 4) {
1434 ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
1435 &tag[4],
1436 tag_len - 4,
1437 secattr);
1438 if (ret_val != 0) {
1439 netlbl_catmap_free(secattr->attr.mls.cat);
1440 return ret_val;
1441 }
1442
1443 if (secattr->attr.mls.cat)
1444 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1445 }
1446
1447 return 0;
1448 }
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462 static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
1463 const struct netlbl_lsm_secattr *secattr,
1464 unsigned char *buffer,
1465 u32 buffer_len)
1466 {
1467 if (!(secattr->flags & NETLBL_SECATTR_SECID))
1468 return -EPERM;
1469
1470 buffer[0] = CIPSO_V4_TAG_LOCAL;
1471 buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
1472 *(u32 *)&buffer[2] = secattr->attr.secid;
1473
1474 return CIPSO_V4_TAG_LOC_BLEN;
1475 }
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488 static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
1489 const unsigned char *tag,
1490 struct netlbl_lsm_secattr *secattr)
1491 {
1492 secattr->attr.secid = *(u32 *)&tag[2];
1493 secattr->flags |= NETLBL_SECATTR_SECID;
1494
1495 return 0;
1496 }
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
1508 {
1509 const struct iphdr *iph = ip_hdr(skb);
1510 unsigned char *optptr = (unsigned char *)&(ip_hdr(skb)[1]);
1511 int optlen;
1512 int taglen;
1513
1514 for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 1; ) {
1515 switch (optptr[0]) {
1516 case IPOPT_END:
1517 return NULL;
1518 case IPOPT_NOOP:
1519 taglen = 1;
1520 break;
1521 default:
1522 taglen = optptr[1];
1523 }
1524 if (!taglen || taglen > optlen)
1525 return NULL;
1526 if (optptr[0] == IPOPT_CIPSO)
1527 return optptr;
1528
1529 optlen -= taglen;
1530 optptr += taglen;
1531 }
1532
1533 return NULL;
1534 }
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555 int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
1556 {
1557 unsigned char *opt = *option;
1558 unsigned char *tag;
1559 unsigned char opt_iter;
1560 unsigned char err_offset = 0;
1561 u8 opt_len;
1562 u8 tag_len;
1563 struct cipso_v4_doi *doi_def = NULL;
1564 u32 tag_iter;
1565
1566
1567 opt_len = opt[1];
1568 if (opt_len < 8) {
1569 err_offset = 1;
1570 goto validate_return;
1571 }
1572
1573 rcu_read_lock();
1574 doi_def = cipso_v4_doi_search(get_unaligned_be32(&opt[2]));
1575 if (!doi_def) {
1576 err_offset = 2;
1577 goto validate_return_locked;
1578 }
1579
1580 opt_iter = CIPSO_V4_HDR_LEN;
1581 tag = opt + opt_iter;
1582 while (opt_iter < opt_len) {
1583 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
1584 if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
1585 ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
1586 err_offset = opt_iter;
1587 goto validate_return_locked;
1588 }
1589
1590 if (opt_iter + 1 == opt_len) {
1591 err_offset = opt_iter;
1592 goto validate_return_locked;
1593 }
1594 tag_len = tag[1];
1595 if (tag_len > (opt_len - opt_iter)) {
1596 err_offset = opt_iter + 1;
1597 goto validate_return_locked;
1598 }
1599
1600 switch (tag[0]) {
1601 case CIPSO_V4_TAG_RBITMAP:
1602 if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
1603 err_offset = opt_iter + 1;
1604 goto validate_return_locked;
1605 }
1606
1607
1608
1609
1610
1611
1612
1613
1614 if (cipso_v4_rbm_strictvalid) {
1615 if (cipso_v4_map_lvl_valid(doi_def,
1616 tag[3]) < 0) {
1617 err_offset = opt_iter + 3;
1618 goto validate_return_locked;
1619 }
1620 if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
1621 cipso_v4_map_cat_rbm_valid(doi_def,
1622 &tag[4],
1623 tag_len - 4) < 0) {
1624 err_offset = opt_iter + 4;
1625 goto validate_return_locked;
1626 }
1627 }
1628 break;
1629 case CIPSO_V4_TAG_ENUM:
1630 if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
1631 err_offset = opt_iter + 1;
1632 goto validate_return_locked;
1633 }
1634
1635 if (cipso_v4_map_lvl_valid(doi_def,
1636 tag[3]) < 0) {
1637 err_offset = opt_iter + 3;
1638 goto validate_return_locked;
1639 }
1640 if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
1641 cipso_v4_map_cat_enum_valid(doi_def,
1642 &tag[4],
1643 tag_len - 4) < 0) {
1644 err_offset = opt_iter + 4;
1645 goto validate_return_locked;
1646 }
1647 break;
1648 case CIPSO_V4_TAG_RANGE:
1649 if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
1650 err_offset = opt_iter + 1;
1651 goto validate_return_locked;
1652 }
1653
1654 if (cipso_v4_map_lvl_valid(doi_def,
1655 tag[3]) < 0) {
1656 err_offset = opt_iter + 3;
1657 goto validate_return_locked;
1658 }
1659 if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
1660 cipso_v4_map_cat_rng_valid(doi_def,
1661 &tag[4],
1662 tag_len - 4) < 0) {
1663 err_offset = opt_iter + 4;
1664 goto validate_return_locked;
1665 }
1666 break;
1667 case CIPSO_V4_TAG_LOCAL:
1668
1669
1670
1671
1672
1673 if (!skb || !(skb->dev->flags & IFF_LOOPBACK)) {
1674 err_offset = opt_iter;
1675 goto validate_return_locked;
1676 }
1677 if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
1678 err_offset = opt_iter + 1;
1679 goto validate_return_locked;
1680 }
1681 break;
1682 default:
1683 err_offset = opt_iter;
1684 goto validate_return_locked;
1685 }
1686
1687 tag += tag_len;
1688 opt_iter += tag_len;
1689 }
1690
1691 validate_return_locked:
1692 rcu_read_unlock();
1693 validate_return:
1694 *option = opt + err_offset;
1695 return err_offset;
1696 }
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1726 {
1727 unsigned char optbuf[sizeof(struct ip_options) + 40];
1728 struct ip_options *opt = (struct ip_options *)optbuf;
1729 int res;
1730
1731 if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
1732 return;
1733
1734
1735
1736
1737
1738
1739 memset(opt, 0, sizeof(struct ip_options));
1740 opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
1741 rcu_read_lock();
1742 res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL);
1743 rcu_read_unlock();
1744
1745 if (res)
1746 return;
1747
1748 if (gateway)
1749 __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, opt);
1750 else
1751 __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, opt);
1752 }
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767 static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
1768 const struct cipso_v4_doi *doi_def,
1769 const struct netlbl_lsm_secattr *secattr)
1770 {
1771 int ret_val;
1772 u32 iter;
1773
1774 if (buf_len <= CIPSO_V4_HDR_LEN)
1775 return -ENOSPC;
1776
1777
1778
1779
1780 iter = 0;
1781 do {
1782 memset(buf, 0, buf_len);
1783 switch (doi_def->tags[iter]) {
1784 case CIPSO_V4_TAG_RBITMAP:
1785 ret_val = cipso_v4_gentag_rbm(doi_def,
1786 secattr,
1787 &buf[CIPSO_V4_HDR_LEN],
1788 buf_len - CIPSO_V4_HDR_LEN);
1789 break;
1790 case CIPSO_V4_TAG_ENUM:
1791 ret_val = cipso_v4_gentag_enum(doi_def,
1792 secattr,
1793 &buf[CIPSO_V4_HDR_LEN],
1794 buf_len - CIPSO_V4_HDR_LEN);
1795 break;
1796 case CIPSO_V4_TAG_RANGE:
1797 ret_val = cipso_v4_gentag_rng(doi_def,
1798 secattr,
1799 &buf[CIPSO_V4_HDR_LEN],
1800 buf_len - CIPSO_V4_HDR_LEN);
1801 break;
1802 case CIPSO_V4_TAG_LOCAL:
1803 ret_val = cipso_v4_gentag_loc(doi_def,
1804 secattr,
1805 &buf[CIPSO_V4_HDR_LEN],
1806 buf_len - CIPSO_V4_HDR_LEN);
1807 break;
1808 default:
1809 return -EPERM;
1810 }
1811
1812 iter++;
1813 } while (ret_val < 0 &&
1814 iter < CIPSO_V4_TAG_MAXCNT &&
1815 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1816 if (ret_val < 0)
1817 return ret_val;
1818 cipso_v4_gentag_hdr(doi_def, buf, ret_val);
1819 return CIPSO_V4_HDR_LEN + ret_val;
1820 }
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836 int cipso_v4_sock_setattr(struct sock *sk,
1837 const struct cipso_v4_doi *doi_def,
1838 const struct netlbl_lsm_secattr *secattr)
1839 {
1840 int ret_val = -EPERM;
1841 unsigned char *buf = NULL;
1842 u32 buf_len;
1843 u32 opt_len;
1844 struct ip_options_rcu *old, *opt = NULL;
1845 struct inet_sock *sk_inet;
1846 struct inet_connection_sock *sk_conn;
1847
1848
1849
1850
1851
1852 if (!sk)
1853 return 0;
1854
1855
1856
1857
1858 buf_len = CIPSO_V4_OPT_LEN_MAX;
1859 buf = kmalloc(buf_len, GFP_ATOMIC);
1860 if (!buf) {
1861 ret_val = -ENOMEM;
1862 goto socket_setattr_failure;
1863 }
1864
1865 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1866 if (ret_val < 0)
1867 goto socket_setattr_failure;
1868 buf_len = ret_val;
1869
1870
1871
1872
1873
1874 opt_len = (buf_len + 3) & ~3;
1875 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1876 if (!opt) {
1877 ret_val = -ENOMEM;
1878 goto socket_setattr_failure;
1879 }
1880 memcpy(opt->opt.__data, buf, buf_len);
1881 opt->opt.optlen = opt_len;
1882 opt->opt.cipso = sizeof(struct iphdr);
1883 kfree(buf);
1884 buf = NULL;
1885
1886 sk_inet = inet_sk(sk);
1887
1888 old = rcu_dereference_protected(sk_inet->inet_opt,
1889 lockdep_sock_is_held(sk));
1890 if (sk_inet->is_icsk) {
1891 sk_conn = inet_csk(sk);
1892 if (old)
1893 sk_conn->icsk_ext_hdr_len -= old->opt.optlen;
1894 sk_conn->icsk_ext_hdr_len += opt->opt.optlen;
1895 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
1896 }
1897 rcu_assign_pointer(sk_inet->inet_opt, opt);
1898 if (old)
1899 kfree_rcu(old, rcu);
1900
1901 return 0;
1902
1903 socket_setattr_failure:
1904 kfree(buf);
1905 kfree(opt);
1906 return ret_val;
1907 }
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921 int cipso_v4_req_setattr(struct request_sock *req,
1922 const struct cipso_v4_doi *doi_def,
1923 const struct netlbl_lsm_secattr *secattr)
1924 {
1925 int ret_val = -EPERM;
1926 unsigned char *buf = NULL;
1927 u32 buf_len;
1928 u32 opt_len;
1929 struct ip_options_rcu *opt = NULL;
1930 struct inet_request_sock *req_inet;
1931
1932
1933
1934
1935 buf_len = CIPSO_V4_OPT_LEN_MAX;
1936 buf = kmalloc(buf_len, GFP_ATOMIC);
1937 if (!buf) {
1938 ret_val = -ENOMEM;
1939 goto req_setattr_failure;
1940 }
1941
1942 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1943 if (ret_val < 0)
1944 goto req_setattr_failure;
1945 buf_len = ret_val;
1946
1947
1948
1949
1950
1951 opt_len = (buf_len + 3) & ~3;
1952 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1953 if (!opt) {
1954 ret_val = -ENOMEM;
1955 goto req_setattr_failure;
1956 }
1957 memcpy(opt->opt.__data, buf, buf_len);
1958 opt->opt.optlen = opt_len;
1959 opt->opt.cipso = sizeof(struct iphdr);
1960 kfree(buf);
1961 buf = NULL;
1962
1963 req_inet = inet_rsk(req);
1964 opt = xchg((__force struct ip_options_rcu **)&req_inet->ireq_opt, opt);
1965 if (opt)
1966 kfree_rcu(opt, rcu);
1967
1968 return 0;
1969
1970 req_setattr_failure:
1971 kfree(buf);
1972 kfree(opt);
1973 return ret_val;
1974 }
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986 static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
1987 {
1988 struct ip_options_rcu *opt = rcu_dereference_protected(*opt_ptr, 1);
1989 int hdr_delta = 0;
1990
1991 if (!opt || opt->opt.cipso == 0)
1992 return 0;
1993 if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) {
1994 u8 cipso_len;
1995 u8 cipso_off;
1996 unsigned char *cipso_ptr;
1997 int iter;
1998 int optlen_new;
1999
2000 cipso_off = opt->opt.cipso - sizeof(struct iphdr);
2001 cipso_ptr = &opt->opt.__data[cipso_off];
2002 cipso_len = cipso_ptr[1];
2003
2004 if (opt->opt.srr > opt->opt.cipso)
2005 opt->opt.srr -= cipso_len;
2006 if (opt->opt.rr > opt->opt.cipso)
2007 opt->opt.rr -= cipso_len;
2008 if (opt->opt.ts > opt->opt.cipso)
2009 opt->opt.ts -= cipso_len;
2010 if (opt->opt.router_alert > opt->opt.cipso)
2011 opt->opt.router_alert -= cipso_len;
2012 opt->opt.cipso = 0;
2013
2014 memmove(cipso_ptr, cipso_ptr + cipso_len,
2015 opt->opt.optlen - cipso_off - cipso_len);
2016
2017
2018
2019
2020
2021
2022 iter = 0;
2023 optlen_new = 0;
2024 while (iter < opt->opt.optlen)
2025 if (opt->opt.__data[iter] != IPOPT_NOP) {
2026 iter += opt->opt.__data[iter + 1];
2027 optlen_new = iter;
2028 } else
2029 iter++;
2030 hdr_delta = opt->opt.optlen;
2031 opt->opt.optlen = (optlen_new + 3) & ~3;
2032 hdr_delta -= opt->opt.optlen;
2033 } else {
2034
2035
2036 *opt_ptr = NULL;
2037 hdr_delta = opt->opt.optlen;
2038 kfree_rcu(opt, rcu);
2039 }
2040
2041 return hdr_delta;
2042 }
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052 void cipso_v4_sock_delattr(struct sock *sk)
2053 {
2054 struct inet_sock *sk_inet;
2055 int hdr_delta;
2056
2057 sk_inet = inet_sk(sk);
2058
2059 hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt);
2060 if (sk_inet->is_icsk && hdr_delta > 0) {
2061 struct inet_connection_sock *sk_conn = inet_csk(sk);
2062 sk_conn->icsk_ext_hdr_len -= hdr_delta;
2063 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
2064 }
2065 }
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075 void cipso_v4_req_delattr(struct request_sock *req)
2076 {
2077 cipso_v4_delopt(&inet_rsk(req)->ireq_opt);
2078 }
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090 int cipso_v4_getattr(const unsigned char *cipso,
2091 struct netlbl_lsm_secattr *secattr)
2092 {
2093 int ret_val = -ENOMSG;
2094 u32 doi;
2095 struct cipso_v4_doi *doi_def;
2096
2097 if (cipso_v4_cache_check(cipso, cipso[1], secattr) == 0)
2098 return 0;
2099
2100 doi = get_unaligned_be32(&cipso[2]);
2101 rcu_read_lock();
2102 doi_def = cipso_v4_doi_search(doi);
2103 if (!doi_def)
2104 goto getattr_return;
2105
2106
2107
2108 switch (cipso[6]) {
2109 case CIPSO_V4_TAG_RBITMAP:
2110 ret_val = cipso_v4_parsetag_rbm(doi_def, &cipso[6], secattr);
2111 break;
2112 case CIPSO_V4_TAG_ENUM:
2113 ret_val = cipso_v4_parsetag_enum(doi_def, &cipso[6], secattr);
2114 break;
2115 case CIPSO_V4_TAG_RANGE:
2116 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
2117 break;
2118 case CIPSO_V4_TAG_LOCAL:
2119 ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
2120 break;
2121 }
2122 if (ret_val == 0)
2123 secattr->type = NETLBL_NLTYPE_CIPSOV4;
2124
2125 getattr_return:
2126 rcu_read_unlock();
2127 return ret_val;
2128 }
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
2143 {
2144 struct ip_options_rcu *opt;
2145 int res = -ENOMSG;
2146
2147 rcu_read_lock();
2148 opt = rcu_dereference(inet_sk(sk)->inet_opt);
2149 if (opt && opt->opt.cipso)
2150 res = cipso_v4_getattr(opt->opt.__data +
2151 opt->opt.cipso -
2152 sizeof(struct iphdr),
2153 secattr);
2154 rcu_read_unlock();
2155 return res;
2156 }
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168 int cipso_v4_skbuff_setattr(struct sk_buff *skb,
2169 const struct cipso_v4_doi *doi_def,
2170 const struct netlbl_lsm_secattr *secattr)
2171 {
2172 int ret_val;
2173 struct iphdr *iph;
2174 struct ip_options *opt = &IPCB(skb)->opt;
2175 unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
2176 u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
2177 u32 opt_len;
2178 int len_delta;
2179
2180 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
2181 if (ret_val < 0)
2182 return ret_val;
2183 buf_len = ret_val;
2184 opt_len = (buf_len + 3) & ~3;
2185
2186
2187
2188
2189
2190
2191
2192 len_delta = opt_len - opt->optlen;
2193
2194
2195
2196 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
2197 if (ret_val < 0)
2198 return ret_val;
2199
2200 if (len_delta > 0) {
2201
2202
2203 iph = ip_hdr(skb);
2204 skb_push(skb, len_delta);
2205 memmove((char *)iph - len_delta, iph, iph->ihl << 2);
2206 skb_reset_network_header(skb);
2207 iph = ip_hdr(skb);
2208 } else if (len_delta < 0) {
2209 iph = ip_hdr(skb);
2210 memset(iph + 1, IPOPT_NOP, opt->optlen);
2211 } else
2212 iph = ip_hdr(skb);
2213
2214 if (opt->optlen > 0)
2215 memset(opt, 0, sizeof(*opt));
2216 opt->optlen = opt_len;
2217 opt->cipso = sizeof(struct iphdr);
2218 opt->is_changed = 1;
2219
2220
2221
2222
2223
2224
2225 memcpy(iph + 1, buf, buf_len);
2226 if (opt_len > buf_len)
2227 memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
2228 if (len_delta != 0) {
2229 iph->ihl = 5 + (opt_len >> 2);
2230 iph->tot_len = htons(skb->len);
2231 }
2232 ip_send_check(iph);
2233
2234 return 0;
2235 }
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246 int cipso_v4_skbuff_delattr(struct sk_buff *skb)
2247 {
2248 int ret_val;
2249 struct iphdr *iph;
2250 struct ip_options *opt = &IPCB(skb)->opt;
2251 unsigned char *cipso_ptr;
2252
2253 if (opt->cipso == 0)
2254 return 0;
2255
2256
2257 ret_val = skb_cow(skb, skb_headroom(skb));
2258 if (ret_val < 0)
2259 return ret_val;
2260
2261
2262
2263
2264
2265 iph = ip_hdr(skb);
2266 cipso_ptr = (unsigned char *)iph + opt->cipso;
2267 memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
2268 opt->cipso = 0;
2269 opt->is_changed = 1;
2270
2271 ip_send_check(iph);
2272
2273 return 0;
2274 }
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288 static int __init cipso_v4_init(void)
2289 {
2290 int ret_val;
2291
2292 ret_val = cipso_v4_cache_init();
2293 if (ret_val != 0)
2294 panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
2295 ret_val);
2296
2297 return 0;
2298 }
2299
2300 subsys_initcall(cipso_v4_init);