aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/cipso_ipv4.c656
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/netlabel/Makefile3
-rw-r--r--net/netlabel/netlabel_addrlist.c388
-rw-r--r--net/netlabel/netlabel_addrlist.h189
-rw-r--r--net/netlabel/netlabel_cipso_v4.c136
-rw-r--r--net/netlabel/netlabel_cipso_v4.h10
-rw-r--r--net/netlabel/netlabel_domainhash.c393
-rw-r--r--net/netlabel/netlabel_domainhash.h40
-rw-r--r--net/netlabel/netlabel_kapi.c272
-rw-r--r--net/netlabel/netlabel_mgmt.c410
-rw-r--r--net/netlabel/netlabel_mgmt.h59
-rw-r--r--net/netlabel/netlabel_unlabeled.c456
13 files changed, 2186 insertions, 828 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2c0e4572cc90..490e035c6d90 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -13,7 +13,7 @@
13 */ 13 */
14 14
15/* 15/*
16 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 16 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
17 * 17 *
18 * This program is free software; you can redistribute it and/or modify 18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by 19 * it under the terms of the GNU General Public License as published by
@@ -47,17 +47,7 @@
47#include <asm/bug.h> 47#include <asm/bug.h>
48#include <asm/unaligned.h> 48#include <asm/unaligned.h>
49 49
50struct cipso_v4_domhsh_entry {
51 char *domain;
52 u32 valid;
53 struct list_head list;
54 struct rcu_head rcu;
55};
56
57/* List of available DOI definitions */ 50/* List of available DOI definitions */
58/* XXX - Updates should be minimal so having a single lock for the
59 * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
60 * okay. */
61/* XXX - This currently assumes a minimal number of different DOIs in use, 51/* XXX - This currently assumes a minimal number of different DOIs in use,
62 * if in practice there are a lot of different DOIs this list should 52 * if in practice there are a lot of different DOIs this list should
63 * probably be turned into a hash table or something similar so we 53 * probably be turned into a hash table or something similar so we
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1;
119 * be omitted. */ 109 * be omitted. */
120#define CIPSO_V4_TAG_RNG_CAT_MAX 8 110#define CIPSO_V4_TAG_RNG_CAT_MAX 8
121 111
112/* Base length of the local tag (non-standard tag).
113 * Tag definition (may change between kernel versions)
114 *
115 * 0 8 16 24 32
116 * +----------+----------+----------+----------+
117 * | 10000000 | 00000110 | 32-bit secid value |
118 * +----------+----------+----------+----------+
119 * | in (host byte order)|
120 * +----------+----------+
121 *
122 */
123#define CIPSO_V4_TAG_LOC_BLEN 6
124
122/* 125/*
123 * Helper Functions 126 * Helper Functions
124 */ 127 */
@@ -194,25 +197,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
194} 197}
195 198
196/** 199/**
197 * cipso_v4_doi_domhsh_free - Frees a domain list entry
198 * @entry: the entry's RCU field
199 *
200 * Description:
201 * This function is designed to be used as a callback to the call_rcu()
202 * function so that the memory allocated to a domain list entry can be released
203 * safely.
204 *
205 */
206static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
207{
208 struct cipso_v4_domhsh_entry *ptr;
209
210 ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
211 kfree(ptr->domain);
212 kfree(ptr);
213}
214
215/**
216 * cipso_v4_cache_entry_free - Frees a cache entry 200 * cipso_v4_cache_entry_free - Frees a cache entry
217 * @entry: the entry to free 201 * @entry: the entry to free
218 * 202 *
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
457 struct cipso_v4_doi *iter; 441 struct cipso_v4_doi *iter;
458 442
459 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) 443 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
460 if (iter->doi == doi && iter->valid) 444 if (iter->doi == doi && atomic_read(&iter->refcount))
461 return iter; 445 return iter;
462 return NULL; 446 return NULL;
463} 447}
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
496 if (doi_def->type != CIPSO_V4_MAP_PASS) 480 if (doi_def->type != CIPSO_V4_MAP_PASS)
497 return -EINVAL; 481 return -EINVAL;
498 break; 482 break;
483 case CIPSO_V4_TAG_LOCAL:
484 if (doi_def->type != CIPSO_V4_MAP_LOCAL)
485 return -EINVAL;
486 break;
499 default: 487 default:
500 return -EINVAL; 488 return -EINVAL;
501 } 489 }
502 } 490 }
503 491
504 doi_def->valid = 1; 492 atomic_set(&doi_def->refcount, 1);
505 INIT_RCU_HEAD(&doi_def->rcu); 493 INIT_RCU_HEAD(&doi_def->rcu);
506 INIT_LIST_HEAD(&doi_def->dom_list);
507 494
508 spin_lock(&cipso_v4_doi_list_lock); 495 spin_lock(&cipso_v4_doi_list_lock);
509 if (cipso_v4_doi_search(doi_def->doi) != NULL) 496 if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -519,59 +506,129 @@ doi_add_failure:
519} 506}
520 507
521/** 508/**
509 * cipso_v4_doi_free - Frees a DOI definition
510 * @entry: the entry's RCU field
511 *
512 * Description:
513 * This function frees all of the memory associated with a DOI definition.
514 *
515 */
516void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
517{
518 if (doi_def == NULL)
519 return;
520
521 switch (doi_def->type) {
522 case CIPSO_V4_MAP_TRANS:
523 kfree(doi_def->map.std->lvl.cipso);
524 kfree(doi_def->map.std->lvl.local);
525 kfree(doi_def->map.std->cat.cipso);
526 kfree(doi_def->map.std->cat.local);
527 break;
528 }
529 kfree(doi_def);
530}
531
532/**
533 * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
534 * @entry: the entry's RCU field
535 *
536 * Description:
537 * This function is designed to be used as a callback to the call_rcu()
538 * function so that the memory allocated to the DOI definition can be released
539 * safely.
540 *
541 */
542static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
543{
544 struct cipso_v4_doi *doi_def;
545
546 doi_def = container_of(entry, struct cipso_v4_doi, rcu);
547 cipso_v4_doi_free(doi_def);
548}
549
550/**
522 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine 551 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
523 * @doi: the DOI value 552 * @doi: the DOI value
524 * @audit_secid: the LSM secid to use in the audit message 553 * @audit_secid: the LSM secid to use in the audit message
525 * @callback: the DOI cleanup/free callback
526 * 554 *
527 * Description: 555 * Description:
528 * Removes a DOI definition from the CIPSO engine, @callback is called to 556 * Removes a DOI definition from the CIPSO engine. The NetLabel routines will
529 * free any memory. The NetLabel routines will be called to release their own 557 * be called to release their own LSM domain mappings as well as our own
530 * LSM domain mappings as well as our own domain list. Returns zero on 558 * domain list. Returns zero on success and negative values on failure.
531 * success and negative values on failure.
532 * 559 *
533 */ 560 */
534int cipso_v4_doi_remove(u32 doi, 561int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
535 struct netlbl_audit *audit_info,
536 void (*callback) (struct rcu_head * head))
537{ 562{
538 struct cipso_v4_doi *doi_def; 563 struct cipso_v4_doi *doi_def;
539 struct cipso_v4_domhsh_entry *dom_iter;
540 564
541 spin_lock(&cipso_v4_doi_list_lock); 565 spin_lock(&cipso_v4_doi_list_lock);
542 doi_def = cipso_v4_doi_search(doi); 566 doi_def = cipso_v4_doi_search(doi);
543 if (doi_def != NULL) { 567 if (doi_def == NULL) {
544 doi_def->valid = 0;
545 list_del_rcu(&doi_def->list);
546 spin_unlock(&cipso_v4_doi_list_lock); 568 spin_unlock(&cipso_v4_doi_list_lock);
547 rcu_read_lock(); 569 return -ENOENT;
548 list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) 570 }
549 if (dom_iter->valid) 571 if (!atomic_dec_and_test(&doi_def->refcount)) {
550 netlbl_cfg_map_del(dom_iter->domain, 572 spin_unlock(&cipso_v4_doi_list_lock);
551 audit_info); 573 return -EBUSY;
552 rcu_read_unlock();
553 cipso_v4_cache_invalidate();
554 call_rcu(&doi_def->rcu, callback);
555 return 0;
556 } 574 }
575 list_del_rcu(&doi_def->list);
557 spin_unlock(&cipso_v4_doi_list_lock); 576 spin_unlock(&cipso_v4_doi_list_lock);
558 577
559 return -ENOENT; 578 cipso_v4_cache_invalidate();
579 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
580
581 return 0;
560} 582}
561 583
562/** 584/**
563 * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition 585 * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
564 * @doi: the DOI value 586 * @doi: the DOI value
565 * 587 *
566 * Description: 588 * Description:
567 * Searches for a valid DOI definition and if one is found it is returned to 589 * Searches for a valid DOI definition and if one is found it is returned to
568 * the caller. Otherwise NULL is returned. The caller must ensure that 590 * the caller. Otherwise NULL is returned. The caller must ensure that
569 * rcu_read_lock() is held while accessing the returned definition. 591 * rcu_read_lock() is held while accessing the returned definition and the DOI
592 * definition reference count is decremented when the caller is done.
570 * 593 *
571 */ 594 */
572struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) 595struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
573{ 596{
574 return cipso_v4_doi_search(doi); 597 struct cipso_v4_doi *doi_def;
598
599 rcu_read_lock();
600 doi_def = cipso_v4_doi_search(doi);
601 if (doi_def == NULL)
602 goto doi_getdef_return;
603 if (!atomic_inc_not_zero(&doi_def->refcount))
604 doi_def = NULL;
605
606doi_getdef_return:
607 rcu_read_unlock();
608 return doi_def;
609}
610
611/**
612 * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
613 * @doi_def: the DOI definition
614 *
615 * Description:
616 * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
617 *
618 */
619void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
620{
621 if (doi_def == NULL)
622 return;
623
624 if (!atomic_dec_and_test(&doi_def->refcount))
625 return;
626 spin_lock(&cipso_v4_doi_list_lock);
627 list_del_rcu(&doi_def->list);
628 spin_unlock(&cipso_v4_doi_list_lock);
629
630 cipso_v4_cache_invalidate();
631 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
575} 632}
576 633
577/** 634/**
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
597 654
598 rcu_read_lock(); 655 rcu_read_lock();
599 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) 656 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
600 if (iter_doi->valid) { 657 if (atomic_read(&iter_doi->refcount) > 0) {
601 if (doi_cnt++ < *skip_cnt) 658 if (doi_cnt++ < *skip_cnt)
602 continue; 659 continue;
603 ret_val = callback(iter_doi, cb_arg); 660 ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +670,6 @@ doi_walk_return:
613 return ret_val; 670 return ret_val;
614} 671}
615 672
616/**
617 * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
618 * @doi_def: the DOI definition
619 * @domain: the domain to add
620 *
621 * Description:
622 * Adds the @domain to the DOI specified by @doi_def, this function
623 * should only be called by external functions (i.e. NetLabel). This function
624 * does allocate memory. Returns zero on success, negative values on failure.
625 *
626 */
627int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
628{
629 struct cipso_v4_domhsh_entry *iter;
630 struct cipso_v4_domhsh_entry *new_dom;
631
632 new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
633 if (new_dom == NULL)
634 return -ENOMEM;
635 if (domain) {
636 new_dom->domain = kstrdup(domain, GFP_KERNEL);
637 if (new_dom->domain == NULL) {
638 kfree(new_dom);
639 return -ENOMEM;
640 }
641 }
642 new_dom->valid = 1;
643 INIT_RCU_HEAD(&new_dom->rcu);
644
645 spin_lock(&cipso_v4_doi_list_lock);
646 list_for_each_entry(iter, &doi_def->dom_list, list)
647 if (iter->valid &&
648 ((domain != NULL && iter->domain != NULL &&
649 strcmp(iter->domain, domain) == 0) ||
650 (domain == NULL && iter->domain == NULL))) {
651 spin_unlock(&cipso_v4_doi_list_lock);
652 kfree(new_dom->domain);
653 kfree(new_dom);
654 return -EEXIST;
655 }
656 list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
657 spin_unlock(&cipso_v4_doi_list_lock);
658
659 return 0;
660}
661
662/**
663 * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
664 * @doi_def: the DOI definition
665 * @domain: the domain to remove
666 *
667 * Description:
668 * Removes the @domain from the DOI specified by @doi_def, this function
669 * should only be called by external functions (i.e. NetLabel). Returns zero
670 * on success and negative values on error.
671 *
672 */
673int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
674 const char *domain)
675{
676 struct cipso_v4_domhsh_entry *iter;
677
678 spin_lock(&cipso_v4_doi_list_lock);
679 list_for_each_entry(iter, &doi_def->dom_list, list)
680 if (iter->valid &&
681 ((domain != NULL && iter->domain != NULL &&
682 strcmp(iter->domain, domain) == 0) ||
683 (domain == NULL && iter->domain == NULL))) {
684 iter->valid = 0;
685 list_del_rcu(&iter->list);
686 spin_unlock(&cipso_v4_doi_list_lock);
687 call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
688 return 0;
689 }
690 spin_unlock(&cipso_v4_doi_list_lock);
691
692 return -ENOENT;
693}
694
695/* 673/*
696 * Label Mapping Functions 674 * Label Mapping Functions
697 */ 675 */
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
712 switch (doi_def->type) { 690 switch (doi_def->type) {
713 case CIPSO_V4_MAP_PASS: 691 case CIPSO_V4_MAP_PASS:
714 return 0; 692 return 0;
715 case CIPSO_V4_MAP_STD: 693 case CIPSO_V4_MAP_TRANS:
716 if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) 694 if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
717 return 0; 695 return 0;
718 break; 696 break;
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
741 case CIPSO_V4_MAP_PASS: 719 case CIPSO_V4_MAP_PASS:
742 *net_lvl = host_lvl; 720 *net_lvl = host_lvl;
743 return 0; 721 return 0;
744 case CIPSO_V4_MAP_STD: 722 case CIPSO_V4_MAP_TRANS:
745 if (host_lvl < doi_def->map.std->lvl.local_size && 723 if (host_lvl < doi_def->map.std->lvl.local_size &&
746 doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) { 724 doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
747 *net_lvl = doi_def->map.std->lvl.local[host_lvl]; 725 *net_lvl = doi_def->map.std->lvl.local[host_lvl];
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
775 case CIPSO_V4_MAP_PASS: 753 case CIPSO_V4_MAP_PASS:
776 *host_lvl = net_lvl; 754 *host_lvl = net_lvl;
777 return 0; 755 return 0;
778 case CIPSO_V4_MAP_STD: 756 case CIPSO_V4_MAP_TRANS:
779 map_tbl = doi_def->map.std; 757 map_tbl = doi_def->map.std;
780 if (net_lvl < map_tbl->lvl.cipso_size && 758 if (net_lvl < map_tbl->lvl.cipso_size &&
781 map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { 759 map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
812 switch (doi_def->type) { 790 switch (doi_def->type) {
813 case CIPSO_V4_MAP_PASS: 791 case CIPSO_V4_MAP_PASS:
814 return 0; 792 return 0;
815 case CIPSO_V4_MAP_STD: 793 case CIPSO_V4_MAP_TRANS:
816 cipso_cat_size = doi_def->map.std->cat.cipso_size; 794 cipso_cat_size = doi_def->map.std->cat.cipso_size;
817 cipso_array = doi_def->map.std->cat.cipso; 795 cipso_array = doi_def->map.std->cat.cipso;
818 for (;;) { 796 for (;;) {
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
860 u32 host_cat_size = 0; 838 u32 host_cat_size = 0;
861 u32 *host_cat_array = NULL; 839 u32 *host_cat_array = NULL;
862 840
863 if (doi_def->type == CIPSO_V4_MAP_STD) { 841 if (doi_def->type == CIPSO_V4_MAP_TRANS) {
864 host_cat_size = doi_def->map.std->cat.local_size; 842 host_cat_size = doi_def->map.std->cat.local_size;
865 host_cat_array = doi_def->map.std->cat.local; 843 host_cat_array = doi_def->map.std->cat.local;
866 } 844 }
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
875 case CIPSO_V4_MAP_PASS: 853 case CIPSO_V4_MAP_PASS:
876 net_spot = host_spot; 854 net_spot = host_spot;
877 break; 855 break;
878 case CIPSO_V4_MAP_STD: 856 case CIPSO_V4_MAP_TRANS:
879 if (host_spot >= host_cat_size) 857 if (host_spot >= host_cat_size)
880 return -EPERM; 858 return -EPERM;
881 net_spot = host_cat_array[host_spot]; 859 net_spot = host_cat_array[host_spot];
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
921 u32 net_cat_size = 0; 899 u32 net_cat_size = 0;
922 u32 *net_cat_array = NULL; 900 u32 *net_cat_array = NULL;
923 901
924 if (doi_def->type == CIPSO_V4_MAP_STD) { 902 if (doi_def->type == CIPSO_V4_MAP_TRANS) {
925 net_cat_size = doi_def->map.std->cat.cipso_size; 903 net_cat_size = doi_def->map.std->cat.cipso_size;
926 net_cat_array = doi_def->map.std->cat.cipso; 904 net_cat_array = doi_def->map.std->cat.cipso;
927 } 905 }
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
941 case CIPSO_V4_MAP_PASS: 919 case CIPSO_V4_MAP_PASS:
942 host_spot = net_spot; 920 host_spot = net_spot;
943 break; 921 break;
944 case CIPSO_V4_MAP_STD: 922 case CIPSO_V4_MAP_TRANS:
945 if (net_spot >= net_cat_size) 923 if (net_spot >= net_cat_size)
946 return -EPERM; 924 return -EPERM;
947 host_spot = net_cat_array[net_spot]; 925 host_spot = net_cat_array[net_spot];
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
1277 } else 1255 } else
1278 tag_len = 4; 1256 tag_len = 4;
1279 1257
1280 buffer[0] = 0x01; 1258 buffer[0] = CIPSO_V4_TAG_RBITMAP;
1281 buffer[1] = tag_len; 1259 buffer[1] = tag_len;
1282 buffer[3] = level; 1260 buffer[3] = level;
1283 1261
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
1373 } else 1351 } else
1374 tag_len = 4; 1352 tag_len = 4;
1375 1353
1376 buffer[0] = 0x02; 1354 buffer[0] = CIPSO_V4_TAG_ENUM;
1377 buffer[1] = tag_len; 1355 buffer[1] = tag_len;
1378 buffer[3] = level; 1356 buffer[3] = level;
1379 1357
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
1469 } else 1447 } else
1470 tag_len = 4; 1448 tag_len = 4;
1471 1449
1472 buffer[0] = 0x05; 1450 buffer[0] = CIPSO_V4_TAG_RANGE;
1473 buffer[1] = tag_len; 1451 buffer[1] = tag_len;
1474 buffer[3] = level; 1452 buffer[3] = level;
1475 1453
@@ -1523,6 +1501,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1523} 1501}
1524 1502
1525/** 1503/**
1504 * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
1505 * @doi_def: the DOI definition
1506 * @secattr: the security attributes
1507 * @buffer: the option buffer
1508 * @buffer_len: length of buffer in bytes
1509 *
1510 * Description:
1511 * Generate a CIPSO option using the local tag. Returns the size of the tag
1512 * on success, negative values on failure.
1513 *
1514 */
1515static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
1516 const struct netlbl_lsm_secattr *secattr,
1517 unsigned char *buffer,
1518 u32 buffer_len)
1519{
1520 if (!(secattr->flags & NETLBL_SECATTR_SECID))
1521 return -EPERM;
1522
1523 buffer[0] = CIPSO_V4_TAG_LOCAL;
1524 buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
1525 *(u32 *)&buffer[2] = secattr->attr.secid;
1526
1527 return CIPSO_V4_TAG_LOC_BLEN;
1528}
1529
1530/**
1531 * cipso_v4_parsetag_loc - Parse a CIPSO local tag
1532 * @doi_def: the DOI definition
1533 * @tag: the CIPSO tag
1534 * @secattr: the security attributes
1535 *
1536 * Description:
1537 * Parse a CIPSO local tag and return the security attributes in @secattr.
1538 * Return zero on success, negatives values on failure.
1539 *
1540 */
1541static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
1542 const unsigned char *tag,
1543 struct netlbl_lsm_secattr *secattr)
1544{
1545 secattr->attr.secid = *(u32 *)&tag[2];
1546 secattr->flags |= NETLBL_SECATTR_SECID;
1547
1548 return 0;
1549}
1550
1551/**
1526 * cipso_v4_validate - Validate a CIPSO option 1552 * cipso_v4_validate - Validate a CIPSO option
1527 * @option: the start of the option, on error it is set to point to the error 1553 * @option: the start of the option, on error it is set to point to the error
1528 * 1554 *
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1541 * that is unrecognized." 1567 * that is unrecognized."
1542 * 1568 *
1543 */ 1569 */
1544int cipso_v4_validate(unsigned char **option) 1570int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
1545{ 1571{
1546 unsigned char *opt = *option; 1572 unsigned char *opt = *option;
1547 unsigned char *tag; 1573 unsigned char *tag;
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option)
1566 goto validate_return_locked; 1592 goto validate_return_locked;
1567 } 1593 }
1568 1594
1569 opt_iter = 6; 1595 opt_iter = CIPSO_V4_HDR_LEN;
1570 tag = opt + opt_iter; 1596 tag = opt + opt_iter;
1571 while (opt_iter < opt_len) { 1597 while (opt_iter < opt_len) {
1572 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) 1598 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option)
1584 1610
1585 switch (tag[0]) { 1611 switch (tag[0]) {
1586 case CIPSO_V4_TAG_RBITMAP: 1612 case CIPSO_V4_TAG_RBITMAP:
1587 if (tag_len < 4) { 1613 if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
1588 err_offset = opt_iter + 1; 1614 err_offset = opt_iter + 1;
1589 goto validate_return_locked; 1615 goto validate_return_locked;
1590 } 1616 }
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option)
1602 err_offset = opt_iter + 3; 1628 err_offset = opt_iter + 3;
1603 goto validate_return_locked; 1629 goto validate_return_locked;
1604 } 1630 }
1605 if (tag_len > 4 && 1631 if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
1606 cipso_v4_map_cat_rbm_valid(doi_def, 1632 cipso_v4_map_cat_rbm_valid(doi_def,
1607 &tag[4], 1633 &tag[4],
1608 tag_len - 4) < 0) { 1634 tag_len - 4) < 0) {
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option)
1612 } 1638 }
1613 break; 1639 break;
1614 case CIPSO_V4_TAG_ENUM: 1640 case CIPSO_V4_TAG_ENUM:
1615 if (tag_len < 4) { 1641 if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
1616 err_offset = opt_iter + 1; 1642 err_offset = opt_iter + 1;
1617 goto validate_return_locked; 1643 goto validate_return_locked;
1618 } 1644 }
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option)
1622 err_offset = opt_iter + 3; 1648 err_offset = opt_iter + 3;
1623 goto validate_return_locked; 1649 goto validate_return_locked;
1624 } 1650 }
1625 if (tag_len > 4 && 1651 if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
1626 cipso_v4_map_cat_enum_valid(doi_def, 1652 cipso_v4_map_cat_enum_valid(doi_def,
1627 &tag[4], 1653 &tag[4],
1628 tag_len - 4) < 0) { 1654 tag_len - 4) < 0) {
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option)
1631 } 1657 }
1632 break; 1658 break;
1633 case CIPSO_V4_TAG_RANGE: 1659 case CIPSO_V4_TAG_RANGE:
1634 if (tag_len < 4) { 1660 if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
1635 err_offset = opt_iter + 1; 1661 err_offset = opt_iter + 1;
1636 goto validate_return_locked; 1662 goto validate_return_locked;
1637 } 1663 }
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option)
1641 err_offset = opt_iter + 3; 1667 err_offset = opt_iter + 3;
1642 goto validate_return_locked; 1668 goto validate_return_locked;
1643 } 1669 }
1644 if (tag_len > 4 && 1670 if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
1645 cipso_v4_map_cat_rng_valid(doi_def, 1671 cipso_v4_map_cat_rng_valid(doi_def,
1646 &tag[4], 1672 &tag[4],
1647 tag_len - 4) < 0) { 1673 tag_len - 4) < 0) {
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option)
1649 goto validate_return_locked; 1675 goto validate_return_locked;
1650 } 1676 }
1651 break; 1677 break;
1678 case CIPSO_V4_TAG_LOCAL:
1679 /* This is a non-standard tag that we only allow for
1680 * local connections, so if the incoming interface is
1681 * not the loopback device drop the packet. */
1682 if (!(skb->dev->flags & IFF_LOOPBACK)) {
1683 err_offset = opt_iter;
1684 goto validate_return_locked;
1685 }
1686 if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
1687 err_offset = opt_iter + 1;
1688 goto validate_return_locked;
1689 }
1690 break;
1652 default: 1691 default:
1653 err_offset = opt_iter; 1692 err_offset = opt_iter;
1654 goto validate_return_locked; 1693 goto validate_return_locked;
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1704} 1743}
1705 1744
1706/** 1745/**
1707 * cipso_v4_sock_setattr - Add a CIPSO option to a socket 1746 * cipso_v4_genopt - Generate a CIPSO option
1708 * @sk: the socket 1747 * @buf: the option buffer
1748 * @buf_len: the size of opt_buf
1709 * @doi_def: the CIPSO DOI to use 1749 * @doi_def: the CIPSO DOI to use
1710 * @secattr: the specific security attributes of the socket 1750 * @secattr: the security attributes
1711 * 1751 *
1712 * Description: 1752 * Description:
1713 * Set the CIPSO option on the given socket using the DOI definition and 1753 * Generate a CIPSO option using the DOI definition and security attributes
1714 * security attributes passed to the function. This function requires 1754 * passed to the function. Returns the length of the option on success and
1715 * exclusive access to @sk, which means it either needs to be in the 1755 * negative values on failure.
1716 * process of being created or locked. Returns zero on success and negative
1717 * values on failure.
1718 * 1756 *
1719 */ 1757 */
1720int cipso_v4_sock_setattr(struct sock *sk, 1758static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
1721 const struct cipso_v4_doi *doi_def, 1759 const struct cipso_v4_doi *doi_def,
1722 const struct netlbl_lsm_secattr *secattr) 1760 const struct netlbl_lsm_secattr *secattr)
1723{ 1761{
1724 int ret_val = -EPERM; 1762 int ret_val;
1725 u32 iter; 1763 u32 iter;
1726 unsigned char *buf;
1727 u32 buf_len = 0;
1728 u32 opt_len;
1729 struct ip_options *opt = NULL;
1730 struct inet_sock *sk_inet;
1731 struct inet_connection_sock *sk_conn;
1732 1764
1733 /* In the case of sock_create_lite(), the sock->sk field is not 1765 if (buf_len <= CIPSO_V4_HDR_LEN)
1734 * defined yet but it is not a problem as the only users of these 1766 return -ENOSPC;
1735 * "lite" PF_INET sockets are functions which do an accept() call
1736 * afterwards so we will label the socket as part of the accept(). */
1737 if (sk == NULL)
1738 return 0;
1739
1740 /* We allocate the maximum CIPSO option size here so we are probably
1741 * being a little wasteful, but it makes our life _much_ easier later
1742 * on and after all we are only talking about 40 bytes. */
1743 buf_len = CIPSO_V4_OPT_LEN_MAX;
1744 buf = kmalloc(buf_len, GFP_ATOMIC);
1745 if (buf == NULL) {
1746 ret_val = -ENOMEM;
1747 goto socket_setattr_failure;
1748 }
1749 1767
1750 /* XXX - This code assumes only one tag per CIPSO option which isn't 1768 /* XXX - This code assumes only one tag per CIPSO option which isn't
1751 * really a good assumption to make but since we only support the MAC 1769 * really a good assumption to make but since we only support the MAC
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk,
1772 &buf[CIPSO_V4_HDR_LEN], 1790 &buf[CIPSO_V4_HDR_LEN],
1773 buf_len - CIPSO_V4_HDR_LEN); 1791 buf_len - CIPSO_V4_HDR_LEN);
1774 break; 1792 break;
1793 case CIPSO_V4_TAG_LOCAL:
1794 ret_val = cipso_v4_gentag_loc(doi_def,
1795 secattr,
1796 &buf[CIPSO_V4_HDR_LEN],
1797 buf_len - CIPSO_V4_HDR_LEN);
1798 break;
1775 default: 1799 default:
1776 ret_val = -EPERM; 1800 return -EPERM;
1777 goto socket_setattr_failure;
1778 } 1801 }
1779 1802
1780 iter++; 1803 iter++;
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
1782 iter < CIPSO_V4_TAG_MAXCNT && 1805 iter < CIPSO_V4_TAG_MAXCNT &&
1783 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); 1806 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1784 if (ret_val < 0) 1807 if (ret_val < 0)
1785 goto socket_setattr_failure; 1808 return ret_val;
1786 cipso_v4_gentag_hdr(doi_def, buf, ret_val); 1809 cipso_v4_gentag_hdr(doi_def, buf, ret_val);
1787 buf_len = CIPSO_V4_HDR_LEN + ret_val; 1810 return CIPSO_V4_HDR_LEN + ret_val;
1811}
1812
1813/**
1814 * cipso_v4_sock_setattr - Add a CIPSO option to a socket
1815 * @sk: the socket
1816 * @doi_def: the CIPSO DOI to use
1817 * @secattr: the specific security attributes of the socket
1818 *
1819 * Description:
1820 * Set the CIPSO option on the given socket using the DOI definition and
1821 * security attributes passed to the function. This function requires
1822 * exclusive access to @sk, which means it either needs to be in the
1823 * process of being created or locked. Returns zero on success and negative
1824 * values on failure.
1825 *
1826 */
1827int cipso_v4_sock_setattr(struct sock *sk,
1828 const struct cipso_v4_doi *doi_def,
1829 const struct netlbl_lsm_secattr *secattr)
1830{
1831 int ret_val = -EPERM;
1832 unsigned char *buf = NULL;
1833 u32 buf_len;
1834 u32 opt_len;
1835 struct ip_options *opt = NULL;
1836 struct inet_sock *sk_inet;
1837 struct inet_connection_sock *sk_conn;
1838
1839 /* In the case of sock_create_lite(), the sock->sk field is not
1840 * defined yet but it is not a problem as the only users of these
1841 * "lite" PF_INET sockets are functions which do an accept() call
1842 * afterwards so we will label the socket as part of the accept(). */
1843 if (sk == NULL)
1844 return 0;
1845
1846 /* We allocate the maximum CIPSO option size here so we are probably
1847 * being a little wasteful, but it makes our life _much_ easier later
1848 * on and after all we are only talking about 40 bytes. */
1849 buf_len = CIPSO_V4_OPT_LEN_MAX;
1850 buf = kmalloc(buf_len, GFP_ATOMIC);
1851 if (buf == NULL) {
1852 ret_val = -ENOMEM;
1853 goto socket_setattr_failure;
1854 }
1855
1856 ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1857 if (ret_val < 0)
1858 goto socket_setattr_failure;
1859 buf_len = ret_val;
1788 1860
1789 /* We can't use ip_options_get() directly because it makes a call to 1861 /* We can't use ip_options_get() directly because it makes a call to
1790 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 1862 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
@@ -1822,6 +1894,80 @@ socket_setattr_failure:
1822} 1894}
1823 1895
1824/** 1896/**
1897 * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
1898 * @sk: the socket
1899 *
1900 * Description:
1901 * Removes the CIPSO option from a socket, if present.
1902 *
1903 */
1904void cipso_v4_sock_delattr(struct sock *sk)
1905{
1906 u8 hdr_delta;
1907 struct ip_options *opt;
1908 struct inet_sock *sk_inet;
1909
1910 sk_inet = inet_sk(sk);
1911 opt = sk_inet->opt;
1912 if (opt == NULL || opt->cipso == 0)
1913 return;
1914
1915 if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
1916 u8 cipso_len;
1917 u8 cipso_off;
1918 unsigned char *cipso_ptr;
1919 int iter;
1920 int optlen_new;
1921
1922 cipso_off = opt->cipso - sizeof(struct iphdr);
1923 cipso_ptr = &opt->__data[cipso_off];
1924 cipso_len = cipso_ptr[1];
1925
1926 if (opt->srr > opt->cipso)
1927 opt->srr -= cipso_len;
1928 if (opt->rr > opt->cipso)
1929 opt->rr -= cipso_len;
1930 if (opt->ts > opt->cipso)
1931 opt->ts -= cipso_len;
1932 if (opt->router_alert > opt->cipso)
1933 opt->router_alert -= cipso_len;
1934 opt->cipso = 0;
1935
1936 memmove(cipso_ptr, cipso_ptr + cipso_len,
1937 opt->optlen - cipso_off - cipso_len);
1938
1939 /* determining the new total option length is tricky because of
1940 * the padding necessary, the only thing i can think to do at
1941 * this point is walk the options one-by-one, skipping the
1942 * padding at the end to determine the actual option size and
1943 * from there we can determine the new total option length */
1944 iter = 0;
1945 optlen_new = 0;
1946 while (iter < opt->optlen)
1947 if (opt->__data[iter] != IPOPT_NOP) {
1948 iter += opt->__data[iter + 1];
1949 optlen_new = iter;
1950 } else
1951 iter++;
1952 hdr_delta = opt->optlen;
1953 opt->optlen = (optlen_new + 3) & ~3;
1954 hdr_delta -= opt->optlen;
1955 } else {
1956 /* only the cipso option was present on the socket so we can
1957 * remove the entire option struct */
1958 sk_inet->opt = NULL;
1959 hdr_delta = opt->optlen;
1960 kfree(opt);
1961 }
1962
1963 if (sk_inet->is_icsk && hdr_delta > 0) {
1964 struct inet_connection_sock *sk_conn = inet_csk(sk);
1965 sk_conn->icsk_ext_hdr_len -= hdr_delta;
1966 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
1967 }
1968}
1969
1970/**
1825 * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions 1971 * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
1826 * @cipso: the CIPSO v4 option 1972 * @cipso: the CIPSO v4 option
1827 * @secattr: the security attributes 1973 * @secattr: the security attributes
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso,
1859 case CIPSO_V4_TAG_RANGE: 2005 case CIPSO_V4_TAG_RANGE:
1860 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); 2006 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
1861 break; 2007 break;
2008 case CIPSO_V4_TAG_LOCAL:
2009 ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
2010 break;
1862 } 2011 }
1863 if (ret_val == 0) 2012 if (ret_val == 0)
1864 secattr->type = NETLBL_NLTYPE_CIPSOV4; 2013 secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -1893,6 +2042,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
1893} 2042}
1894 2043
1895/** 2044/**
2045 * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
2046 * @skb: the packet
2047 * @secattr: the security attributes
2048 *
2049 * Description:
2050 * Set the CIPSO option on the given packet based on the security attributes.
2051 * Returns a pointer to the IP header on success and NULL on failure.
2052 *
2053 */
2054int cipso_v4_skbuff_setattr(struct sk_buff *skb,
2055 const struct cipso_v4_doi *doi_def,
2056 const struct netlbl_lsm_secattr *secattr)
2057{
2058 int ret_val;
2059 struct iphdr *iph;
2060 struct ip_options *opt = &IPCB(skb)->opt;
2061 unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
2062 u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
2063 u32 opt_len;
2064 int len_delta;
2065
2066 buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
2067 if (buf_len < 0)
2068 return buf_len;
2069 opt_len = (buf_len + 3) & ~3;
2070
2071 /* we overwrite any existing options to ensure that we have enough
2072 * room for the CIPSO option, the reason is that we _need_ to guarantee
2073 * that the security label is applied to the packet - we do the same
2074 * thing when using the socket options and it hasn't caused a problem,
2075 * if we need to we can always revisit this choice later */
2076
2077 len_delta = opt_len - opt->optlen;
2078 /* if we don't ensure enough headroom we could panic on the skb_push()
2079 * call below so make sure we have enough, we are also "mangling" the
2080 * packet so we should probably do a copy-on-write call anyway */
2081 ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
2082 if (ret_val < 0)
2083 return ret_val;
2084
2085 if (len_delta > 0) {
2086 /* we assume that the header + opt->optlen have already been
2087 * "pushed" in ip_options_build() or similar */
2088 iph = ip_hdr(skb);
2089 skb_push(skb, len_delta);
2090 memmove((char *)iph - len_delta, iph, iph->ihl << 2);
2091 skb_reset_network_header(skb);
2092 iph = ip_hdr(skb);
2093 } else if (len_delta < 0) {
2094 iph = ip_hdr(skb);
2095 memset(iph + 1, IPOPT_NOP, opt->optlen);
2096 } else
2097 iph = ip_hdr(skb);
2098
2099 if (opt->optlen > 0)
2100 memset(opt, 0, sizeof(*opt));
2101 opt->optlen = opt_len;
2102 opt->cipso = sizeof(struct iphdr);
2103 opt->is_changed = 1;
2104
2105 /* we have to do the following because we are being called from a
2106 * netfilter hook which means the packet already has had the header
2107 * fields populated and the checksum calculated - yes this means we
2108 * are doing more work than needed but we do it to keep the core
2109 * stack clean and tidy */
2110 memcpy(iph + 1, buf, buf_len);
2111 if (opt_len > buf_len)
2112 memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
2113 if (len_delta != 0) {
2114 iph->ihl = 5 + (opt_len >> 2);
2115 iph->tot_len = htons(skb->len);
2116 }
2117 ip_send_check(iph);
2118
2119 return 0;
2120}
2121
2122/**
2123 * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
2124 * @skb: the packet
2125 *
2126 * Description:
2127 * Removes any and all CIPSO options from the given packet. Returns zero on
2128 * success, negative values on failure.
2129 *
2130 */
2131int cipso_v4_skbuff_delattr(struct sk_buff *skb)
2132{
2133 int ret_val;
2134 struct iphdr *iph;
2135 struct ip_options *opt = &IPCB(skb)->opt;
2136 unsigned char *cipso_ptr;
2137
2138 if (opt->cipso == 0)
2139 return 0;
2140
2141 /* since we are changing the packet we should make a copy */
2142 ret_val = skb_cow(skb, skb_headroom(skb));
2143 if (ret_val < 0)
2144 return ret_val;
2145
2146 /* the easiest thing to do is just replace the cipso option with noop
2147 * options since we don't change the size of the packet, although we
2148 * still need to recalculate the checksum */
2149
2150 iph = ip_hdr(skb);
2151 cipso_ptr = (unsigned char *)iph + opt->cipso;
2152 memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
2153 opt->cipso = 0;
2154 opt->is_changed = 1;
2155
2156 ip_send_check(iph);
2157
2158 return 0;
2159}
2160
2161/**
1896 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option 2162 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
1897 * @skb: the packet 2163 * @skb: the packet
1898 * @secattr: the security attributes 2164 * @secattr: the security attributes
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index be3f18a7a40e..2c88da6e7862 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net,
438 goto error; 438 goto error;
439 } 439 }
440 opt->cipso = optptr - iph; 440 opt->cipso = optptr - iph;
441 if (cipso_v4_validate(&optptr)) { 441 if (cipso_v4_validate(skb, &optptr)) {
442 pp_ptr = optptr; 442 pp_ptr = optptr;
443 goto error; 443 goto error;
444 } 444 }
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile
index 8af18c0a47d9..ea750e9df65f 100644
--- a/net/netlabel/Makefile
+++ b/net/netlabel/Makefile
@@ -5,7 +5,8 @@
5# 5#
6 6
7# base objects 7# base objects
8obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o 8obj-y := netlabel_user.o netlabel_kapi.o
9obj-y += netlabel_domainhash.o netlabel_addrlist.o
9 10
10# management objects 11# management objects
11obj-y += netlabel_mgmt.o 12obj-y += netlabel_mgmt.o
diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c
new file mode 100644
index 000000000000..b0925a303353
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.c
@@ -0,0 +1,388 @@
1/*
2 * NetLabel Network Address Lists
3 *
4 * This file contains network address list functions used to manage ordered
5 * lists of network addresses for use by the NetLabel subsystem. The NetLabel
6 * system manages static and dynamic label mappings for network protocols such
7 * as CIPSO and RIPSO.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 */
12
13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32#include <linux/types.h>
33#include <linux/rcupdate.h>
34#include <linux/list.h>
35#include <linux/spinlock.h>
36#include <linux/in.h>
37#include <linux/in6.h>
38#include <linux/ip.h>
39#include <linux/ipv6.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
42#include <linux/audit.h>
43
44#include "netlabel_addrlist.h"
45
46/*
47 * Address List Functions
48 */
49
50/**
51 * netlbl_af4list_search - Search for a matching IPv4 address entry
52 * @addr: IPv4 address
53 * @head: the list head
54 *
55 * Description:
56 * Searches the IPv4 address list given by @head. If a matching address entry
57 * is found it is returned, otherwise NULL is returned. The caller is
58 * responsible for calling the rcu_read_[un]lock() functions.
59 *
60 */
61struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
62 struct list_head *head)
63{
64 struct netlbl_af4list *iter;
65
66 list_for_each_entry_rcu(iter, head, list)
67 if (iter->valid && (addr & iter->mask) == iter->addr)
68 return iter;
69
70 return NULL;
71}
72
73/**
74 * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
75 * @addr: IPv4 address
76 * @mask: IPv4 address mask
77 * @head: the list head
78 *
79 * Description:
80 * Searches the IPv4 address list given by @head. If an exact match if found
81 * it is returned, otherwise NULL is returned. The caller is responsible for
82 * calling the rcu_read_[un]lock() functions.
83 *
84 */
85struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
86 __be32 mask,
87 struct list_head *head)
88{
89 struct netlbl_af4list *iter;
90
91 list_for_each_entry_rcu(iter, head, list)
92 if (iter->valid && iter->addr == addr && iter->mask == mask)
93 return iter;
94
95 return NULL;
96}
97
98
99#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
100/**
101 * netlbl_af6list_search - Search for a matching IPv6 address entry
102 * @addr: IPv6 address
103 * @head: the list head
104 *
105 * Description:
106 * Searches the IPv6 address list given by @head. If a matching address entry
107 * is found it is returned, otherwise NULL is returned. The caller is
108 * responsible for calling the rcu_read_[un]lock() functions.
109 *
110 */
111struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
112 struct list_head *head)
113{
114 struct netlbl_af6list *iter;
115
116 list_for_each_entry_rcu(iter, head, list)
117 if (iter->valid &&
118 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
119 return iter;
120
121 return NULL;
122}
123
124/**
125 * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
126 * @addr: IPv6 address
127 * @mask: IPv6 address mask
128 * @head: the list head
129 *
130 * Description:
131 * Searches the IPv6 address list given by @head. If an exact match if found
132 * it is returned, otherwise NULL is returned. The caller is responsible for
133 * calling the rcu_read_[un]lock() functions.
134 *
135 */
136struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
137 const struct in6_addr *mask,
138 struct list_head *head)
139{
140 struct netlbl_af6list *iter;
141
142 list_for_each_entry_rcu(iter, head, list)
143 if (iter->valid &&
144 ipv6_addr_equal(&iter->addr, addr) &&
145 ipv6_addr_equal(&iter->mask, mask))
146 return iter;
147
148 return NULL;
149}
150#endif /* IPv6 */
151
152/**
153 * netlbl_af4list_add - Add a new IPv4 address entry to a list
154 * @entry: address entry
155 * @head: the list head
156 *
157 * Description:
158 * Add a new address entry to the list pointed to by @head. On success zero is
159 * returned, otherwise a negative value is returned. The caller is responsible
160 * for calling the necessary locking functions.
161 *
162 */
163int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
164{
165 struct netlbl_af4list *iter;
166
167 iter = netlbl_af4list_search(entry->addr, head);
168 if (iter != NULL &&
169 iter->addr == entry->addr && iter->mask == entry->mask)
170 return -EEXIST;
171
172 /* in order to speed up address searches through the list (the common
173 * case) we need to keep the list in order based on the size of the
174 * address mask such that the entry with the widest mask (smallest
175 * numerical value) appears first in the list */
176 list_for_each_entry_rcu(iter, head, list)
177 if (iter->valid &&
178 ntohl(entry->mask) > ntohl(iter->mask)) {
179 __list_add_rcu(&entry->list,
180 iter->list.prev,
181 &iter->list);
182 return 0;
183 }
184 list_add_tail_rcu(&entry->list, head);
185 return 0;
186}
187
188#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
189/**
190 * netlbl_af6list_add - Add a new IPv6 address entry to a list
191 * @entry: address entry
192 * @head: the list head
193 *
194 * Description:
195 * Add a new address entry to the list pointed to by @head. On success zero is
196 * returned, otherwise a negative value is returned. The caller is responsible
197 * for calling the necessary locking functions.
198 *
199 */
200int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
201{
202 struct netlbl_af6list *iter;
203
204 iter = netlbl_af6list_search(&entry->addr, head);
205 if (iter != NULL &&
206 ipv6_addr_equal(&iter->addr, &entry->addr) &&
207 ipv6_addr_equal(&iter->mask, &entry->mask))
208 return -EEXIST;
209
210 /* in order to speed up address searches through the list (the common
211 * case) we need to keep the list in order based on the size of the
212 * address mask such that the entry with the widest mask (smallest
213 * numerical value) appears first in the list */
214 list_for_each_entry_rcu(iter, head, list)
215 if (iter->valid &&
216 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
217 __list_add_rcu(&entry->list,
218 iter->list.prev,
219 &iter->list);
220 return 0;
221 }
222 list_add_tail_rcu(&entry->list, head);
223 return 0;
224}
225#endif /* IPv6 */
226
227/**
228 * netlbl_af4list_remove_entry - Remove an IPv4 address entry
229 * @entry: address entry
230 *
231 * Description:
232 * Remove the specified IP address entry. The caller is responsible for
233 * calling the necessary locking functions.
234 *
235 */
236void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
237{
238 entry->valid = 0;
239 list_del_rcu(&entry->list);
240}
241
242/**
243 * netlbl_af4list_remove - Remove an IPv4 address entry
244 * @addr: IP address
245 * @mask: IP address mask
246 * @head: the list head
247 *
248 * Description:
249 * Remove an IP address entry from the list pointed to by @head. Returns the
250 * entry on success, NULL on failure. The caller is responsible for calling
251 * the necessary locking functions.
252 *
253 */
254struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
255 struct list_head *head)
256{
257 struct netlbl_af4list *entry;
258
259 entry = netlbl_af4list_search(addr, head);
260 if (entry != NULL && entry->addr == addr && entry->mask == mask) {
261 netlbl_af4list_remove_entry(entry);
262 return entry;
263 }
264
265 return NULL;
266}
267
268#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
269/**
270 * netlbl_af6list_remove_entry - Remove an IPv6 address entry
271 * @entry: address entry
272 *
273 * Description:
274 * Remove the specified IP address entry. The caller is responsible for
275 * calling the necessary locking functions.
276 *
277 */
278void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
279{
280 entry->valid = 0;
281 list_del_rcu(&entry->list);
282}
283
284/**
285 * netlbl_af6list_remove - Remove an IPv6 address entry
286 * @addr: IP address
287 * @mask: IP address mask
288 * @head: the list head
289 *
290 * Description:
291 * Remove an IP address entry from the list pointed to by @head. Returns the
292 * entry on success, NULL on failure. The caller is responsible for calling
293 * the necessary locking functions.
294 *
295 */
296struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
297 const struct in6_addr *mask,
298 struct list_head *head)
299{
300 struct netlbl_af6list *entry;
301
302 entry = netlbl_af6list_search(addr, head);
303 if (entry != NULL &&
304 ipv6_addr_equal(&entry->addr, addr) &&
305 ipv6_addr_equal(&entry->mask, mask)) {
306 netlbl_af6list_remove_entry(entry);
307 return entry;
308 }
309
310 return NULL;
311}
312#endif /* IPv6 */
313
314/*
315 * Audit Helper Functions
316 */
317
318/**
319 * netlbl_af4list_audit_addr - Audit an IPv4 address
320 * @audit_buf: audit buffer
321 * @src: true if source address, false if destination
322 * @dev: network interface
323 * @addr: IP address
324 * @mask: IP address mask
325 *
326 * Description:
327 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
328 *
329 */
330void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
331 int src, const char *dev,
332 __be32 addr, __be32 mask)
333{
334 u32 mask_val = ntohl(mask);
335 char *dir = (src ? "src" : "dst");
336
337 if (dev != NULL)
338 audit_log_format(audit_buf, " netif=%s", dev);
339 audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
340 if (mask_val != 0xffffffff) {
341 u32 mask_len = 0;
342 while (mask_val > 0) {
343 mask_val <<= 1;
344 mask_len++;
345 }
346 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
347 }
348}
349
350#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
351/**
352 * netlbl_af6list_audit_addr - Audit an IPv6 address
353 * @audit_buf: audit buffer
354 * @src: true if source address, false if destination
355 * @dev: network interface
356 * @addr: IP address
357 * @mask: IP address mask
358 *
359 * Description:
360 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
361 *
362 */
363void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
364 int src,
365 const char *dev,
366 const struct in6_addr *addr,
367 const struct in6_addr *mask)
368{
369 char *dir = (src ? "src" : "dst");
370
371 if (dev != NULL)
372 audit_log_format(audit_buf, " netif=%s", dev);
373 audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr));
374 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
375 u32 mask_len = 0;
376 u32 mask_val;
377 int iter = -1;
378 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
379 mask_len += 32;
380 mask_val = ntohl(mask->s6_addr32[iter]);
381 while (mask_val > 0) {
382 mask_val <<= 1;
383 mask_len++;
384 }
385 audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
386 }
387}
388#endif /* IPv6 */
diff --git a/net/netlabel/netlabel_addrlist.h b/net/netlabel/netlabel_addrlist.h
new file mode 100644
index 000000000000..0242bead405f
--- /dev/null
+++ b/net/netlabel/netlabel_addrlist.h
@@ -0,0 +1,189 @@
1/*
2 * NetLabel Network Address Lists
3 *
4 * This file contains network address list functions used to manage ordered
5 * lists of network addresses for use by the NetLabel subsystem. The NetLabel
6 * system manages static and dynamic label mappings for network protocols such
7 * as CIPSO and RIPSO.
8 *
9 * Author: Paul Moore <paul.moore@hp.com>
10 *
11 */
12
13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
24 * the GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32#ifndef _NETLABEL_ADDRLIST_H
33#define _NETLABEL_ADDRLIST_H
34
35#include <linux/types.h>
36#include <linux/rcupdate.h>
37#include <linux/list.h>
38#include <linux/in6.h>
39#include <linux/audit.h>
40
41/**
42 * struct netlbl_af4list - NetLabel IPv4 address list
43 * @addr: IPv4 address
44 * @mask: IPv4 address mask
45 * @valid: valid flag
46 * @list: list structure, used internally
47 */
48struct netlbl_af4list {
49 __be32 addr;
50 __be32 mask;
51
52 u32 valid;
53 struct list_head list;
54};
55
56/**
57 * struct netlbl_af6list - NetLabel IPv6 address list
58 * @addr: IPv6 address
59 * @mask: IPv6 address mask
60 * @valid: valid flag
61 * @list: list structure, used internally
62 */
63struct netlbl_af6list {
64 struct in6_addr addr;
65 struct in6_addr mask;
66
67 u32 valid;
68 struct list_head list;
69};
70
71#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
72
73static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
74 struct list_head *h)
75{
76 struct list_head *i = s;
77 struct netlbl_af4list *n = __af4list_entry(s);
78 while (i != h && !n->valid) {
79 i = i->next;
80 n = __af4list_entry(i);
81 }
82 return n;
83}
84
85static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
86 struct list_head *h)
87{
88 struct list_head *i = s;
89 struct netlbl_af4list *n = __af4list_entry(s);
90 while (i != h && !n->valid) {
91 i = rcu_dereference(i->next);
92 n = __af4list_entry(i);
93 }
94 return n;
95}
96
97#define netlbl_af4list_foreach(iter, head) \
98 for (iter = __af4list_valid((head)->next, head); \
99 prefetch(iter->list.next), &iter->list != (head); \
100 iter = __af4list_valid(iter->list.next, head))
101
102#define netlbl_af4list_foreach_rcu(iter, head) \
103 for (iter = __af4list_valid_rcu((head)->next, head); \
104 prefetch(iter->list.next), &iter->list != (head); \
105 iter = __af4list_valid_rcu(iter->list.next, head))
106
107#define netlbl_af4list_foreach_safe(iter, tmp, head) \
108 for (iter = __af4list_valid((head)->next, head), \
109 tmp = __af4list_valid(iter->list.next, head); \
110 &iter->list != (head); \
111 iter = tmp, tmp = __af4list_valid(iter->list.next, head))
112
113int netlbl_af4list_add(struct netlbl_af4list *entry,
114 struct list_head *head);
115struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
116 struct list_head *head);
117void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
118struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
119 struct list_head *head);
120struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
121 __be32 mask,
122 struct list_head *head);
123void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
124 int src, const char *dev,
125 __be32 addr, __be32 mask);
126
127#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
128
129#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
130
131static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
132 struct list_head *h)
133{
134 struct list_head *i = s;
135 struct netlbl_af6list *n = __af6list_entry(s);
136 while (i != h && !n->valid) {
137 i = i->next;
138 n = __af6list_entry(i);
139 }
140 return n;
141}
142
143static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
144 struct list_head *h)
145{
146 struct list_head *i = s;
147 struct netlbl_af6list *n = __af6list_entry(s);
148 while (i != h && !n->valid) {
149 i = rcu_dereference(i->next);
150 n = __af6list_entry(i);
151 }
152 return n;
153}
154
155#define netlbl_af6list_foreach(iter, head) \
156 for (iter = __af6list_valid((head)->next, head); \
157 prefetch(iter->list.next), &iter->list != (head); \
158 iter = __af6list_valid(iter->list.next, head))
159
160#define netlbl_af6list_foreach_rcu(iter, head) \
161 for (iter = __af6list_valid_rcu((head)->next, head); \
162 prefetch(iter->list.next), &iter->list != (head); \
163 iter = __af6list_valid_rcu(iter->list.next, head))
164
165#define netlbl_af6list_foreach_safe(iter, tmp, head) \
166 for (iter = __af6list_valid((head)->next, head), \
167 tmp = __af6list_valid(iter->list.next, head); \
168 &iter->list != (head); \
169 iter = tmp, tmp = __af6list_valid(iter->list.next, head))
170
171int netlbl_af6list_add(struct netlbl_af6list *entry,
172 struct list_head *head);
173struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
174 const struct in6_addr *mask,
175 struct list_head *head);
176void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
177struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
178 struct list_head *head);
179struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
180 const struct in6_addr *mask,
181 struct list_head *head);
182void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
183 int src,
184 const char *dev,
185 const struct in6_addr *addr,
186 const struct in6_addr *mask);
187#endif /* IPV6 */
188
189#endif
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 0aec318bf0ef..fff32b70efa9 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -43,6 +43,7 @@
43#include "netlabel_user.h" 43#include "netlabel_user.h"
44#include "netlabel_cipso_v4.h" 44#include "netlabel_cipso_v4.h"
45#include "netlabel_mgmt.h" 45#include "netlabel_mgmt.h"
46#include "netlabel_domainhash.h"
46 47
47/* Argument struct for cipso_v4_doi_walk() */ 48/* Argument struct for cipso_v4_doi_walk() */
48struct netlbl_cipsov4_doiwalk_arg { 49struct netlbl_cipsov4_doiwalk_arg {
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg {
51 u32 seq; 52 u32 seq;
52}; 53};
53 54
55/* Argument struct for netlbl_domhsh_walk() */
56struct netlbl_domhsh_walk_arg {
57 struct netlbl_audit *audit_info;
58 u32 doi;
59};
60
54/* NetLabel Generic NETLINK CIPSOv4 family */ 61/* NetLabel Generic NETLINK CIPSOv4 family */
55static struct genl_family netlbl_cipsov4_gnl_family = { 62static struct genl_family netlbl_cipsov4_gnl_family = {
56 .id = GENL_ID_GENERATE, 63 .id = GENL_ID_GENERATE,
@@ -81,32 +88,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
81 */ 88 */
82 89
83/** 90/**
84 * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
85 * @entry: the entry's RCU field
86 *
87 * Description:
88 * This function is designed to be used as a callback to the call_rcu()
89 * function so that the memory allocated to the DOI definition can be released
90 * safely.
91 *
92 */
93void netlbl_cipsov4_doi_free(struct rcu_head *entry)
94{
95 struct cipso_v4_doi *ptr;
96
97 ptr = container_of(entry, struct cipso_v4_doi, rcu);
98 switch (ptr->type) {
99 case CIPSO_V4_MAP_STD:
100 kfree(ptr->map.std->lvl.cipso);
101 kfree(ptr->map.std->lvl.local);
102 kfree(ptr->map.std->cat.cipso);
103 kfree(ptr->map.std->cat.local);
104 break;
105 }
106 kfree(ptr);
107}
108
109/**
110 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message 91 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
111 * @info: the Generic NETLINK info block 92 * @info: the Generic NETLINK info block
112 * @doi_def: the CIPSO V4 DOI definition 93 * @doi_def: the CIPSO V4 DOI definition
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
151 * @info: the Generic NETLINK info block 132 * @info: the Generic NETLINK info block
152 * 133 *
153 * Description: 134 * Description:
154 * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message 135 * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
155 * and add it to the CIPSO V4 engine. Return zero on success and non-zero on 136 * message and add it to the CIPSO V4 engine. Return zero on success and
156 * error. 137 * non-zero on error.
157 * 138 *
158 */ 139 */
159static int netlbl_cipsov4_add_std(struct genl_info *info) 140static int netlbl_cipsov4_add_std(struct genl_info *info)
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
183 ret_val = -ENOMEM; 164 ret_val = -ENOMEM;
184 goto add_std_failure; 165 goto add_std_failure;
185 } 166 }
186 doi_def->type = CIPSO_V4_MAP_STD; 167 doi_def->type = CIPSO_V4_MAP_TRANS;
187 168
188 ret_val = netlbl_cipsov4_add_common(info, doi_def); 169 ret_val = netlbl_cipsov4_add_common(info, doi_def);
189 if (ret_val != 0) 170 if (ret_val != 0)
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
342 323
343add_std_failure: 324add_std_failure:
344 if (doi_def) 325 if (doi_def)
345 netlbl_cipsov4_doi_free(&doi_def->rcu); 326 cipso_v4_doi_free(doi_def);
346 return ret_val; 327 return ret_val;
347} 328}
348 329
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
379 return 0; 360 return 0;
380 361
381add_pass_failure: 362add_pass_failure:
382 netlbl_cipsov4_doi_free(&doi_def->rcu); 363 cipso_v4_doi_free(doi_def);
364 return ret_val;
365}
366
367/**
368 * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
369 * @info: the Generic NETLINK info block
370 *
371 * Description:
372 * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
373 * message and add it to the CIPSO V4 engine. Return zero on success and
374 * non-zero on error.
375 *
376 */
377static int netlbl_cipsov4_add_local(struct genl_info *info)
378{
379 int ret_val;
380 struct cipso_v4_doi *doi_def = NULL;
381
382 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
383 return -EINVAL;
384
385 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
386 if (doi_def == NULL)
387 return -ENOMEM;
388 doi_def->type = CIPSO_V4_MAP_LOCAL;
389
390 ret_val = netlbl_cipsov4_add_common(info, doi_def);
391 if (ret_val != 0)
392 goto add_local_failure;
393
394 ret_val = cipso_v4_doi_add(doi_def);
395 if (ret_val != 0)
396 goto add_local_failure;
397 return 0;
398
399add_local_failure:
400 cipso_v4_doi_free(doi_def);
383 return ret_val; 401 return ret_val;
384} 402}
385 403
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
412 430
413 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); 431 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
414 switch (type) { 432 switch (type) {
415 case CIPSO_V4_MAP_STD: 433 case CIPSO_V4_MAP_TRANS:
416 type_str = "std"; 434 type_str = "trans";
417 ret_val = netlbl_cipsov4_add_std(info); 435 ret_val = netlbl_cipsov4_add_std(info);
418 break; 436 break;
419 case CIPSO_V4_MAP_PASS: 437 case CIPSO_V4_MAP_PASS:
420 type_str = "pass"; 438 type_str = "pass";
421 ret_val = netlbl_cipsov4_add_pass(info); 439 ret_val = netlbl_cipsov4_add_pass(info);
422 break; 440 break;
441 case CIPSO_V4_MAP_LOCAL:
442 type_str = "local";
443 ret_val = netlbl_cipsov4_add_local(info);
444 break;
423 } 445 }
424 if (ret_val == 0) 446 if (ret_val == 0)
425 atomic_inc(&netlabel_mgmt_protocount); 447 atomic_inc(&netlabel_mgmt_protocount);
@@ -491,7 +513,7 @@ list_start:
491 doi_def = cipso_v4_doi_getdef(doi); 513 doi_def = cipso_v4_doi_getdef(doi);
492 if (doi_def == NULL) { 514 if (doi_def == NULL) {
493 ret_val = -EINVAL; 515 ret_val = -EINVAL;
494 goto list_failure; 516 goto list_failure_lock;
495 } 517 }
496 518
497 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); 519 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
@@ -516,7 +538,7 @@ list_start:
516 nla_nest_end(ans_skb, nla_a); 538 nla_nest_end(ans_skb, nla_a);
517 539
518 switch (doi_def->type) { 540 switch (doi_def->type) {
519 case CIPSO_V4_MAP_STD: 541 case CIPSO_V4_MAP_TRANS:
520 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); 542 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
521 if (nla_a == NULL) { 543 if (nla_a == NULL) {
522 ret_val = -ENOMEM; 544 ret_val = -ENOMEM;
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
655 struct netlink_callback *cb) 677 struct netlink_callback *cb)
656{ 678{
657 struct netlbl_cipsov4_doiwalk_arg cb_arg; 679 struct netlbl_cipsov4_doiwalk_arg cb_arg;
658 int doi_skip = cb->args[0]; 680 u32 doi_skip = cb->args[0];
659 681
660 cb_arg.nl_cb = cb; 682 cb_arg.nl_cb = cb;
661 cb_arg.skb = skb; 683 cb_arg.skb = skb;
@@ -668,6 +690,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
668} 690}
669 691
670/** 692/**
693 * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
694 * @entry: LSM domain mapping entry
695 * @arg: the netlbl_domhsh_walk_arg structure
696 *
697 * Description:
698 * This function is intended for use by netlbl_cipsov4_remove() as the callback
699 * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
700 * which are associated with the CIPSO DOI specified in @arg. Returns zero on
701 * success, negative values on failure.
702 *
703 */
704static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
705{
706 struct netlbl_domhsh_walk_arg *cb_arg = arg;
707
708 if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
709 entry->type_def.cipsov4->doi == cb_arg->doi)
710 return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
711
712 return 0;
713}
714
715/**
671 * netlbl_cipsov4_remove - Handle a REMOVE message 716 * netlbl_cipsov4_remove - Handle a REMOVE message
672 * @skb: the NETLINK buffer 717 * @skb: the NETLINK buffer
673 * @info: the Generic NETLINK info block 718 * @info: the Generic NETLINK info block
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
681{ 726{
682 int ret_val = -EINVAL; 727 int ret_val = -EINVAL;
683 u32 doi = 0; 728 u32 doi = 0;
729 struct netlbl_domhsh_walk_arg cb_arg;
684 struct audit_buffer *audit_buf; 730 struct audit_buffer *audit_buf;
685 struct netlbl_audit audit_info; 731 struct netlbl_audit audit_info;
732 u32 skip_bkt = 0;
733 u32 skip_chain = 0;
686 734
687 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) 735 if (!info->attrs[NLBL_CIPSOV4_A_DOI])
688 return -EINVAL; 736 return -EINVAL;
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
690 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 738 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
691 netlbl_netlink_auditinfo(skb, &audit_info); 739 netlbl_netlink_auditinfo(skb, &audit_info);
692 740
693 ret_val = cipso_v4_doi_remove(doi, 741 cb_arg.doi = doi;
694 &audit_info, 742 cb_arg.audit_info = &audit_info;
695 netlbl_cipsov4_doi_free); 743 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
696 if (ret_val == 0) 744 netlbl_cipsov4_remove_cb, &cb_arg);
697 atomic_dec(&netlabel_mgmt_protocount); 745 if (ret_val == 0 || ret_val == -ENOENT) {
746 ret_val = cipso_v4_doi_remove(doi, &audit_info);
747 if (ret_val == 0)
748 atomic_dec(&netlabel_mgmt_protocount);
749 }
698 750
699 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, 751 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
700 &audit_info); 752 &audit_info);
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h
index 220cb9d06b49..c8a4079261f0 100644
--- a/net/netlabel/netlabel_cipso_v4.h
+++ b/net/netlabel/netlabel_cipso_v4.h
@@ -45,12 +45,13 @@
45 * NLBL_CIPSOV4_A_MTYPE 45 * NLBL_CIPSOV4_A_MTYPE
46 * NLBL_CIPSOV4_A_TAGLST 46 * NLBL_CIPSOV4_A_TAGLST
47 * 47 *
48 * If using CIPSO_V4_MAP_STD the following attributes are required: 48 * If using CIPSO_V4_MAP_TRANS the following attributes are required:
49 * 49 *
50 * NLBL_CIPSOV4_A_MLSLVLLST 50 * NLBL_CIPSOV4_A_MLSLVLLST
51 * NLBL_CIPSOV4_A_MLSCATLST 51 * NLBL_CIPSOV4_A_MLSCATLST
52 * 52 *
53 * If using CIPSO_V4_MAP_PASS no additional attributes are required. 53 * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
54 * are required.
54 * 55 *
55 * o REMOVE: 56 * o REMOVE:
56 * Sent by an application to remove a specific DOI mapping table from the 57 * Sent by an application to remove a specific DOI mapping table from the
@@ -76,12 +77,13 @@
76 * NLBL_CIPSOV4_A_MTYPE 77 * NLBL_CIPSOV4_A_MTYPE
77 * NLBL_CIPSOV4_A_TAGLST 78 * NLBL_CIPSOV4_A_TAGLST
78 * 79 *
79 * If using CIPSO_V4_MAP_STD the following attributes are required: 80 * If using CIPSO_V4_MAP_TRANS the following attributes are required:
80 * 81 *
81 * NLBL_CIPSOV4_A_MLSLVLLST 82 * NLBL_CIPSOV4_A_MLSLVLLST
82 * NLBL_CIPSOV4_A_MLSCATLST 83 * NLBL_CIPSOV4_A_MLSCATLST
83 * 84 *
84 * If using CIPSO_V4_MAP_PASS no additional attributes are required. 85 * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
86 * are required.
85 * 87 *
86 * o LISTALL: 88 * o LISTALL:
87 * This message is sent by an application to list the valid DOIs on the 89 * This message is sent by an application to list the valid DOIs on the
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 643c032a3a57..5fadf10e5ddf 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13/* 13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15 * 15 *
16 * This program is free software; you can redistribute it and/or modify 16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
40#include <asm/bug.h> 40#include <asm/bug.h>
41 41
42#include "netlabel_mgmt.h" 42#include "netlabel_mgmt.h"
43#include "netlabel_addrlist.h"
43#include "netlabel_domainhash.h" 44#include "netlabel_domainhash.h"
44#include "netlabel_user.h" 45#include "netlabel_user.h"
45 46
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
72static void netlbl_domhsh_free_entry(struct rcu_head *entry) 73static void netlbl_domhsh_free_entry(struct rcu_head *entry)
73{ 74{
74 struct netlbl_dom_map *ptr; 75 struct netlbl_dom_map *ptr;
76 struct netlbl_af4list *iter4;
77 struct netlbl_af4list *tmp4;
78#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
79 struct netlbl_af6list *iter6;
80 struct netlbl_af6list *tmp6;
81#endif /* IPv6 */
75 82
76 ptr = container_of(entry, struct netlbl_dom_map, rcu); 83 ptr = container_of(entry, struct netlbl_dom_map, rcu);
84 if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
85 netlbl_af4list_foreach_safe(iter4, tmp4,
86 &ptr->type_def.addrsel->list4) {
87 netlbl_af4list_remove_entry(iter4);
88 kfree(netlbl_domhsh_addr4_entry(iter4));
89 }
90#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
91 netlbl_af6list_foreach_safe(iter6, tmp6,
92 &ptr->type_def.addrsel->list6) {
93 netlbl_af6list_remove_entry(iter6);
94 kfree(netlbl_domhsh_addr6_entry(iter6));
95 }
96#endif /* IPv6 */
97 }
77 kfree(ptr->domain); 98 kfree(ptr->domain);
78 kfree(ptr); 99 kfree(ptr);
79} 100}
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key)
115static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) 136static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
116{ 137{
117 u32 bkt; 138 u32 bkt;
139 struct list_head *bkt_list;
118 struct netlbl_dom_map *iter; 140 struct netlbl_dom_map *iter;
119 141
120 if (domain != NULL) { 142 if (domain != NULL) {
121 bkt = netlbl_domhsh_hash(domain); 143 bkt = netlbl_domhsh_hash(domain);
122 list_for_each_entry_rcu(iter, 144 bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt];
123 &rcu_dereference(netlbl_domhsh)->tbl[bkt], 145 list_for_each_entry_rcu(iter, bkt_list, list)
124 list)
125 if (iter->valid && strcmp(iter->domain, domain) == 0) 146 if (iter->valid && strcmp(iter->domain, domain) == 0)
126 return iter; 147 return iter;
127 } 148 }
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
156 return entry; 177 return entry;
157} 178}
158 179
180/**
181 * netlbl_domhsh_audit_add - Generate an audit entry for an add event
182 * @entry: the entry being added
183 * @addr4: the IPv4 address information
184 * @addr6: the IPv6 address information
185 * @result: the result code
186 * @audit_info: NetLabel audit information
187 *
188 * Description:
189 * Generate an audit record for adding a new NetLabel/LSM mapping entry with
190 * the given information. Caller is responsibile for holding the necessary
191 * locks.
192 *
193 */
194static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
195 struct netlbl_af4list *addr4,
196 struct netlbl_af6list *addr6,
197 int result,
198 struct netlbl_audit *audit_info)
199{
200 struct audit_buffer *audit_buf;
201 struct cipso_v4_doi *cipsov4 = NULL;
202 u32 type;
203
204 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
205 if (audit_buf != NULL) {
206 audit_log_format(audit_buf, " nlbl_domain=%s",
207 entry->domain ? entry->domain : "(default)");
208 if (addr4 != NULL) {
209 struct netlbl_domaddr4_map *map4;
210 map4 = netlbl_domhsh_addr4_entry(addr4);
211 type = map4->type;
212 cipsov4 = map4->type_def.cipsov4;
213 netlbl_af4list_audit_addr(audit_buf, 0, NULL,
214 addr4->addr, addr4->mask);
215#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
216 } else if (addr6 != NULL) {
217 struct netlbl_domaddr6_map *map6;
218 map6 = netlbl_domhsh_addr6_entry(addr6);
219 type = map6->type;
220 netlbl_af6list_audit_addr(audit_buf, 0, NULL,
221 &addr6->addr, &addr6->mask);
222#endif /* IPv6 */
223 } else {
224 type = entry->type;
225 cipsov4 = entry->type_def.cipsov4;
226 }
227 switch (type) {
228 case NETLBL_NLTYPE_UNLABELED:
229 audit_log_format(audit_buf, " nlbl_protocol=unlbl");
230 break;
231 case NETLBL_NLTYPE_CIPSOV4:
232 BUG_ON(cipsov4 == NULL);
233 audit_log_format(audit_buf,
234 " nlbl_protocol=cipsov4 cipso_doi=%u",
235 cipsov4->doi);
236 break;
237 }
238 audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
239 audit_log_end(audit_buf);
240 }
241}
242
159/* 243/*
160 * Domain Hash Table Functions 244 * Domain Hash Table Functions
161 */ 245 */
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
213int netlbl_domhsh_add(struct netlbl_dom_map *entry, 297int netlbl_domhsh_add(struct netlbl_dom_map *entry,
214 struct netlbl_audit *audit_info) 298 struct netlbl_audit *audit_info)
215{ 299{
216 int ret_val; 300 int ret_val = 0;
217 u32 bkt; 301 struct netlbl_dom_map *entry_old;
218 struct audit_buffer *audit_buf; 302 struct netlbl_af4list *iter4;
219 303 struct netlbl_af4list *tmp4;
220 switch (entry->type) { 304#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
221 case NETLBL_NLTYPE_UNLABELED: 305 struct netlbl_af6list *iter6;
222 ret_val = 0; 306 struct netlbl_af6list *tmp6;
223 break; 307#endif /* IPv6 */
224 case NETLBL_NLTYPE_CIPSOV4:
225 ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
226 entry->domain);
227 break;
228 default:
229 return -EINVAL;
230 }
231 if (ret_val != 0)
232 return ret_val;
233
234 entry->valid = 1;
235 INIT_RCU_HEAD(&entry->rcu);
236 308
237 rcu_read_lock(); 309 rcu_read_lock();
310
238 spin_lock(&netlbl_domhsh_lock); 311 spin_lock(&netlbl_domhsh_lock);
239 if (entry->domain != NULL) { 312 if (entry->domain != NULL)
240 bkt = netlbl_domhsh_hash(entry->domain); 313 entry_old = netlbl_domhsh_search(entry->domain);
241 if (netlbl_domhsh_search(entry->domain) == NULL) 314 else
315 entry_old = netlbl_domhsh_search_def(entry->domain);
316 if (entry_old == NULL) {
317 entry->valid = 1;
318 INIT_RCU_HEAD(&entry->rcu);
319
320 if (entry->domain != NULL) {
321 u32 bkt = netlbl_domhsh_hash(entry->domain);
242 list_add_tail_rcu(&entry->list, 322 list_add_tail_rcu(&entry->list,
243 &rcu_dereference(netlbl_domhsh)->tbl[bkt]); 323 &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
244 else 324 } else {
245 ret_val = -EEXIST; 325 INIT_LIST_HEAD(&entry->list);
246 } else {
247 INIT_LIST_HEAD(&entry->list);
248 if (rcu_dereference(netlbl_domhsh_def) == NULL)
249 rcu_assign_pointer(netlbl_domhsh_def, entry); 326 rcu_assign_pointer(netlbl_domhsh_def, entry);
250 else
251 ret_val = -EEXIST;
252 }
253 spin_unlock(&netlbl_domhsh_lock);
254 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
255 if (audit_buf != NULL) {
256 audit_log_format(audit_buf,
257 " nlbl_domain=%s",
258 entry->domain ? entry->domain : "(default)");
259 switch (entry->type) {
260 case NETLBL_NLTYPE_UNLABELED:
261 audit_log_format(audit_buf, " nlbl_protocol=unlbl");
262 break;
263 case NETLBL_NLTYPE_CIPSOV4:
264 audit_log_format(audit_buf,
265 " nlbl_protocol=cipsov4 cipso_doi=%u",
266 entry->type_def.cipsov4->doi);
267 break;
268 } 327 }
269 audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
270 audit_log_end(audit_buf);
271 }
272 rcu_read_unlock();
273 328
274 if (ret_val != 0) { 329 if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
275 switch (entry->type) { 330 netlbl_af4list_foreach_rcu(iter4,
276 case NETLBL_NLTYPE_CIPSOV4: 331 &entry->type_def.addrsel->list4)
277 if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, 332 netlbl_domhsh_audit_add(entry, iter4, NULL,
278 entry->domain) != 0) 333 ret_val, audit_info);
279 BUG(); 334#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
280 break; 335 netlbl_af6list_foreach_rcu(iter6,
336 &entry->type_def.addrsel->list6)
337 netlbl_domhsh_audit_add(entry, NULL, iter6,
338 ret_val, audit_info);
339#endif /* IPv6 */
340 } else
341 netlbl_domhsh_audit_add(entry, NULL, NULL,
342 ret_val, audit_info);
343 } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
344 entry->type == NETLBL_NLTYPE_ADDRSELECT) {
345 struct list_head *old_list4;
346 struct list_head *old_list6;
347
348 old_list4 = &entry_old->type_def.addrsel->list4;
349 old_list6 = &entry_old->type_def.addrsel->list6;
350
351 /* we only allow the addition of address selectors if all of
352 * the selectors do not exist in the existing domain map */
353 netlbl_af4list_foreach_rcu(iter4,
354 &entry->type_def.addrsel->list4)
355 if (netlbl_af4list_search_exact(iter4->addr,
356 iter4->mask,
357 old_list4)) {
358 ret_val = -EEXIST;
359 goto add_return;
360 }
361#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
362 netlbl_af6list_foreach_rcu(iter6,
363 &entry->type_def.addrsel->list6)
364 if (netlbl_af6list_search_exact(&iter6->addr,
365 &iter6->mask,
366 old_list6)) {
367 ret_val = -EEXIST;
368 goto add_return;
369 }
370#endif /* IPv6 */
371
372 netlbl_af4list_foreach_safe(iter4, tmp4,
373 &entry->type_def.addrsel->list4) {
374 netlbl_af4list_remove_entry(iter4);
375 iter4->valid = 1;
376 ret_val = netlbl_af4list_add(iter4, old_list4);
377 netlbl_domhsh_audit_add(entry_old, iter4, NULL,
378 ret_val, audit_info);
379 if (ret_val != 0)
380 goto add_return;
281 } 381 }
282 } 382#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
383 netlbl_af6list_foreach_safe(iter6, tmp6,
384 &entry->type_def.addrsel->list6) {
385 netlbl_af6list_remove_entry(iter6);
386 iter6->valid = 1;
387 ret_val = netlbl_af6list_add(iter6, old_list6);
388 netlbl_domhsh_audit_add(entry_old, NULL, iter6,
389 ret_val, audit_info);
390 if (ret_val != 0)
391 goto add_return;
392 }
393#endif /* IPv6 */
394 } else
395 ret_val = -EINVAL;
283 396
397add_return:
398 spin_unlock(&netlbl_domhsh_lock);
399 rcu_read_unlock();
284 return ret_val; 400 return ret_val;
285} 401}
286 402
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
302} 418}
303 419
304/** 420/**
305 * netlbl_domhsh_remove - Removes an entry from the domain hash table 421 * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
306 * @domain: the domain to remove 422 * @entry: the entry to remove
307 * @audit_info: NetLabel audit information 423 * @audit_info: NetLabel audit information
308 * 424 *
309 * Description: 425 * Description:
310 * Removes an entry from the domain hash table and handles any updates to the 426 * Removes an entry from the domain hash table and handles any updates to the
311 * lower level protocol handler (i.e. CIPSO). Returns zero on success, 427 * lower level protocol handler (i.e. CIPSO). Caller is responsible for
312 * negative on failure. 428 * ensuring that the RCU read lock is held. Returns zero on success, negative
429 * on failure.
313 * 430 *
314 */ 431 */
315int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) 432int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
433 struct netlbl_audit *audit_info)
316{ 434{
317 int ret_val = -ENOENT; 435 int ret_val = 0;
318 struct netlbl_dom_map *entry;
319 struct audit_buffer *audit_buf; 436 struct audit_buffer *audit_buf;
320 437
321 rcu_read_lock();
322 if (domain)
323 entry = netlbl_domhsh_search(domain);
324 else
325 entry = netlbl_domhsh_search_def(domain);
326 if (entry == NULL) 438 if (entry == NULL)
327 goto remove_return; 439 return -ENOENT;
328 switch (entry->type) { 440
329 case NETLBL_NLTYPE_CIPSOV4:
330 cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
331 entry->domain);
332 break;
333 }
334 spin_lock(&netlbl_domhsh_lock); 441 spin_lock(&netlbl_domhsh_lock);
335 if (entry->valid) { 442 if (entry->valid) {
336 entry->valid = 0; 443 entry->valid = 0;
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
338 list_del_rcu(&entry->list); 445 list_del_rcu(&entry->list);
339 else 446 else
340 rcu_assign_pointer(netlbl_domhsh_def, NULL); 447 rcu_assign_pointer(netlbl_domhsh_def, NULL);
341 ret_val = 0; 448 } else
342 } 449 ret_val = -ENOENT;
343 spin_unlock(&netlbl_domhsh_lock); 450 spin_unlock(&netlbl_domhsh_lock);
344 451
345 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); 452 audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
351 audit_log_end(audit_buf); 458 audit_log_end(audit_buf);
352 } 459 }
353 460
354remove_return: 461 if (ret_val == 0) {
355 rcu_read_unlock(); 462 struct netlbl_af4list *iter4;
356 if (ret_val == 0) 463 struct netlbl_domaddr4_map *map4;
464
465 switch (entry->type) {
466 case NETLBL_NLTYPE_ADDRSELECT:
467 netlbl_af4list_foreach_rcu(iter4,
468 &entry->type_def.addrsel->list4) {
469 map4 = netlbl_domhsh_addr4_entry(iter4);
470 cipso_v4_doi_putdef(map4->type_def.cipsov4);
471 }
472 /* no need to check the IPv6 list since we currently
473 * support only unlabeled protocols for IPv6 */
474 break;
475 case NETLBL_NLTYPE_CIPSOV4:
476 cipso_v4_doi_putdef(entry->type_def.cipsov4);
477 break;
478 }
357 call_rcu(&entry->rcu, netlbl_domhsh_free_entry); 479 call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
480 }
481
482 return ret_val;
483}
484
485/**
486 * netlbl_domhsh_remove - Removes an entry from the domain hash table
487 * @domain: the domain to remove
488 * @audit_info: NetLabel audit information
489 *
490 * Description:
491 * Removes an entry from the domain hash table and handles any updates to the
492 * lower level protocol handler (i.e. CIPSO). Returns zero on success,
493 * negative on failure.
494 *
495 */
496int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
497{
498 int ret_val;
499 struct netlbl_dom_map *entry;
500
501 rcu_read_lock();
502 if (domain)
503 entry = netlbl_domhsh_search(domain);
504 else
505 entry = netlbl_domhsh_search_def(domain);
506 ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
507 rcu_read_unlock();
508
358 return ret_val; 509 return ret_val;
359} 510}
360 511
@@ -389,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
389} 540}
390 541
391/** 542/**
543 * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
544 * @domain: the domain name to search for
545 * @addr: the IP address to search for
546 *
547 * Description:
548 * Look through the domain hash table searching for an entry to match @domain
549 * and @addr, return a pointer to a copy of the entry or NULL. The caller is
550 * responsible for ensuring that rcu_read_[un]lock() is called.
551 *
552 */
553struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
554 __be32 addr)
555{
556 struct netlbl_dom_map *dom_iter;
557 struct netlbl_af4list *addr_iter;
558
559 dom_iter = netlbl_domhsh_search_def(domain);
560 if (dom_iter == NULL)
561 return NULL;
562 if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
563 return NULL;
564
565 addr_iter = netlbl_af4list_search(addr,
566 &dom_iter->type_def.addrsel->list4);
567 if (addr_iter == NULL)
568 return NULL;
569
570 return netlbl_domhsh_addr4_entry(addr_iter);
571}
572
573#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
574/**
575 * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
576 * @domain: the domain name to search for
577 * @addr: the IP address to search for
578 *
579 * Description:
580 * Look through the domain hash table searching for an entry to match @domain
581 * and @addr, return a pointer to a copy of the entry or NULL. The caller is
582 * responsible for ensuring that rcu_read_[un]lock() is called.
583 *
584 */
585struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
586 const struct in6_addr *addr)
587{
588 struct netlbl_dom_map *dom_iter;
589 struct netlbl_af6list *addr_iter;
590
591 dom_iter = netlbl_domhsh_search_def(domain);
592 if (dom_iter == NULL)
593 return NULL;
594 if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
595 return NULL;
596
597 addr_iter = netlbl_af6list_search(addr,
598 &dom_iter->type_def.addrsel->list6);
599 if (addr_iter == NULL)
600 return NULL;
601
602 return netlbl_domhsh_addr6_entry(addr_iter);
603}
604#endif /* IPv6 */
605
606/**
392 * netlbl_domhsh_walk - Iterate through the domain mapping hash table 607 * netlbl_domhsh_walk - Iterate through the domain mapping hash table
393 * @skip_bkt: the number of buckets to skip at the start 608 * @skip_bkt: the number of buckets to skip at the start
394 * @skip_chain: the number of entries to skip in the first iterated bucket 609 * @skip_chain: the number of entries to skip in the first iterated bucket
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
410{ 625{
411 int ret_val = -ENOENT; 626 int ret_val = -ENOENT;
412 u32 iter_bkt; 627 u32 iter_bkt;
628 struct list_head *iter_list;
413 struct netlbl_dom_map *iter_entry; 629 struct netlbl_dom_map *iter_entry;
414 u32 chain_cnt = 0; 630 u32 chain_cnt = 0;
415 631
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
417 for (iter_bkt = *skip_bkt; 633 for (iter_bkt = *skip_bkt;
418 iter_bkt < rcu_dereference(netlbl_domhsh)->size; 634 iter_bkt < rcu_dereference(netlbl_domhsh)->size;
419 iter_bkt++, chain_cnt = 0) { 635 iter_bkt++, chain_cnt = 0) {
420 list_for_each_entry_rcu(iter_entry, 636 iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
421 &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt], 637 list_for_each_entry_rcu(iter_entry, iter_list, list)
422 list)
423 if (iter_entry->valid) { 638 if (iter_entry->valid) {
424 if (chain_cnt++ < *skip_chain) 639 if (chain_cnt++ < *skip_chain)
425 continue; 640 continue;
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 8220990ceb96..bfcb6763a1a1 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13/* 13/*
14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15 * 15 *
16 * This program is free software; you can redistribute it and/or modify 16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
@@ -36,16 +36,43 @@
36#include <linux/rcupdate.h> 36#include <linux/rcupdate.h>
37#include <linux/list.h> 37#include <linux/list.h>
38 38
39#include "netlabel_addrlist.h"
40
39/* Domain hash table size */ 41/* Domain hash table size */
40/* XXX - currently this number is an uneducated guess */ 42/* XXX - currently this number is an uneducated guess */
41#define NETLBL_DOMHSH_BITSIZE 7 43#define NETLBL_DOMHSH_BITSIZE 7
42 44
43/* Domain mapping definition struct */ 45/* Domain mapping definition structures */
46#define netlbl_domhsh_addr4_entry(iter) \
47 container_of(iter, struct netlbl_domaddr4_map, list)
48struct netlbl_domaddr4_map {
49 u32 type;
50 union {
51 struct cipso_v4_doi *cipsov4;
52 } type_def;
53
54 struct netlbl_af4list list;
55};
56#define netlbl_domhsh_addr6_entry(iter) \
57 container_of(iter, struct netlbl_domaddr6_map, list)
58struct netlbl_domaddr6_map {
59 u32 type;
60
61 /* NOTE: no 'type_def' union needed at present since we don't currently
62 * support any IPv6 labeling protocols */
63
64 struct netlbl_af6list list;
65};
66struct netlbl_domaddr_map {
67 struct list_head list4;
68 struct list_head list6;
69};
44struct netlbl_dom_map { 70struct netlbl_dom_map {
45 char *domain; 71 char *domain;
46 u32 type; 72 u32 type;
47 union { 73 union {
48 struct cipso_v4_doi *cipsov4; 74 struct cipso_v4_doi *cipsov4;
75 struct netlbl_domaddr_map *addrsel;
49 } type_def; 76 } type_def;
50 77
51 u32 valid; 78 u32 valid;
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
61 struct netlbl_audit *audit_info); 88 struct netlbl_audit *audit_info);
62int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, 89int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
63 struct netlbl_audit *audit_info); 90 struct netlbl_audit *audit_info);
91int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
92 struct netlbl_audit *audit_info);
64int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 93int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
65int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); 94int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
66struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); 95struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
96struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
97 __be32 addr);
67int netlbl_domhsh_walk(u32 *skip_bkt, 98int netlbl_domhsh_walk(u32 *skip_bkt,
68 u32 *skip_chain, 99 u32 *skip_chain,
69 int (*callback) (struct netlbl_dom_map *entry, void *arg), 100 int (*callback) (struct netlbl_dom_map *entry, void *arg),
70 void *cb_arg); 101 void *cb_arg);
71 102
103#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
104struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
105 const struct in6_addr *addr);
106#endif /* IPv6 */
107
72#endif 108#endif
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 39793a1a93aa..b32eceb3ab0d 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
82 82
83 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 83 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
84 if (entry == NULL) 84 if (entry == NULL)
85 goto cfg_unlbl_add_map_failure; 85 return -ENOMEM;
86 if (domain != NULL) { 86 if (domain != NULL) {
87 entry->domain = kstrdup(domain, GFP_ATOMIC); 87 entry->domain = kstrdup(domain, GFP_ATOMIC);
88 if (entry->domain == NULL) 88 if (entry->domain == NULL)
@@ -104,49 +104,6 @@ cfg_unlbl_add_map_failure:
104} 104}
105 105
106/** 106/**
107 * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
108 * @doi_def: the DOI definition
109 * @audit_info: NetLabel audit information
110 *
111 * Description:
112 * Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on
113 * success, negative values on failure.
114 *
115 */
116int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
117 struct netlbl_audit *audit_info)
118{
119 int ret_val;
120 const char *type_str;
121 struct audit_buffer *audit_buf;
122
123 ret_val = cipso_v4_doi_add(doi_def);
124
125 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
126 audit_info);
127 if (audit_buf != NULL) {
128 switch (doi_def->type) {
129 case CIPSO_V4_MAP_STD:
130 type_str = "std";
131 break;
132 case CIPSO_V4_MAP_PASS:
133 type_str = "pass";
134 break;
135 default:
136 type_str = "(unknown)";
137 }
138 audit_log_format(audit_buf,
139 " cipso_doi=%u cipso_type=%s res=%u",
140 doi_def->doi,
141 type_str,
142 ret_val == 0 ? 1 : 0);
143 audit_log_end(audit_buf);
144 }
145
146 return ret_val;
147}
148
149/**
150 * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping 107 * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
151 * @doi_def: the DOI definition 108 * @doi_def: the DOI definition
152 * @domain: the domain mapping to add 109 * @domain: the domain mapping to add
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
164 struct netlbl_audit *audit_info) 121 struct netlbl_audit *audit_info)
165{ 122{
166 int ret_val = -ENOMEM; 123 int ret_val = -ENOMEM;
124 u32 doi;
125 u32 doi_type;
167 struct netlbl_dom_map *entry; 126 struct netlbl_dom_map *entry;
127 const char *type_str;
128 struct audit_buffer *audit_buf;
129
130 doi = doi_def->doi;
131 doi_type = doi_def->type;
168 132
169 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 133 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
170 if (entry == NULL) 134 if (entry == NULL)
171 goto cfg_cipsov4_add_map_failure; 135 return -ENOMEM;
172 if (domain != NULL) { 136 if (domain != NULL) {
173 entry->domain = kstrdup(domain, GFP_ATOMIC); 137 entry->domain = kstrdup(domain, GFP_ATOMIC);
174 if (entry->domain == NULL) 138 if (entry->domain == NULL)
175 goto cfg_cipsov4_add_map_failure; 139 goto cfg_cipsov4_add_map_failure;
176 } 140 }
177 entry->type = NETLBL_NLTYPE_CIPSOV4;
178 entry->type_def.cipsov4 = doi_def;
179
180 /* Grab a RCU read lock here so nothing happens to the doi_def variable
181 * between adding it to the CIPSOv4 protocol engine and adding a
182 * domain mapping for it. */
183 141
184 rcu_read_lock(); 142 ret_val = cipso_v4_doi_add(doi_def);
185 ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
186 if (ret_val != 0) 143 if (ret_val != 0)
187 goto cfg_cipsov4_add_map_failure_unlock; 144 goto cfg_cipsov4_add_map_failure_remove_doi;
145 entry->type = NETLBL_NLTYPE_CIPSOV4;
146 entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
147 if (entry->type_def.cipsov4 == NULL) {
148 ret_val = -ENOENT;
149 goto cfg_cipsov4_add_map_failure_remove_doi;
150 }
188 ret_val = netlbl_domhsh_add(entry, audit_info); 151 ret_val = netlbl_domhsh_add(entry, audit_info);
189 if (ret_val != 0) 152 if (ret_val != 0)
190 goto cfg_cipsov4_add_map_failure_remove_doi; 153 goto cfg_cipsov4_add_map_failure_release_doi;
191 rcu_read_unlock();
192 154
193 return 0; 155cfg_cipsov4_add_map_return:
156 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
157 audit_info);
158 if (audit_buf != NULL) {
159 switch (doi_type) {
160 case CIPSO_V4_MAP_TRANS:
161 type_str = "trans";
162 break;
163 case CIPSO_V4_MAP_PASS:
164 type_str = "pass";
165 break;
166 case CIPSO_V4_MAP_LOCAL:
167 type_str = "local";
168 break;
169 default:
170 type_str = "(unknown)";
171 }
172 audit_log_format(audit_buf,
173 " cipso_doi=%u cipso_type=%s res=%u",
174 doi, type_str, ret_val == 0 ? 1 : 0);
175 audit_log_end(audit_buf);
176 }
194 177
178 return ret_val;
179
180cfg_cipsov4_add_map_failure_release_doi:
181 cipso_v4_doi_putdef(doi_def);
195cfg_cipsov4_add_map_failure_remove_doi: 182cfg_cipsov4_add_map_failure_remove_doi:
196 cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free); 183 cipso_v4_doi_remove(doi, audit_info);
197cfg_cipsov4_add_map_failure_unlock:
198 rcu_read_unlock();
199cfg_cipsov4_add_map_failure: 184cfg_cipsov4_add_map_failure:
200 if (entry != NULL) 185 if (entry != NULL)
201 kfree(entry->domain); 186 kfree(entry->domain);
202 kfree(entry); 187 kfree(entry);
203 return ret_val; 188 goto cfg_cipsov4_add_map_return;
204}
205
206/**
207 * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
208 * @doi: the CIPSO DOI value
209 * @audit_info: NetLabel audit information
210 *
211 * Description:
212 * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
213 * Returns zero on success, negative values on failure.
214 *
215 */
216int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
217{
218 return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
219} 189}
220 190
221/* 191/*
@@ -452,7 +422,9 @@ int netlbl_enabled(void)
452 * Attach the correct label to the given socket using the security attributes 422 * Attach the correct label to the given socket using the security attributes
453 * specified in @secattr. This function requires exclusive access to @sk, 423 * specified in @secattr. This function requires exclusive access to @sk,
454 * which means it either needs to be in the process of being created or locked. 424 * which means it either needs to be in the process of being created or locked.
455 * Returns zero on success, negative values on failure. 425 * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
426 * network address selectors (can't blindly label the socket), and negative
427 * values on all other failures.
456 * 428 *
457 */ 429 */
458int netlbl_sock_setattr(struct sock *sk, 430int netlbl_sock_setattr(struct sock *sk,
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk,
466 if (dom_entry == NULL) 438 if (dom_entry == NULL)
467 goto socket_setattr_return; 439 goto socket_setattr_return;
468 switch (dom_entry->type) { 440 switch (dom_entry->type) {
441 case NETLBL_NLTYPE_ADDRSELECT:
442 ret_val = -EDESTADDRREQ;
443 break;
469 case NETLBL_NLTYPE_CIPSOV4: 444 case NETLBL_NLTYPE_CIPSOV4:
470 ret_val = cipso_v4_sock_setattr(sk, 445 ret_val = cipso_v4_sock_setattr(sk,
471 dom_entry->type_def.cipsov4, 446 dom_entry->type_def.cipsov4,
@@ -484,6 +459,20 @@ socket_setattr_return:
484} 459}
485 460
486/** 461/**
462 * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
463 * @sk: the socket
464 *
465 * Description:
466 * Remove all the NetLabel labeling from @sk. The caller is responsible for
467 * ensuring that @sk is locked.
468 *
469 */
470void netlbl_sock_delattr(struct sock *sk)
471{
472 cipso_v4_sock_delattr(sk);
473}
474
475/**
487 * netlbl_sock_getattr - Determine the security attributes of a sock 476 * netlbl_sock_getattr - Determine the security attributes of a sock
488 * @sk: the sock 477 * @sk: the sock
489 * @secattr: the security attributes 478 * @secattr: the security attributes
@@ -501,6 +490,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
501} 490}
502 491
503/** 492/**
493 * netlbl_conn_setattr - Label a connected socket using the correct protocol
494 * @sk: the socket to label
495 * @addr: the destination address
496 * @secattr: the security attributes
497 *
498 * Description:
499 * Attach the correct label to the given connected socket using the security
500 * attributes specified in @secattr. The caller is responsible for ensuring
501 * that @sk is locked. Returns zero on success, negative values on failure.
502 *
503 */
504int netlbl_conn_setattr(struct sock *sk,
505 struct sockaddr *addr,
506 const struct netlbl_lsm_secattr *secattr)
507{
508 int ret_val;
509 struct sockaddr_in *addr4;
510 struct netlbl_domaddr4_map *af4_entry;
511
512 rcu_read_lock();
513 switch (addr->sa_family) {
514 case AF_INET:
515 addr4 = (struct sockaddr_in *)addr;
516 af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
517 addr4->sin_addr.s_addr);
518 if (af4_entry == NULL) {
519 ret_val = -ENOENT;
520 goto conn_setattr_return;
521 }
522 switch (af4_entry->type) {
523 case NETLBL_NLTYPE_CIPSOV4:
524 ret_val = cipso_v4_sock_setattr(sk,
525 af4_entry->type_def.cipsov4,
526 secattr);
527 break;
528 case NETLBL_NLTYPE_UNLABELED:
529 /* just delete the protocols we support for right now
530 * but we could remove other protocols if needed */
531 cipso_v4_sock_delattr(sk);
532 ret_val = 0;
533 break;
534 default:
535 ret_val = -ENOENT;
536 }
537 break;
538#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
539 case AF_INET6:
540 /* since we don't support any IPv6 labeling protocols right
541 * now we can optimize everything away until we do */
542 ret_val = 0;
543 break;
544#endif /* IPv6 */
545 default:
546 ret_val = 0;
547 }
548
549conn_setattr_return:
550 rcu_read_unlock();
551 return ret_val;
552}
553
554/**
555 * netlbl_skbuff_setattr - Label a packet using the correct protocol
556 * @skb: the packet
557 * @family: protocol family
558 * @secattr: the security attributes
559 *
560 * Description:
561 * Attach the correct label to the given packet using the security attributes
562 * specified in @secattr. Returns zero on success, negative values on failure.
563 *
564 */
565int netlbl_skbuff_setattr(struct sk_buff *skb,
566 u16 family,
567 const struct netlbl_lsm_secattr *secattr)
568{
569 int ret_val;
570 struct iphdr *hdr4;
571 struct netlbl_domaddr4_map *af4_entry;
572
573 rcu_read_lock();
574 switch (family) {
575 case AF_INET:
576 hdr4 = ip_hdr(skb);
577 af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
578 hdr4->daddr);
579 if (af4_entry == NULL) {
580 ret_val = -ENOENT;
581 goto skbuff_setattr_return;
582 }
583 switch (af4_entry->type) {
584 case NETLBL_NLTYPE_CIPSOV4:
585 ret_val = cipso_v4_skbuff_setattr(skb,
586 af4_entry->type_def.cipsov4,
587 secattr);
588 break;
589 case NETLBL_NLTYPE_UNLABELED:
590 /* just delete the protocols we support for right now
591 * but we could remove other protocols if needed */
592 ret_val = cipso_v4_skbuff_delattr(skb);
593 break;
594 default:
595 ret_val = -ENOENT;
596 }
597 break;
598#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
599 case AF_INET6:
600 /* since we don't support any IPv6 labeling protocols right
601 * now we can optimize everything away until we do */
602 ret_val = 0;
603 break;
604#endif /* IPv6 */
605 default:
606 ret_val = 0;
607 }
608
609skbuff_setattr_return:
610 rcu_read_unlock();
611 return ret_val;
612}
613
614/**
504 * netlbl_skbuff_getattr - Determine the security attributes of a packet 615 * netlbl_skbuff_getattr - Determine the security attributes of a packet
505 * @skb: the packet 616 * @skb: the packet
506 * @family: protocol family 617 * @family: protocol family
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
528 * netlbl_skbuff_err - Handle a LSM error on a sk_buff 639 * netlbl_skbuff_err - Handle a LSM error on a sk_buff
529 * @skb: the packet 640 * @skb: the packet
530 * @error: the error code 641 * @error: the error code
642 * @gateway: true if host is acting as a gateway, false otherwise
531 * 643 *
532 * Description: 644 * Description:
533 * Deal with a LSM problem when handling the packet in @skb, typically this is 645 * Deal with a LSM problem when handling the packet in @skb, typically this is
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
535 * according to the packet's labeling protocol. 647 * according to the packet's labeling protocol.
536 * 648 *
537 */ 649 */
538void netlbl_skbuff_err(struct sk_buff *skb, int error) 650void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
539{ 651{
540 if (CIPSO_V4_OPTEXIST(skb)) 652 if (CIPSO_V4_OPTEXIST(skb))
541 cipso_v4_error(skb, error, 0); 653 cipso_v4_error(skb, error, gateway);
542} 654}
543 655
544/** 656/**
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 44be5d5261f4..ee769ecaa13c 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -32,9 +32,13 @@
32#include <linux/socket.h> 32#include <linux/socket.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/skbuff.h> 34#include <linux/skbuff.h>
35#include <linux/in.h>
36#include <linux/in6.h>
35#include <net/sock.h> 37#include <net/sock.h>
36#include <net/netlink.h> 38#include <net/netlink.h>
37#include <net/genetlink.h> 39#include <net/genetlink.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
38#include <net/netlabel.h> 42#include <net/netlabel.h>
39#include <net/cipso_ipv4.h> 43#include <net/cipso_ipv4.h>
40#include <asm/atomic.h> 44#include <asm/atomic.h>
@@ -71,86 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
71}; 75};
72 76
73/* 77/*
74 * NetLabel Command Handlers 78 * Helper Functions
75 */ 79 */
76 80
77/** 81/**
78 * netlbl_mgmt_add - Handle an ADD message 82 * netlbl_mgmt_add - Handle an ADD message
79 * @skb: the NETLINK buffer
80 * @info: the Generic NETLINK info block 83 * @info: the Generic NETLINK info block
84 * @audit_info: NetLabel audit information
81 * 85 *
82 * Description: 86 * Description:
83 * Process a user generated ADD message and add the domains from the message 87 * Helper function for the ADD and ADDDEF messages to add the domain mappings
84 * to the hash table. See netlabel.h for a description of the message format. 88 * from the message to the hash table. See netlabel.h for a description of the
85 * Returns zero on success, negative values on failure. 89 * message format. Returns zero on success, negative values on failure.
86 * 90 *
87 */ 91 */
88static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 92static int netlbl_mgmt_add_common(struct genl_info *info,
93 struct netlbl_audit *audit_info)
89{ 94{
90 int ret_val = -EINVAL; 95 int ret_val = -EINVAL;
91 struct netlbl_dom_map *entry = NULL; 96 struct netlbl_dom_map *entry = NULL;
92 size_t tmp_size; 97 struct netlbl_domaddr_map *addrmap = NULL;
98 struct cipso_v4_doi *cipsov4 = NULL;
93 u32 tmp_val; 99 u32 tmp_val;
94 struct netlbl_audit audit_info;
95
96 if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
97 !info->attrs[NLBL_MGMT_A_PROTOCOL])
98 goto add_failure;
99
100 netlbl_netlink_auditinfo(skb, &audit_info);
101 100
102 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 101 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
103 if (entry == NULL) { 102 if (entry == NULL) {
104 ret_val = -ENOMEM; 103 ret_val = -ENOMEM;
105 goto add_failure; 104 goto add_failure;
106 } 105 }
107 tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
108 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
109 if (entry->domain == NULL) {
110 ret_val = -ENOMEM;
111 goto add_failure;
112 }
113 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 106 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
114 nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 107 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
108 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
109 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
110 if (entry->domain == NULL) {
111 ret_val = -ENOMEM;
112 goto add_failure;
113 }
114 nla_strlcpy(entry->domain,
115 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
116 }
117
118 /* NOTE: internally we allow/use a entry->type value of
119 * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
120 * to pass that as a protocol value because we need to know the
121 * "real" protocol */
115 122
116 switch (entry->type) { 123 switch (entry->type) {
117 case NETLBL_NLTYPE_UNLABELED: 124 case NETLBL_NLTYPE_UNLABELED:
118 ret_val = netlbl_domhsh_add(entry, &audit_info);
119 break; 125 break;
120 case NETLBL_NLTYPE_CIPSOV4: 126 case NETLBL_NLTYPE_CIPSOV4:
121 if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 127 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
122 goto add_failure; 128 goto add_failure;
123 129
124 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 130 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
125 /* We should be holding a rcu_read_lock() here while we hold 131 cipsov4 = cipso_v4_doi_getdef(tmp_val);
126 * the result but since the entry will always be deleted when 132 if (cipsov4 == NULL)
127 * the CIPSO DOI is deleted we aren't going to keep the
128 * lock. */
129 rcu_read_lock();
130 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
131 if (entry->type_def.cipsov4 == NULL) {
132 rcu_read_unlock();
133 goto add_failure; 133 goto add_failure;
134 } 134 entry->type_def.cipsov4 = cipsov4;
135 ret_val = netlbl_domhsh_add(entry, &audit_info);
136 rcu_read_unlock();
137 break; 135 break;
138 default: 136 default:
139 goto add_failure; 137 goto add_failure;
140 } 138 }
139
140 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
141 struct in_addr *addr;
142 struct in_addr *mask;
143 struct netlbl_domaddr4_map *map;
144
145 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
146 if (addrmap == NULL) {
147 ret_val = -ENOMEM;
148 goto add_failure;
149 }
150 INIT_LIST_HEAD(&addrmap->list4);
151 INIT_LIST_HEAD(&addrmap->list6);
152
153 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
154 sizeof(struct in_addr)) {
155 ret_val = -EINVAL;
156 goto add_failure;
157 }
158 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
159 sizeof(struct in_addr)) {
160 ret_val = -EINVAL;
161 goto add_failure;
162 }
163 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
164 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
165
166 map = kzalloc(sizeof(*map), GFP_KERNEL);
167 if (map == NULL) {
168 ret_val = -ENOMEM;
169 goto add_failure;
170 }
171 map->list.addr = addr->s_addr & mask->s_addr;
172 map->list.mask = mask->s_addr;
173 map->list.valid = 1;
174 map->type = entry->type;
175 if (cipsov4)
176 map->type_def.cipsov4 = cipsov4;
177
178 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
179 if (ret_val != 0) {
180 kfree(map);
181 goto add_failure;
182 }
183
184 entry->type = NETLBL_NLTYPE_ADDRSELECT;
185 entry->type_def.addrsel = addrmap;
186#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
187 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
188 struct in6_addr *addr;
189 struct in6_addr *mask;
190 struct netlbl_domaddr6_map *map;
191
192 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
193 if (addrmap == NULL) {
194 ret_val = -ENOMEM;
195 goto add_failure;
196 }
197 INIT_LIST_HEAD(&addrmap->list4);
198 INIT_LIST_HEAD(&addrmap->list6);
199
200 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
201 sizeof(struct in6_addr)) {
202 ret_val = -EINVAL;
203 goto add_failure;
204 }
205 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
206 sizeof(struct in6_addr)) {
207 ret_val = -EINVAL;
208 goto add_failure;
209 }
210 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
211 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
212
213 map = kzalloc(sizeof(*map), GFP_KERNEL);
214 if (map == NULL) {
215 ret_val = -ENOMEM;
216 goto add_failure;
217 }
218 ipv6_addr_copy(&map->list.addr, addr);
219 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
220 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
221 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
222 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
223 ipv6_addr_copy(&map->list.mask, mask);
224 map->list.valid = 1;
225 map->type = entry->type;
226
227 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
228 if (ret_val != 0) {
229 kfree(map);
230 goto add_failure;
231 }
232
233 entry->type = NETLBL_NLTYPE_ADDRSELECT;
234 entry->type_def.addrsel = addrmap;
235#endif /* IPv6 */
236 }
237
238 ret_val = netlbl_domhsh_add(entry, audit_info);
141 if (ret_val != 0) 239 if (ret_val != 0)
142 goto add_failure; 240 goto add_failure;
143 241
144 return 0; 242 return 0;
145 243
146add_failure: 244add_failure:
245 if (cipsov4)
246 cipso_v4_doi_putdef(cipsov4);
147 if (entry) 247 if (entry)
148 kfree(entry->domain); 248 kfree(entry->domain);
249 kfree(addrmap);
149 kfree(entry); 250 kfree(entry);
150 return ret_val; 251 return ret_val;
151} 252}
152 253
153/** 254/**
255 * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
256 * @skb: the NETLINK buffer
257 * @entry: the map entry
258 *
259 * Description:
260 * This function is a helper function used by the LISTALL and LISTDEF command
261 * handlers. The caller is responsibile for ensuring that the RCU read lock
262 * is held. Returns zero on success, negative values on failure.
263 *
264 */
265static int netlbl_mgmt_listentry(struct sk_buff *skb,
266 struct netlbl_dom_map *entry)
267{
268 int ret_val;
269 struct nlattr *nla_a;
270 struct nlattr *nla_b;
271 struct netlbl_af4list *iter4;
272#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
273 struct netlbl_af6list *iter6;
274#endif
275
276 if (entry->domain != NULL) {
277 ret_val = nla_put_string(skb,
278 NLBL_MGMT_A_DOMAIN, entry->domain);
279 if (ret_val != 0)
280 return ret_val;
281 }
282
283 switch (entry->type) {
284 case NETLBL_NLTYPE_ADDRSELECT:
285 nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
286 if (nla_a == NULL)
287 return -ENOMEM;
288
289 netlbl_af4list_foreach_rcu(iter4,
290 &entry->type_def.addrsel->list4) {
291 struct netlbl_domaddr4_map *map4;
292 struct in_addr addr_struct;
293
294 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
295 if (nla_b == NULL)
296 return -ENOMEM;
297
298 addr_struct.s_addr = iter4->addr;
299 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
300 sizeof(struct in_addr),
301 &addr_struct);
302 if (ret_val != 0)
303 return ret_val;
304 addr_struct.s_addr = iter4->mask;
305 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
306 sizeof(struct in_addr),
307 &addr_struct);
308 if (ret_val != 0)
309 return ret_val;
310 map4 = netlbl_domhsh_addr4_entry(iter4);
311 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
312 map4->type);
313 if (ret_val != 0)
314 return ret_val;
315 switch (map4->type) {
316 case NETLBL_NLTYPE_CIPSOV4:
317 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
318 map4->type_def.cipsov4->doi);
319 if (ret_val != 0)
320 return ret_val;
321 break;
322 }
323
324 nla_nest_end(skb, nla_b);
325 }
326#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
327 netlbl_af6list_foreach_rcu(iter6,
328 &entry->type_def.addrsel->list6) {
329 struct netlbl_domaddr6_map *map6;
330
331 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
332 if (nla_b == NULL)
333 return -ENOMEM;
334
335 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
336 sizeof(struct in6_addr),
337 &iter6->addr);
338 if (ret_val != 0)
339 return ret_val;
340 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
341 sizeof(struct in6_addr),
342 &iter6->mask);
343 if (ret_val != 0)
344 return ret_val;
345 map6 = netlbl_domhsh_addr6_entry(iter6);
346 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
347 map6->type);
348 if (ret_val != 0)
349 return ret_val;
350
351 nla_nest_end(skb, nla_b);
352 }
353#endif /* IPv6 */
354
355 nla_nest_end(skb, nla_a);
356 break;
357 case NETLBL_NLTYPE_UNLABELED:
358 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
359 break;
360 case NETLBL_NLTYPE_CIPSOV4:
361 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
362 if (ret_val != 0)
363 return ret_val;
364 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
365 entry->type_def.cipsov4->doi);
366 break;
367 }
368
369 return ret_val;
370}
371
372/*
373 * NetLabel Command Handlers
374 */
375
376/**
377 * netlbl_mgmt_add - Handle an ADD message
378 * @skb: the NETLINK buffer
379 * @info: the Generic NETLINK info block
380 *
381 * Description:
382 * Process a user generated ADD message and add the domains from the message
383 * to the hash table. See netlabel.h for a description of the message format.
384 * Returns zero on success, negative values on failure.
385 *
386 */
387static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
388{
389 struct netlbl_audit audit_info;
390
391 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
392 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
393 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
394 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
395 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
396 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
397 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
398 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
399 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
400 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
401 return -EINVAL;
402
403 netlbl_netlink_auditinfo(skb, &audit_info);
404
405 return netlbl_mgmt_add_common(info, &audit_info);
406}
407
408/**
154 * netlbl_mgmt_remove - Handle a REMOVE message 409 * netlbl_mgmt_remove - Handle a REMOVE message
155 * @skb: the NETLINK buffer 410 * @skb: the NETLINK buffer
156 * @info: the Generic NETLINK info block 411 * @info: the Generic NETLINK info block
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
198 if (data == NULL) 453 if (data == NULL)
199 goto listall_cb_failure; 454 goto listall_cb_failure;
200 455
201 ret_val = nla_put_string(cb_arg->skb, 456 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
202 NLBL_MGMT_A_DOMAIN,
203 entry->domain);
204 if (ret_val != 0) 457 if (ret_val != 0)
205 goto listall_cb_failure; 458 goto listall_cb_failure;
206 ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
207 if (ret_val != 0)
208 goto listall_cb_failure;
209 switch (entry->type) {
210 case NETLBL_NLTYPE_CIPSOV4:
211 ret_val = nla_put_u32(cb_arg->skb,
212 NLBL_MGMT_A_CV4DOI,
213 entry->type_def.cipsov4->doi);
214 if (ret_val != 0)
215 goto listall_cb_failure;
216 break;
217 }
218 459
219 cb_arg->seq++; 460 cb_arg->seq++;
220 return genlmsg_end(cb_arg->skb, data); 461 return genlmsg_end(cb_arg->skb, data);
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
268 */ 509 */
269static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 510static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
270{ 511{
271 int ret_val = -EINVAL;
272 struct netlbl_dom_map *entry = NULL;
273 u32 tmp_val;
274 struct netlbl_audit audit_info; 512 struct netlbl_audit audit_info;
275 513
276 if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 514 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
277 goto adddef_failure; 515 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
516 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
517 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
518 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
519 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
520 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
521 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
522 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
523 return -EINVAL;
278 524
279 netlbl_netlink_auditinfo(skb, &audit_info); 525 netlbl_netlink_auditinfo(skb, &audit_info);
280 526
281 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 527 return netlbl_mgmt_add_common(info, &audit_info);
282 if (entry == NULL) {
283 ret_val = -ENOMEM;
284 goto adddef_failure;
285 }
286 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
287
288 switch (entry->type) {
289 case NETLBL_NLTYPE_UNLABELED:
290 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
291 break;
292 case NETLBL_NLTYPE_CIPSOV4:
293 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
294 goto adddef_failure;
295
296 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
297 /* We should be holding a rcu_read_lock() here while we hold
298 * the result but since the entry will always be deleted when
299 * the CIPSO DOI is deleted we aren't going to keep the
300 * lock. */
301 rcu_read_lock();
302 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
303 if (entry->type_def.cipsov4 == NULL) {
304 rcu_read_unlock();
305 goto adddef_failure;
306 }
307 ret_val = netlbl_domhsh_add_default(entry, &audit_info);
308 rcu_read_unlock();
309 break;
310 default:
311 goto adddef_failure;
312 }
313 if (ret_val != 0)
314 goto adddef_failure;
315
316 return 0;
317
318adddef_failure:
319 kfree(entry);
320 return ret_val;
321} 528}
322 529
323/** 530/**
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
371 ret_val = -ENOENT; 578 ret_val = -ENOENT;
372 goto listdef_failure_lock; 579 goto listdef_failure_lock;
373 } 580 }
374 ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 581 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
375 if (ret_val != 0)
376 goto listdef_failure_lock;
377 switch (entry->type) {
378 case NETLBL_NLTYPE_CIPSOV4:
379 ret_val = nla_put_u32(ans_skb,
380 NLBL_MGMT_A_CV4DOI,
381 entry->type_def.cipsov4->doi);
382 if (ret_val != 0)
383 goto listdef_failure_lock;
384 break;
385 }
386 rcu_read_unlock(); 582 rcu_read_unlock();
583 if (ret_val != 0)
584 goto listdef_failure;
387 585
388 genlmsg_end(ans_skb, data); 586 genlmsg_end(ans_skb, data);
389 return genlmsg_reply(ans_skb, info); 587 return genlmsg_reply(ans_skb, info);
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index a43bff169d6b..05d96431f819 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -45,6 +45,16 @@
45 * NLBL_MGMT_A_DOMAIN 45 * NLBL_MGMT_A_DOMAIN
46 * NLBL_MGMT_A_PROTOCOL 46 * NLBL_MGMT_A_PROTOCOL
47 * 47 *
48 * If IPv4 is specified the following attributes are required:
49 *
50 * NLBL_MGMT_A_IPV4ADDR
51 * NLBL_MGMT_A_IPV4MASK
52 *
53 * If IPv6 is specified the following attributes are required:
54 *
55 * NLBL_MGMT_A_IPV6ADDR
56 * NLBL_MGMT_A_IPV6MASK
57 *
48 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 58 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
49 * 59 *
50 * NLBL_MGMT_A_CV4DOI 60 * NLBL_MGMT_A_CV4DOI
@@ -68,13 +78,24 @@
68 * Required attributes: 78 * Required attributes:
69 * 79 *
70 * NLBL_MGMT_A_DOMAIN 80 * NLBL_MGMT_A_DOMAIN
81 *
82 * If the IP address selectors are not used the following attribute is
83 * required:
84 *
71 * NLBL_MGMT_A_PROTOCOL 85 * NLBL_MGMT_A_PROTOCOL
72 * 86 *
73 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 87 * If the IP address selectors are used then the following attritbute is
88 * required:
89 *
90 * NLBL_MGMT_A_SELECTORLIST
91 *
92 * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
93 * attributes are required:
74 * 94 *
75 * NLBL_MGMT_A_CV4DOI 95 * NLBL_MGMT_A_CV4DOI
76 * 96 *
77 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 97 * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
98 * attributes are required.
78 * 99 *
79 * o ADDDEF: 100 * o ADDDEF:
80 * Sent by an application to set the default domain mapping for the NetLabel 101 * Sent by an application to set the default domain mapping for the NetLabel
@@ -100,15 +121,23 @@
100 * application there is no payload. On success the kernel should send a 121 * application there is no payload. On success the kernel should send a
101 * response using the following format. 122 * response using the following format.
102 * 123 *
103 * Required attributes: 124 * If the IP address selectors are not used the following attribute is
125 * required:
104 * 126 *
105 * NLBL_MGMT_A_PROTOCOL 127 * NLBL_MGMT_A_PROTOCOL
106 * 128 *
107 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 129 * If the IP address selectors are used then the following attritbute is
130 * required:
131 *
132 * NLBL_MGMT_A_SELECTORLIST
133 *
134 * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
135 * attributes are required:
108 * 136 *
109 * NLBL_MGMT_A_CV4DOI 137 * NLBL_MGMT_A_CV4DOI
110 * 138 *
111 * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 139 * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
140 * attributes are required.
112 * 141 *
113 * o PROTOCOLS: 142 * o PROTOCOLS:
114 * Sent by an application to request a list of configured NetLabel protocols 143 * Sent by an application to request a list of configured NetLabel protocols
@@ -162,6 +191,26 @@ enum {
162 NLBL_MGMT_A_CV4DOI, 191 NLBL_MGMT_A_CV4DOI,
163 /* (NLA_U32) 192 /* (NLA_U32)
164 * the CIPSOv4 DOI value */ 193 * the CIPSOv4 DOI value */
194 NLBL_MGMT_A_IPV6ADDR,
195 /* (NLA_BINARY, struct in6_addr)
196 * an IPv6 address */
197 NLBL_MGMT_A_IPV6MASK,
198 /* (NLA_BINARY, struct in6_addr)
199 * an IPv6 address mask */
200 NLBL_MGMT_A_IPV4ADDR,
201 /* (NLA_BINARY, struct in_addr)
202 * an IPv4 address */
203 NLBL_MGMT_A_IPV4MASK,
204 /* (NLA_BINARY, struct in_addr)
205 * and IPv4 address mask */
206 NLBL_MGMT_A_ADDRSELECTOR,
207 /* (NLA_NESTED)
208 * an IP address selector, must contain an address, mask, and protocol
209 * attribute plus any protocol specific attributes */
210 NLBL_MGMT_A_SELECTORLIST,
211 /* (NLA_NESTED)
212 * the selector list, there must be at least one
213 * NLBL_MGMT_A_ADDRSELECTOR attribute */
165 __NLBL_MGMT_A_MAX, 214 __NLBL_MGMT_A_MAX,
166}; 215};
167#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) 216#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 921c118ead89..e8a5c32b0f10 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12/* 12/*
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007 13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
14 * 14 *
15 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
54#include <asm/atomic.h> 54#include <asm/atomic.h>
55 55
56#include "netlabel_user.h" 56#include "netlabel_user.h"
57#include "netlabel_addrlist.h"
57#include "netlabel_domainhash.h" 58#include "netlabel_domainhash.h"
58#include "netlabel_unlabeled.h" 59#include "netlabel_unlabeled.h"
59#include "netlabel_mgmt.h" 60#include "netlabel_mgmt.h"
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
76 struct list_head *tbl; 77 struct list_head *tbl;
77 u32 size; 78 u32 size;
78}; 79};
80#define netlbl_unlhsh_addr4_entry(iter) \
81 container_of(iter, struct netlbl_unlhsh_addr4, list)
79struct netlbl_unlhsh_addr4 { 82struct netlbl_unlhsh_addr4 {
80 __be32 addr;
81 __be32 mask;
82 u32 secid; 83 u32 secid;
83 84
84 u32 valid; 85 struct netlbl_af4list list;
85 struct list_head list;
86 struct rcu_head rcu; 86 struct rcu_head rcu;
87}; 87};
88#define netlbl_unlhsh_addr6_entry(iter) \
89 container_of(iter, struct netlbl_unlhsh_addr6, list)
88struct netlbl_unlhsh_addr6 { 90struct netlbl_unlhsh_addr6 {
89 struct in6_addr addr;
90 struct in6_addr mask;
91 u32 secid; 91 u32 secid;
92 92
93 u32 valid; 93 struct netlbl_af6list list;
94 struct list_head list;
95 struct rcu_head rcu; 94 struct rcu_head rcu;
96}; 95};
97struct netlbl_unlhsh_iface { 96struct netlbl_unlhsh_iface {
@@ -147,76 +146,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
147}; 146};
148 147
149/* 148/*
150 * Audit Helper Functions
151 */
152
153/**
154 * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
155 * @audit_buf: audit buffer
156 * @dev: network interface
157 * @addr: IP address
158 * @mask: IP address mask
159 *
160 * Description:
161 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
162 *
163 */
164static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
165 const char *dev,
166 __be32 addr, __be32 mask)
167{
168 u32 mask_val = ntohl(mask);
169
170 if (dev != NULL)
171 audit_log_format(audit_buf, " netif=%s", dev);
172 audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
173 if (mask_val != 0xffffffff) {
174 u32 mask_len = 0;
175 while (mask_val > 0) {
176 mask_val <<= 1;
177 mask_len++;
178 }
179 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
180 }
181}
182
183#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
184/**
185 * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
186 * @audit_buf: audit buffer
187 * @dev: network interface
188 * @addr: IP address
189 * @mask: IP address mask
190 *
191 * Description:
192 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
193 *
194 */
195static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
196 const char *dev,
197 const struct in6_addr *addr,
198 const struct in6_addr *mask)
199{
200 if (dev != NULL)
201 audit_log_format(audit_buf, " netif=%s", dev);
202 audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
203 if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
204 u32 mask_len = 0;
205 u32 mask_val;
206 int iter = -1;
207 while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
208 mask_len += 32;
209 mask_val = ntohl(mask->s6_addr32[iter]);
210 while (mask_val > 0) {
211 mask_val <<= 1;
212 mask_len++;
213 }
214 audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
215 }
216}
217#endif /* IPv6 */
218
219/*
220 * Unlabeled Connection Hash Table Functions 149 * Unlabeled Connection Hash Table Functions
221 */ 150 */
222 151
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
274static void netlbl_unlhsh_free_iface(struct rcu_head *entry) 203static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
275{ 204{
276 struct netlbl_unlhsh_iface *iface; 205 struct netlbl_unlhsh_iface *iface;
277 struct netlbl_unlhsh_addr4 *iter4; 206 struct netlbl_af4list *iter4;
278 struct netlbl_unlhsh_addr4 *tmp4; 207 struct netlbl_af4list *tmp4;
279 struct netlbl_unlhsh_addr6 *iter6; 208#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
280 struct netlbl_unlhsh_addr6 *tmp6; 209 struct netlbl_af6list *iter6;
210 struct netlbl_af6list *tmp6;
211#endif /* IPv6 */
281 212
282 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); 213 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
283 214
284 /* no need for locks here since we are the only one with access to this 215 /* no need for locks here since we are the only one with access to this
285 * structure */ 216 * structure */
286 217
287 list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list) 218 netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
288 if (iter4->valid) { 219 netlbl_af4list_remove_entry(iter4);
289 list_del_rcu(&iter4->list); 220 kfree(netlbl_unlhsh_addr4_entry(iter4));
290 kfree(iter4); 221 }
291 } 222#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
292 list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list) 223 netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
293 if (iter6->valid) { 224 netlbl_af6list_remove_entry(iter6);
294 list_del_rcu(&iter6->list); 225 kfree(netlbl_unlhsh_addr6_entry(iter6));
295 kfree(iter6); 226 }
296 } 227#endif /* IPv6 */
297 kfree(iface); 228 kfree(iface);
298} 229}
299 230
@@ -316,59 +247,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
316} 247}
317 248
318/** 249/**
319 * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
320 * @addr: IPv4 address
321 * @iface: the network interface entry
322 *
323 * Description:
324 * Searches the IPv4 address list of the network interface specified by @iface.
325 * If a matching address entry is found it is returned, otherwise NULL is
326 * returned. The caller is responsible for calling the rcu_read_[un]lock()
327 * functions.
328 *
329 */
330static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4(
331 __be32 addr,
332 const struct netlbl_unlhsh_iface *iface)
333{
334 struct netlbl_unlhsh_addr4 *iter;
335
336 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
337 if (iter->valid && (addr & iter->mask) == iter->addr)
338 return iter;
339
340 return NULL;
341}
342
343#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
344/**
345 * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
346 * @addr: IPv6 address
347 * @iface: the network interface entry
348 *
349 * Description:
350 * Searches the IPv6 address list of the network interface specified by @iface.
351 * If a matching address entry is found it is returned, otherwise NULL is
352 * returned. The caller is responsible for calling the rcu_read_[un]lock()
353 * functions.
354 *
355 */
356static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
357 const struct in6_addr *addr,
358 const struct netlbl_unlhsh_iface *iface)
359{
360 struct netlbl_unlhsh_addr6 *iter;
361
362 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
363 if (iter->valid &&
364 ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
365 return iter;
366
367 return NULL;
368}
369#endif /* IPv6 */
370
371/**
372 * netlbl_unlhsh_search_iface - Search for a matching interface entry 250 * netlbl_unlhsh_search_iface - Search for a matching interface entry
373 * @ifindex: the network interface 251 * @ifindex: the network interface
374 * 252 *
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
381static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) 259static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
382{ 260{
383 u32 bkt; 261 u32 bkt;
262 struct list_head *bkt_list;
384 struct netlbl_unlhsh_iface *iter; 263 struct netlbl_unlhsh_iface *iter;
385 264
386 bkt = netlbl_unlhsh_hash(ifindex); 265 bkt = netlbl_unlhsh_hash(ifindex);
387 list_for_each_entry_rcu(iter, 266 bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
388 &rcu_dereference(netlbl_unlhsh)->tbl[bkt], 267 list_for_each_entry_rcu(iter, bkt_list, list)
389 list)
390 if (iter->valid && iter->ifindex == ifindex) 268 if (iter->valid && iter->ifindex == ifindex)
391 return iter; 269 return iter;
392 270
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
439 const struct in_addr *mask, 317 const struct in_addr *mask,
440 u32 secid) 318 u32 secid)
441{ 319{
320 int ret_val;
442 struct netlbl_unlhsh_addr4 *entry; 321 struct netlbl_unlhsh_addr4 *entry;
443 struct netlbl_unlhsh_addr4 *iter;
444 322
445 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 323 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
446 if (entry == NULL) 324 if (entry == NULL)
447 return -ENOMEM; 325 return -ENOMEM;
448 326
449 entry->addr = addr->s_addr & mask->s_addr; 327 entry->list.addr = addr->s_addr & mask->s_addr;
450 entry->mask = mask->s_addr; 328 entry->list.mask = mask->s_addr;
451 entry->secid = secid; 329 entry->list.valid = 1;
452 entry->valid = 1;
453 INIT_RCU_HEAD(&entry->rcu); 330 INIT_RCU_HEAD(&entry->rcu);
331 entry->secid = secid;
454 332
455 spin_lock(&netlbl_unlhsh_lock); 333 spin_lock(&netlbl_unlhsh_lock);
456 iter = netlbl_unlhsh_search_addr4(entry->addr, iface); 334 ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
457 if (iter != NULL &&
458 iter->addr == addr->s_addr && iter->mask == mask->s_addr) {
459 spin_unlock(&netlbl_unlhsh_lock);
460 kfree(entry);
461 return -EEXIST;
462 }
463 /* in order to speed up address searches through the list (the common
464 * case) we need to keep the list in order based on the size of the
465 * address mask such that the entry with the widest mask (smallest
466 * numerical value) appears first in the list */
467 list_for_each_entry_rcu(iter, &iface->addr4_list, list)
468 if (iter->valid &&
469 ntohl(entry->mask) > ntohl(iter->mask)) {
470 __list_add_rcu(&entry->list,
471 iter->list.prev,
472 &iter->list);
473 spin_unlock(&netlbl_unlhsh_lock);
474 return 0;
475 }
476 list_add_tail_rcu(&entry->list, &iface->addr4_list);
477 spin_unlock(&netlbl_unlhsh_lock); 335 spin_unlock(&netlbl_unlhsh_lock);
478 return 0; 336
337 if (ret_val != 0)
338 kfree(entry);
339 return ret_val;
479} 340}
480 341
481#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 342#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
498 const struct in6_addr *mask, 359 const struct in6_addr *mask,
499 u32 secid) 360 u32 secid)
500{ 361{
362 int ret_val;
501 struct netlbl_unlhsh_addr6 *entry; 363 struct netlbl_unlhsh_addr6 *entry;
502 struct netlbl_unlhsh_addr6 *iter;
503 364
504 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 365 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
505 if (entry == NULL) 366 if (entry == NULL)
506 return -ENOMEM; 367 return -ENOMEM;
507 368
508 ipv6_addr_copy(&entry->addr, addr); 369 ipv6_addr_copy(&entry->list.addr, addr);
509 entry->addr.s6_addr32[0] &= mask->s6_addr32[0]; 370 entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
510 entry->addr.s6_addr32[1] &= mask->s6_addr32[1]; 371 entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
511 entry->addr.s6_addr32[2] &= mask->s6_addr32[2]; 372 entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
512 entry->addr.s6_addr32[3] &= mask->s6_addr32[3]; 373 entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
513 ipv6_addr_copy(&entry->mask, mask); 374 ipv6_addr_copy(&entry->list.mask, mask);
514 entry->secid = secid; 375 entry->list.valid = 1;
515 entry->valid = 1;
516 INIT_RCU_HEAD(&entry->rcu); 376 INIT_RCU_HEAD(&entry->rcu);
377 entry->secid = secid;
517 378
518 spin_lock(&netlbl_unlhsh_lock); 379 spin_lock(&netlbl_unlhsh_lock);
519 iter = netlbl_unlhsh_search_addr6(&entry->addr, iface); 380 ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
520 if (iter != NULL &&
521 (ipv6_addr_equal(&iter->addr, addr) &&
522 ipv6_addr_equal(&iter->mask, mask))) {
523 spin_unlock(&netlbl_unlhsh_lock);
524 kfree(entry);
525 return -EEXIST;
526 }
527 /* in order to speed up address searches through the list (the common
528 * case) we need to keep the list in order based on the size of the
529 * address mask such that the entry with the widest mask (smallest
530 * numerical value) appears first in the list */
531 list_for_each_entry_rcu(iter, &iface->addr6_list, list)
532 if (iter->valid &&
533 ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
534 __list_add_rcu(&entry->list,
535 iter->list.prev,
536 &iter->list);
537 spin_unlock(&netlbl_unlhsh_lock);
538 return 0;
539 }
540 list_add_tail_rcu(&entry->list, &iface->addr6_list);
541 spin_unlock(&netlbl_unlhsh_lock); 381 spin_unlock(&netlbl_unlhsh_lock);
382
383 if (ret_val != 0)
384 kfree(entry);
542 return 0; 385 return 0;
543} 386}
544#endif /* IPv6 */ 387#endif /* IPv6 */
@@ -658,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
658 mask4 = (struct in_addr *)mask; 501 mask4 = (struct in_addr *)mask;
659 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); 502 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
660 if (audit_buf != NULL) 503 if (audit_buf != NULL)
661 netlbl_unlabel_audit_addr4(audit_buf, 504 netlbl_af4list_audit_addr(audit_buf, 1,
662 dev_name, 505 dev_name,
663 addr4->s_addr, 506 addr4->s_addr,
664 mask4->s_addr); 507 mask4->s_addr);
665 break; 508 break;
666 } 509 }
667#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 510#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -672,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
672 mask6 = (struct in6_addr *)mask; 515 mask6 = (struct in6_addr *)mask;
673 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); 516 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
674 if (audit_buf != NULL) 517 if (audit_buf != NULL)
675 netlbl_unlabel_audit_addr6(audit_buf, 518 netlbl_af6list_audit_addr(audit_buf, 1,
676 dev_name, 519 dev_name,
677 addr6, mask6); 520 addr6, mask6);
678 break; 521 break;
679 } 522 }
680#endif /* IPv6 */ 523#endif /* IPv6 */
@@ -719,35 +562,34 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
719 const struct in_addr *mask, 562 const struct in_addr *mask,
720 struct netlbl_audit *audit_info) 563 struct netlbl_audit *audit_info)
721{ 564{
722 int ret_val = -ENOENT; 565 int ret_val = 0;
566 struct netlbl_af4list *list_entry;
723 struct netlbl_unlhsh_addr4 *entry; 567 struct netlbl_unlhsh_addr4 *entry;
724 struct audit_buffer *audit_buf = NULL; 568 struct audit_buffer *audit_buf;
725 struct net_device *dev; 569 struct net_device *dev;
726 char *secctx = NULL; 570 char *secctx;
727 u32 secctx_len; 571 u32 secctx_len;
728 572
729 spin_lock(&netlbl_unlhsh_lock); 573 spin_lock(&netlbl_unlhsh_lock);
730 entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface); 574 list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
731 if (entry != NULL && 575 &iface->addr4_list);
732 entry->addr == addr->s_addr && entry->mask == mask->s_addr) {
733 entry->valid = 0;
734 list_del_rcu(&entry->list);
735 ret_val = 0;
736 }
737 spin_unlock(&netlbl_unlhsh_lock); 576 spin_unlock(&netlbl_unlhsh_lock);
577 if (list_entry == NULL)
578 ret_val = -ENOENT;
579 entry = netlbl_unlhsh_addr4_entry(list_entry);
738 580
739 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 581 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
740 audit_info); 582 audit_info);
741 if (audit_buf != NULL) { 583 if (audit_buf != NULL) {
742 dev = dev_get_by_index(net, iface->ifindex); 584 dev = dev_get_by_index(net, iface->ifindex);
743 netlbl_unlabel_audit_addr4(audit_buf, 585 netlbl_af4list_audit_addr(audit_buf, 1,
744 (dev != NULL ? dev->name : NULL), 586 (dev != NULL ? dev->name : NULL),
745 entry->addr, entry->mask); 587 addr->s_addr, mask->s_addr);
746 if (dev != NULL) 588 if (dev != NULL)
747 dev_put(dev); 589 dev_put(dev);
748 if (security_secid_to_secctx(entry->secid, 590 if (entry && security_secid_to_secctx(entry->secid,
749 &secctx, 591 &secctx,
750 &secctx_len) == 0) { 592 &secctx_len) == 0) {
751 audit_log_format(audit_buf, " sec_obj=%s", secctx); 593 audit_log_format(audit_buf, " sec_obj=%s", secctx);
752 security_release_secctx(secctx, secctx_len); 594 security_release_secctx(secctx, secctx_len);
753 } 595 }
@@ -781,36 +623,33 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
781 const struct in6_addr *mask, 623 const struct in6_addr *mask,
782 struct netlbl_audit *audit_info) 624 struct netlbl_audit *audit_info)
783{ 625{
784 int ret_val = -ENOENT; 626 int ret_val = 0;
627 struct netlbl_af6list *list_entry;
785 struct netlbl_unlhsh_addr6 *entry; 628 struct netlbl_unlhsh_addr6 *entry;
786 struct audit_buffer *audit_buf = NULL; 629 struct audit_buffer *audit_buf;
787 struct net_device *dev; 630 struct net_device *dev;
788 char *secctx = NULL; 631 char *secctx;
789 u32 secctx_len; 632 u32 secctx_len;
790 633
791 spin_lock(&netlbl_unlhsh_lock); 634 spin_lock(&netlbl_unlhsh_lock);
792 entry = netlbl_unlhsh_search_addr6(addr, iface); 635 list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
793 if (entry != NULL &&
794 (ipv6_addr_equal(&entry->addr, addr) &&
795 ipv6_addr_equal(&entry->mask, mask))) {
796 entry->valid = 0;
797 list_del_rcu(&entry->list);
798 ret_val = 0;
799 }
800 spin_unlock(&netlbl_unlhsh_lock); 636 spin_unlock(&netlbl_unlhsh_lock);
637 if (list_entry == NULL)
638 ret_val = -ENOENT;
639 entry = netlbl_unlhsh_addr6_entry(list_entry);
801 640
802 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 641 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
803 audit_info); 642 audit_info);
804 if (audit_buf != NULL) { 643 if (audit_buf != NULL) {
805 dev = dev_get_by_index(net, iface->ifindex); 644 dev = dev_get_by_index(net, iface->ifindex);
806 netlbl_unlabel_audit_addr6(audit_buf, 645 netlbl_af6list_audit_addr(audit_buf, 1,
807 (dev != NULL ? dev->name : NULL), 646 (dev != NULL ? dev->name : NULL),
808 addr, mask); 647 addr, mask);
809 if (dev != NULL) 648 if (dev != NULL)
810 dev_put(dev); 649 dev_put(dev);
811 if (security_secid_to_secctx(entry->secid, 650 if (entry && security_secid_to_secctx(entry->secid,
812 &secctx, 651 &secctx,
813 &secctx_len) == 0) { 652 &secctx_len) == 0) {
814 audit_log_format(audit_buf, " sec_obj=%s", secctx); 653 audit_log_format(audit_buf, " sec_obj=%s", secctx);
815 security_release_secctx(secctx, secctx_len); 654 security_release_secctx(secctx, secctx_len);
816 } 655 }
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
836 */ 675 */
837static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) 676static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
838{ 677{
839 struct netlbl_unlhsh_addr4 *iter4; 678 struct netlbl_af4list *iter4;
840 struct netlbl_unlhsh_addr6 *iter6; 679#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
680 struct netlbl_af6list *iter6;
681#endif /* IPv6 */
841 682
842 spin_lock(&netlbl_unlhsh_lock); 683 spin_lock(&netlbl_unlhsh_lock);
843 list_for_each_entry_rcu(iter4, &iface->addr4_list, list) 684 netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
844 if (iter4->valid) 685 goto unlhsh_condremove_failure;
845 goto unlhsh_condremove_failure; 686#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
846 list_for_each_entry_rcu(iter6, &iface->addr6_list, list) 687 netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
847 if (iter6->valid) 688 goto unlhsh_condremove_failure;
848 goto unlhsh_condremove_failure; 689#endif /* IPv6 */
849 iface->valid = 0; 690 iface->valid = 0;
850 if (iface->ifindex > 0) 691 if (iface->ifindex > 0)
851 list_del_rcu(&iface->list); 692 list_del_rcu(&iface->list);
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1349 if (addr4) { 1190 if (addr4) {
1350 struct in_addr addr_struct; 1191 struct in_addr addr_struct;
1351 1192
1352 addr_struct.s_addr = addr4->addr; 1193 addr_struct.s_addr = addr4->list.addr;
1353 ret_val = nla_put(cb_arg->skb, 1194 ret_val = nla_put(cb_arg->skb,
1354 NLBL_UNLABEL_A_IPV4ADDR, 1195 NLBL_UNLABEL_A_IPV4ADDR,
1355 sizeof(struct in_addr), 1196 sizeof(struct in_addr),
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1357 if (ret_val != 0) 1198 if (ret_val != 0)
1358 goto list_cb_failure; 1199 goto list_cb_failure;
1359 1200
1360 addr_struct.s_addr = addr4->mask; 1201 addr_struct.s_addr = addr4->list.mask;
1361 ret_val = nla_put(cb_arg->skb, 1202 ret_val = nla_put(cb_arg->skb,
1362 NLBL_UNLABEL_A_IPV4MASK, 1203 NLBL_UNLABEL_A_IPV4MASK,
1363 sizeof(struct in_addr), 1204 sizeof(struct in_addr),
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
1370 ret_val = nla_put(cb_arg->skb, 1211 ret_val = nla_put(cb_arg->skb,
1371 NLBL_UNLABEL_A_IPV6ADDR, 1212 NLBL_UNLABEL_A_IPV6ADDR,
1372 sizeof(struct in6_addr), 1213 sizeof(struct in6_addr),
1373 &addr6->addr); 1214 &addr6->list.addr);
1374 if (ret_val != 0) 1215 if (ret_val != 0)
1375 goto list_cb_failure; 1216 goto list_cb_failure;
1376 1217
1377 ret_val = nla_put(cb_arg->skb, 1218 ret_val = nla_put(cb_arg->skb,
1378 NLBL_UNLABEL_A_IPV6MASK, 1219 NLBL_UNLABEL_A_IPV6MASK,
1379 sizeof(struct in6_addr), 1220 sizeof(struct in6_addr),
1380 &addr6->mask); 1221 &addr6->list.mask);
1381 if (ret_val != 0) 1222 if (ret_val != 0)
1382 goto list_cb_failure; 1223 goto list_cb_failure;
1383 1224
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1425 u32 iter_bkt; 1266 u32 iter_bkt;
1426 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; 1267 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1427 struct netlbl_unlhsh_iface *iface; 1268 struct netlbl_unlhsh_iface *iface;
1428 struct netlbl_unlhsh_addr4 *addr4; 1269 struct list_head *iter_list;
1429 struct netlbl_unlhsh_addr6 *addr6; 1270 struct netlbl_af4list *addr4;
1271#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1272 struct netlbl_af6list *addr6;
1273#endif
1430 1274
1431 cb_arg.nl_cb = cb; 1275 cb_arg.nl_cb = cb;
1432 cb_arg.skb = skb; 1276 cb_arg.skb = skb;
@@ -1436,44 +1280,43 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1436 for (iter_bkt = skip_bkt; 1280 for (iter_bkt = skip_bkt;
1437 iter_bkt < rcu_dereference(netlbl_unlhsh)->size; 1281 iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1438 iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) { 1282 iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
1439 list_for_each_entry_rcu(iface, 1283 iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
1440 &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt], 1284 list_for_each_entry_rcu(iface, iter_list, list) {
1441 list) {
1442 if (!iface->valid || 1285 if (!iface->valid ||
1443 iter_chain++ < skip_chain) 1286 iter_chain++ < skip_chain)
1444 continue; 1287 continue;
1445 list_for_each_entry_rcu(addr4, 1288 netlbl_af4list_foreach_rcu(addr4,
1446 &iface->addr4_list, 1289 &iface->addr4_list) {
1447 list) { 1290 if (iter_addr4++ < skip_addr4)
1448 if (!addr4->valid || iter_addr4++ < skip_addr4)
1449 continue; 1291 continue;
1450 if (netlbl_unlabel_staticlist_gen( 1292 if (netlbl_unlabel_staticlist_gen(
1451 NLBL_UNLABEL_C_STATICLIST, 1293 NLBL_UNLABEL_C_STATICLIST,
1452 iface, 1294 iface,
1453 addr4, 1295 netlbl_unlhsh_addr4_entry(addr4),
1454 NULL, 1296 NULL,
1455 &cb_arg) < 0) { 1297 &cb_arg) < 0) {
1456 iter_addr4--; 1298 iter_addr4--;
1457 iter_chain--; 1299 iter_chain--;
1458 goto unlabel_staticlist_return; 1300 goto unlabel_staticlist_return;
1459 } 1301 }
1460 } 1302 }
1461 list_for_each_entry_rcu(addr6, 1303#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1462 &iface->addr6_list, 1304 netlbl_af6list_foreach_rcu(addr6,
1463 list) { 1305 &iface->addr6_list) {
1464 if (!addr6->valid || iter_addr6++ < skip_addr6) 1306 if (iter_addr6++ < skip_addr6)
1465 continue; 1307 continue;
1466 if (netlbl_unlabel_staticlist_gen( 1308 if (netlbl_unlabel_staticlist_gen(
1467 NLBL_UNLABEL_C_STATICLIST, 1309 NLBL_UNLABEL_C_STATICLIST,
1468 iface, 1310 iface,
1469 NULL, 1311 NULL,
1470 addr6, 1312 netlbl_unlhsh_addr6_entry(addr6),
1471 &cb_arg) < 0) { 1313 &cb_arg) < 0) {
1472 iter_addr6--; 1314 iter_addr6--;
1473 iter_chain--; 1315 iter_chain--;
1474 goto unlabel_staticlist_return; 1316 goto unlabel_staticlist_return;
1475 } 1317 }
1476 } 1318 }
1319#endif /* IPv6 */
1477 } 1320 }
1478 } 1321 }
1479 1322
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1504 struct netlbl_unlhsh_iface *iface; 1347 struct netlbl_unlhsh_iface *iface;
1505 u32 skip_addr4 = cb->args[0]; 1348 u32 skip_addr4 = cb->args[0];
1506 u32 skip_addr6 = cb->args[1]; 1349 u32 skip_addr6 = cb->args[1];
1507 u32 iter_addr4 = 0, iter_addr6 = 0; 1350 u32 iter_addr4 = 0;
1508 struct netlbl_unlhsh_addr4 *addr4; 1351 struct netlbl_af4list *addr4;
1509 struct netlbl_unlhsh_addr6 *addr6; 1352#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1353 u32 iter_addr6 = 0;
1354 struct netlbl_af6list *addr6;
1355#endif
1510 1356
1511 cb_arg.nl_cb = cb; 1357 cb_arg.nl_cb = cb;
1512 cb_arg.skb = skb; 1358 cb_arg.skb = skb;
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1517 if (iface == NULL || !iface->valid) 1363 if (iface == NULL || !iface->valid)
1518 goto unlabel_staticlistdef_return; 1364 goto unlabel_staticlistdef_return;
1519 1365
1520 list_for_each_entry_rcu(addr4, &iface->addr4_list, list) { 1366 netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
1521 if (!addr4->valid || iter_addr4++ < skip_addr4) 1367 if (iter_addr4++ < skip_addr4)
1522 continue; 1368 continue;
1523 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1369 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1524 iface, 1370 iface,
1525 addr4, 1371 netlbl_unlhsh_addr4_entry(addr4),
1526 NULL, 1372 NULL,
1527 &cb_arg) < 0) { 1373 &cb_arg) < 0) {
1528 iter_addr4--; 1374 iter_addr4--;
1529 goto unlabel_staticlistdef_return; 1375 goto unlabel_staticlistdef_return;
1530 } 1376 }
1531 } 1377 }
1532 list_for_each_entry_rcu(addr6, &iface->addr6_list, list) { 1378#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1533 if (!addr6->valid || iter_addr6++ < skip_addr6) 1379 netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
1380 if (iter_addr6++ < skip_addr6)
1534 continue; 1381 continue;
1535 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1382 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1536 iface, 1383 iface,
1537 NULL, 1384 NULL,
1538 addr6, 1385 netlbl_unlhsh_addr6_entry(addr6),
1539 &cb_arg) < 0) { 1386 &cb_arg) < 0) {
1540 iter_addr6--; 1387 iter_addr6--;
1541 goto unlabel_staticlistdef_return; 1388 goto unlabel_staticlistdef_return;
1542 } 1389 }
1543 } 1390 }
1391#endif /* IPv6 */
1544 1392
1545unlabel_staticlistdef_return: 1393unlabel_staticlistdef_return:
1546 rcu_read_unlock(); 1394 rcu_read_unlock();
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
1718 switch (family) { 1566 switch (family) {
1719 case PF_INET: { 1567 case PF_INET: {
1720 struct iphdr *hdr4; 1568 struct iphdr *hdr4;
1721 struct netlbl_unlhsh_addr4 *addr4; 1569 struct netlbl_af4list *addr4;
1722 1570
1723 hdr4 = ip_hdr(skb); 1571 hdr4 = ip_hdr(skb);
1724 addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); 1572 addr4 = netlbl_af4list_search(hdr4->saddr,
1573 &iface->addr4_list);
1725 if (addr4 == NULL) 1574 if (addr4 == NULL)
1726 goto unlabel_getattr_nolabel; 1575 goto unlabel_getattr_nolabel;
1727 secattr->attr.secid = addr4->secid; 1576 secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
1728 break; 1577 break;
1729 } 1578 }
1730#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1579#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1731 case PF_INET6: { 1580 case PF_INET6: {
1732 struct ipv6hdr *hdr6; 1581 struct ipv6hdr *hdr6;
1733 struct netlbl_unlhsh_addr6 *addr6; 1582 struct netlbl_af6list *addr6;
1734 1583
1735 hdr6 = ipv6_hdr(skb); 1584 hdr6 = ipv6_hdr(skb);
1736 addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); 1585 addr6 = netlbl_af6list_search(&hdr6->saddr,
1586 &iface->addr6_list);
1737 if (addr6 == NULL) 1587 if (addr6 == NULL)
1738 goto unlabel_getattr_nolabel; 1588 goto unlabel_getattr_nolabel;
1739 secattr->attr.secid = addr6->secid; 1589 secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
1740 break; 1590 break;
1741 } 1591 }
1742#endif /* IPv6 */ 1592#endif /* IPv6 */