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
47static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
48static LIST_HEAD(cipso_v4_doi_list);
49
50
51int cipso_v4_cache_enabled = 1;
52int 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
56struct cipso_v4_map_cache_bkt {
57 spinlock_t lock;
58 u32 size;
59 struct list_head list;
60};
61
62struct 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
73static struct cipso_v4_map_cache_bkt *cipso_v4_cache;
74
75
76int cipso_v4_rbm_optfmt = 0;
77int 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
132static 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
149static 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
167static 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
194void 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
234static 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
297int 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
340cache_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
359static 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
382int 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
430doi_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
464void 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
490static 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
509int 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
534doi_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
557struct 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
568doi_getdef_return:
569 rcu_read_unlock();
570 return doi_def;
571}
572
573
574
575
576
577
578
579
580
581void 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
609int 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
629doi_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
650static 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
677static 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
709static 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
744static 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
792static 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
853static 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
915static 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
950static 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
985static 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
1016static 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
1058static 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
1117static 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
1159static 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
1182static 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
1237static 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
1280static 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
1329static 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
1371static 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
1419static 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
1462static 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
1488static 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
1507unsigned 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
1556int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
1557{
1558 unsigned char *opt = *option;
1559 unsigned char *tag;
1560 unsigned char opt_iter;
1561 unsigned char err_offset = 0;
1562 u8 opt_len;
1563 u8 tag_len;
1564 struct cipso_v4_doi *doi_def = NULL;
1565 u32 tag_iter;
1566
1567
1568 opt_len = opt[1];
1569 if (opt_len < 8) {
1570 err_offset = 1;
1571 goto validate_return;
1572 }
1573
1574 rcu_read_lock();
1575 doi_def = cipso_v4_doi_search(get_unaligned_be32(&opt[2]));
1576 if (!doi_def) {
1577 err_offset = 2;
1578 goto validate_return_locked;
1579 }
1580
1581 opt_iter = CIPSO_V4_HDR_LEN;
1582 tag = opt + opt_iter;
1583 while (opt_iter < opt_len) {
1584 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
1585 if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
1586 ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
1587 err_offset = opt_iter;
1588 goto validate_return_locked;
1589 }
1590
1591 if (opt_iter + 1 == opt_len) {
1592 err_offset = opt_iter;
1593 goto validate_return_locked;
1594 }
1595 tag_len = tag[1];
1596 if (tag_len > (opt_len - opt_iter)) {
1597 err_offset = opt_iter + 1;
1598 goto validate_return_locked;
1599 }
1600
1601 switch (tag[0]) {
1602 case CIPSO_V4_TAG_RBITMAP:
1603 if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
1604 err_offset = opt_iter + 1;
1605 goto validate_return_locked;
1606 }
1607
1608
1609
1610
1611
1612
1613
1614
1615 if (cipso_v4_rbm_strictvalid) {
1616 if (cipso_v4_map_lvl_valid(doi_def,
1617 tag[3]) < 0) {
1618 err_offset = opt_iter + 3;
1619 goto validate_return_locked;
1620 }
1621 if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
1622 cipso_v4_map_cat_rbm_valid(doi_def,
1623 &tag[4],
1624 tag_len - 4) < 0) {
1625 err_offset = opt_iter + 4;
1626 goto validate_return_locked;
1627 }
1628 }
1629 break;
1630 case CIPSO_V4_TAG_ENUM:
1631 if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
1632 err_offset = opt_iter + 1;
1633 goto validate_return_locked;
1634 }
1635
1636 if (cipso_v4_map_lvl_valid(doi_def,
1637 tag[3]) < 0) {
1638 err_offset = opt_iter + 3;
1639 goto validate_return_locked;
1640 }
1641 if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
1642 cipso_v4_map_cat_enum_valid(doi_def,
1643 &tag[4],
1644 tag_len - 4) < 0) {
1645 err_offset = opt_iter + 4;
1646 goto validate_return_locked;
1647 }
1648 break;
1649 case CIPSO_V4_TAG_RANGE:
1650 if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
1651 err_offset = opt_iter + 1;
1652 goto validate_return_locked;
1653 }
1654
1655 if (cipso_v4_map_lvl_valid(doi_def,
1656 tag[3]) < 0) {
1657 err_offset = opt_iter + 3;
1658 goto validate_return_locked;
1659 }
1660 if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
1661 cipso_v4_map_cat_rng_valid(doi_def,
1662 &tag[4],
1663 tag_len - 4) < 0) {
1664 err_offset = opt_iter + 4;
1665 goto validate_return_locked;
1666 }
1667 break;
1668 case CIPSO_V4_TAG_LOCAL:
1669
1670
1671
1672
1673
1674 if (!skb || !(skb->dev->flags & IFF_LOOPBACK)) {
1675 err_offset = opt_iter;
1676 goto validate_return_locked;
1677 }
1678 if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
1679 err_offset = opt_iter + 1;
1680 goto validate_return_locked;
1681 }
1682 break;
1683 default:
1684 err_offset = opt_iter;
1685 goto validate_return_locked;
1686 }
1687
1688 tag += tag_len;
1689 opt_iter += tag_len;
1690 }
1691
1692validate_return_locked:
1693 rcu_read_unlock();
1694validate_return:
1695 *option = opt + err_offset;
1696 return err_offset;
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
1726void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1727{
1728 unsigned char optbuf[sizeof(struct ip_options) + 40];
1729 struct ip_options *opt = (struct ip_options *)optbuf;
1730 int res;
1731
1732 if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
1733 return;
1734
1735
1736
1737
1738
1739
1740 memset(opt, 0, sizeof(struct ip_options));
1741 opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
1742 rcu_read_lock();
1743 res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL);
1744 rcu_read_unlock();
1745
1746 if (res)
1747 return;
1748
1749 if (gateway)
1750 __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, opt);
1751 else
1752 __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, opt);
1753}
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
1769 const struct cipso_v4_doi *doi_def,
1770 const struct netlbl_lsm_secattr *secattr)
1771{
1772 int ret_val;
1773 u32 iter;
1774
1775 if (buf_len <= CIPSO_V4_HDR_LEN)
1776 return -ENOSPC;
1777
1778
1779
1780
1781 iter = 0;
1782 do {
1783 memset(buf, 0, buf_len);
1784 switch (doi_def->tags[iter]) {
1785 case CIPSO_V4_TAG_RBITMAP:
1786 ret_val = cipso_v4_gentag_rbm(doi_def,
1787 secattr,
1788 &buf[CIPSO_V4_HDR_LEN],
1789 buf_len - CIPSO_V4_HDR_LEN);
1790 break;
1791 case CIPSO_V4_TAG_ENUM:
1792 ret_val = cipso_v4_gentag_enum(doi_def,
1793 secattr,
1794 &buf[CIPSO_V4_HDR_LEN],
1795 buf_len - CIPSO_V4_HDR_LEN);
1796 break;
1797 case CIPSO_V4_TAG_RANGE:
1798 ret_val = cipso_v4_gentag_rng(doi_def,
1799 secattr,
1800 &buf[CIPSO_V4_HDR_LEN],
1801 buf_len - CIPSO_V4_HDR_LEN);
1802 break;
1803 case CIPSO_V4_TAG_LOCAL:
1804 ret_val = cipso_v4_gentag_loc(doi_def,
1805 secattr,
1806 &buf[CIPSO_V4_HDR_LEN],
1807 buf_len - CIPSO_V4_HDR_LEN);
1808 break;
1809 default:
1810 return -EPERM;
1811 }
1812
1813 iter++;
1814 } while (ret_val < 0 &&
1815 iter < CIPSO_V4_TAG_MAXCNT &&
1816 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1817 if (ret_val < 0)
1818 return ret_val;
1819 cipso_v4_gentag_hdr(doi_def, buf, ret_val);
1820 return CIPSO_V4_HDR_LEN + ret_val;
1821}
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837int cipso_v4_sock_setattr(struct sock *sk,
1838 const struct cipso_v4_doi *doi_def,
1839 const struct netlbl_lsm_secattr *secattr)
1840{
1841 int ret_val = -EPERM;
1842 unsigned char *buf = NULL;
1843 u32 buf_len;
1844 u32 opt_len;
1845 struct ip_options_rcu *old, *opt = NULL;
1846 struct inet_sock *sk_inet;
1847 struct inet_connection_sock *sk_conn;
1848
1849
1850
1851
1852
1853 if (!sk)
1854 return 0;
1855
1856
1857
1858
1859 buf_len = CIPSO_V4_OPT_LEN_MAX;
1860 buf = kmalloc(buf_len, GFP_ATOMIC);
1861 if (!buf) {
1862 ret_val = -ENOMEM;
1863 goto socket_setattr_failure;
1864 }
1865
1866 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1867 if (ret_val < 0)
1868 goto socket_setattr_failure;
1869 buf_len = ret_val;
1870
1871
1872
1873
1874
1875 opt_len = (buf_len + 3) & ~3;
1876 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1877 if (!opt) {
1878 ret_val = -ENOMEM;
1879 goto socket_setattr_failure;
1880 }
1881 memcpy(opt->opt.__data, buf, buf_len);
1882 opt->opt.optlen = opt_len;
1883 opt->opt.cipso = sizeof(struct iphdr);
1884 kfree(buf);
1885 buf = NULL;
1886
1887 sk_inet = inet_sk(sk);
1888
1889 old = rcu_dereference_protected(sk_inet->inet_opt,
1890 lockdep_sock_is_held(sk));
1891 if (sk_inet->is_icsk) {
1892 sk_conn = inet_csk(sk);
1893 if (old)
1894 sk_conn->icsk_ext_hdr_len -= old->opt.optlen;
1895 sk_conn->icsk_ext_hdr_len += opt->opt.optlen;
1896 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
1897 }
1898 rcu_assign_pointer(sk_inet->inet_opt, opt);
1899 if (old)
1900 kfree_rcu(old, rcu);
1901
1902 return 0;
1903
1904socket_setattr_failure:
1905 kfree(buf);
1906 kfree(opt);
1907 return ret_val;
1908}
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922int cipso_v4_req_setattr(struct request_sock *req,
1923 const struct cipso_v4_doi *doi_def,
1924 const struct netlbl_lsm_secattr *secattr)
1925{
1926 int ret_val = -EPERM;
1927 unsigned char *buf = NULL;
1928 u32 buf_len;
1929 u32 opt_len;
1930 struct ip_options_rcu *opt = NULL;
1931 struct inet_request_sock *req_inet;
1932
1933
1934
1935
1936 buf_len = CIPSO_V4_OPT_LEN_MAX;
1937 buf = kmalloc(buf_len, GFP_ATOMIC);
1938 if (!buf) {
1939 ret_val = -ENOMEM;
1940 goto req_setattr_failure;
1941 }
1942
1943 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1944 if (ret_val < 0)
1945 goto req_setattr_failure;
1946 buf_len = ret_val;
1947
1948
1949
1950
1951
1952 opt_len = (buf_len + 3) & ~3;
1953 opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1954 if (!opt) {
1955 ret_val = -ENOMEM;
1956 goto req_setattr_failure;
1957 }
1958 memcpy(opt->opt.__data, buf, buf_len);
1959 opt->opt.optlen = opt_len;
1960 opt->opt.cipso = sizeof(struct iphdr);
1961 kfree(buf);
1962 buf = NULL;
1963
1964 req_inet = inet_rsk(req);
1965 opt = xchg((__force struct ip_options_rcu **)&req_inet->ireq_opt, opt);
1966 if (opt)
1967 kfree_rcu(opt, rcu);
1968
1969 return 0;
1970
1971req_setattr_failure:
1972 kfree(buf);
1973 kfree(opt);
1974 return ret_val;
1975}
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987static int cipso_v4_delopt(struct ip_options_rcu __rcu **opt_ptr)
1988{
1989 struct ip_options_rcu *opt = rcu_dereference_protected(*opt_ptr, 1);
1990 int hdr_delta = 0;
1991
1992 if (!opt || opt->opt.cipso == 0)
1993 return 0;
1994 if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) {
1995 u8 cipso_len;
1996 u8 cipso_off;
1997 unsigned char *cipso_ptr;
1998 int iter;
1999 int optlen_new;
2000
2001 cipso_off = opt->opt.cipso - sizeof(struct iphdr);
2002 cipso_ptr = &opt->opt.__data[cipso_off];
2003 cipso_len = cipso_ptr[1];
2004
2005 if (opt->opt.srr > opt->opt.cipso)
2006 opt->opt.srr -= cipso_len;
2007 if (opt->opt.rr > opt->opt.cipso)
2008 opt->opt.rr -= cipso_len;
2009 if (opt->opt.ts > opt->opt.cipso)
2010 opt->opt.ts -= cipso_len;
2011 if (opt->opt.router_alert > opt->opt.cipso)
2012 opt->opt.router_alert -= cipso_len;
2013 opt->opt.cipso = 0;
2014
2015 memmove(cipso_ptr, cipso_ptr + cipso_len,
2016 opt->opt.optlen - cipso_off - cipso_len);
2017
2018
2019
2020
2021
2022
2023 iter = 0;
2024 optlen_new = 0;
2025 while (iter < opt->opt.optlen)
2026 if (opt->opt.__data[iter] != IPOPT_NOP) {
2027 iter += opt->opt.__data[iter + 1];
2028 optlen_new = iter;
2029 } else
2030 iter++;
2031 hdr_delta = opt->opt.optlen;
2032 opt->opt.optlen = (optlen_new + 3) & ~3;
2033 hdr_delta -= opt->opt.optlen;
2034 } else {
2035
2036
2037 *opt_ptr = NULL;
2038 hdr_delta = opt->opt.optlen;
2039 kfree_rcu(opt, rcu);
2040 }
2041
2042 return hdr_delta;
2043}
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053void cipso_v4_sock_delattr(struct sock *sk)
2054{
2055 struct inet_sock *sk_inet;
2056 int hdr_delta;
2057
2058 sk_inet = inet_sk(sk);
2059
2060 hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt);
2061 if (sk_inet->is_icsk && hdr_delta > 0) {
2062 struct inet_connection_sock *sk_conn = inet_csk(sk);
2063 sk_conn->icsk_ext_hdr_len -= hdr_delta;
2064 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
2065 }
2066}
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076void cipso_v4_req_delattr(struct request_sock *req)
2077{
2078 cipso_v4_delopt(&inet_rsk(req)->ireq_opt);
2079}
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091int cipso_v4_getattr(const unsigned char *cipso,
2092 struct netlbl_lsm_secattr *secattr)
2093{
2094 int ret_val = -ENOMSG;
2095 u32 doi;
2096 struct cipso_v4_doi *doi_def;
2097
2098 if (cipso_v4_cache_check(cipso, cipso[1], secattr) == 0)
2099 return 0;
2100
2101 doi = get_unaligned_be32(&cipso[2]);
2102 rcu_read_lock();
2103 doi_def = cipso_v4_doi_search(doi);
2104 if (!doi_def)
2105 goto getattr_return;
2106
2107
2108
2109 switch (cipso[6]) {
2110 case CIPSO_V4_TAG_RBITMAP:
2111 ret_val = cipso_v4_parsetag_rbm(doi_def, &cipso[6], secattr);
2112 break;
2113 case CIPSO_V4_TAG_ENUM:
2114 ret_val = cipso_v4_parsetag_enum(doi_def, &cipso[6], secattr);
2115 break;
2116 case CIPSO_V4_TAG_RANGE:
2117 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
2118 break;
2119 case CIPSO_V4_TAG_LOCAL:
2120 ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
2121 break;
2122 }
2123 if (ret_val == 0)
2124 secattr->type = NETLBL_NLTYPE_CIPSOV4;
2125
2126getattr_return:
2127 rcu_read_unlock();
2128 return ret_val;
2129}
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
2144{
2145 struct ip_options_rcu *opt;
2146 int res = -ENOMSG;
2147
2148 rcu_read_lock();
2149 opt = rcu_dereference(inet_sk(sk)->inet_opt);
2150 if (opt && opt->opt.cipso)
2151 res = cipso_v4_getattr(opt->opt.__data +
2152 opt->opt.cipso -
2153 sizeof(struct iphdr),
2154 secattr);
2155 rcu_read_unlock();
2156 return res;
2157}
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170int cipso_v4_skbuff_setattr(struct sk_buff *skb,
2171 const struct cipso_v4_doi *doi_def,
2172 const struct netlbl_lsm_secattr *secattr)
2173{
2174 int ret_val;
2175 struct iphdr *iph;
2176 struct ip_options *opt = &IPCB(skb)->opt;
2177 unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
2178 u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
2179 u32 opt_len;
2180 int len_delta;
2181
2182 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
2183 if (ret_val < 0)
2184 return ret_val;
2185 buf_len = ret_val;
2186 opt_len = (buf_len + 3) & ~3;
2187
2188
2189
2190
2191
2192
2193
2194 len_delta = opt_len - opt->optlen;
2195
2196
2197
2198 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
2199 if (ret_val < 0)
2200 return ret_val;
2201
2202 if (len_delta > 0) {
2203
2204
2205 iph = ip_hdr(skb);
2206 skb_push(skb, len_delta);
2207 memmove((char *)iph - len_delta, iph, iph->ihl << 2);
2208 skb_reset_network_header(skb);
2209 iph = ip_hdr(skb);
2210 } else if (len_delta < 0) {
2211 iph = ip_hdr(skb);
2212 memset(iph + 1, IPOPT_NOP, opt->optlen);
2213 } else
2214 iph = ip_hdr(skb);
2215
2216 if (opt->optlen > 0)
2217 memset(opt, 0, sizeof(*opt));
2218 opt->optlen = opt_len;
2219 opt->cipso = sizeof(struct iphdr);
2220 opt->is_changed = 1;
2221
2222
2223
2224
2225
2226
2227 memcpy(iph + 1, buf, buf_len);
2228 if (opt_len > buf_len)
2229 memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
2230 if (len_delta != 0) {
2231 iph->ihl = 5 + (opt_len >> 2);
2232 iph->tot_len = htons(skb->len);
2233 }
2234 ip_send_check(iph);
2235
2236 return 0;
2237}
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248int cipso_v4_skbuff_delattr(struct sk_buff *skb)
2249{
2250 int ret_val;
2251 struct iphdr *iph;
2252 struct ip_options *opt = &IPCB(skb)->opt;
2253 unsigned char *cipso_ptr;
2254
2255 if (opt->cipso == 0)
2256 return 0;
2257
2258
2259 ret_val = skb_cow(skb, skb_headroom(skb));
2260 if (ret_val < 0)
2261 return ret_val;
2262
2263
2264
2265
2266
2267 iph = ip_hdr(skb);
2268 cipso_ptr = (unsigned char *)iph + opt->cipso;
2269 memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
2270 opt->cipso = 0;
2271 opt->is_changed = 1;
2272
2273 ip_send_check(iph);
2274
2275 return 0;
2276}
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290static int __init cipso_v4_init(void)
2291{
2292 int ret_val;
2293
2294 ret_val = cipso_v4_cache_init();
2295 if (ret_val != 0)
2296 panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
2297 ret_val);
2298
2299 return 0;
2300}
2301
2302subsys_initcall(cipso_v4_init);
2303