aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/cipso_ipv4.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/cipso_ipv4.c')
-rw-r--r--net/ipv4/cipso_ipv4.c235
1 files changed, 98 insertions, 137 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2c0e4572cc90..bf87eddfec30 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -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
@@ -194,25 +184,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
194} 184}
195 185
196/** 186/**
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 187 * cipso_v4_cache_entry_free - Frees a cache entry
217 * @entry: the entry to free 188 * @entry: the entry to free
218 * 189 *
@@ -457,7 +428,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
457 struct cipso_v4_doi *iter; 428 struct cipso_v4_doi *iter;
458 429
459 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) 430 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
460 if (iter->doi == doi && iter->valid) 431 if (iter->doi == doi && atomic_read(&iter->refcount))
461 return iter; 432 return iter;
462 return NULL; 433 return NULL;
463} 434}
@@ -501,9 +472,8 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
501 } 472 }
502 } 473 }
503 474
504 doi_def->valid = 1; 475 atomic_set(&doi_def->refcount, 1);
505 INIT_RCU_HEAD(&doi_def->rcu); 476 INIT_RCU_HEAD(&doi_def->rcu);
506 INIT_LIST_HEAD(&doi_def->dom_list);
507 477
508 spin_lock(&cipso_v4_doi_list_lock); 478 spin_lock(&cipso_v4_doi_list_lock);
509 if (cipso_v4_doi_search(doi_def->doi) != NULL) 479 if (cipso_v4_doi_search(doi_def->doi) != NULL)
@@ -519,59 +489,129 @@ doi_add_failure:
519} 489}
520 490
521/** 491/**
492 * cipso_v4_doi_free - Frees a DOI definition
493 * @entry: the entry's RCU field
494 *
495 * Description:
496 * This function frees all of the memory associated with a DOI definition.
497 *
498 */
499void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
500{
501 if (doi_def == NULL)
502 return;
503
504 switch (doi_def->type) {
505 case CIPSO_V4_MAP_STD:
506 kfree(doi_def->map.std->lvl.cipso);
507 kfree(doi_def->map.std->lvl.local);
508 kfree(doi_def->map.std->cat.cipso);
509 kfree(doi_def->map.std->cat.local);
510 break;
511 }
512 kfree(doi_def);
513}
514
515/**
516 * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
517 * @entry: the entry's RCU field
518 *
519 * Description:
520 * This function is designed to be used as a callback to the call_rcu()
521 * function so that the memory allocated to the DOI definition can be released
522 * safely.
523 *
524 */
525static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
526{
527 struct cipso_v4_doi *doi_def;
528
529 doi_def = container_of(entry, struct cipso_v4_doi, rcu);
530 cipso_v4_doi_free(doi_def);
531}
532
533/**
522 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine 534 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
523 * @doi: the DOI value 535 * @doi: the DOI value
524 * @audit_secid: the LSM secid to use in the audit message 536 * @audit_secid: the LSM secid to use in the audit message
525 * @callback: the DOI cleanup/free callback
526 * 537 *
527 * Description: 538 * Description:
528 * Removes a DOI definition from the CIPSO engine, @callback is called to 539 * 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 540 * 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 541 * domain list. Returns zero on success and negative values on failure.
531 * success and negative values on failure.
532 * 542 *
533 */ 543 */
534int cipso_v4_doi_remove(u32 doi, 544int 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{ 545{
538 struct cipso_v4_doi *doi_def; 546 struct cipso_v4_doi *doi_def;
539 struct cipso_v4_domhsh_entry *dom_iter;
540 547
541 spin_lock(&cipso_v4_doi_list_lock); 548 spin_lock(&cipso_v4_doi_list_lock);
542 doi_def = cipso_v4_doi_search(doi); 549 doi_def = cipso_v4_doi_search(doi);
543 if (doi_def != NULL) { 550 if (doi_def == NULL) {
544 doi_def->valid = 0;
545 list_del_rcu(&doi_def->list);
546 spin_unlock(&cipso_v4_doi_list_lock); 551 spin_unlock(&cipso_v4_doi_list_lock);
547 rcu_read_lock(); 552 return -ENOENT;
548 list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) 553 }
549 if (dom_iter->valid) 554 if (!atomic_dec_and_test(&doi_def->refcount)) {
550 netlbl_cfg_map_del(dom_iter->domain, 555 spin_unlock(&cipso_v4_doi_list_lock);
551 audit_info); 556 return -EBUSY;
552 rcu_read_unlock();
553 cipso_v4_cache_invalidate();
554 call_rcu(&doi_def->rcu, callback);
555 return 0;
556 } 557 }
558 list_del_rcu(&doi_def->list);
557 spin_unlock(&cipso_v4_doi_list_lock); 559 spin_unlock(&cipso_v4_doi_list_lock);
558 560
559 return -ENOENT; 561 cipso_v4_cache_invalidate();
562 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
563
564 return 0;
560} 565}
561 566
562/** 567/**
563 * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition 568 * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
564 * @doi: the DOI value 569 * @doi: the DOI value
565 * 570 *
566 * Description: 571 * Description:
567 * Searches for a valid DOI definition and if one is found it is returned to 572 * 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 573 * the caller. Otherwise NULL is returned. The caller must ensure that
569 * rcu_read_lock() is held while accessing the returned definition. 574 * rcu_read_lock() is held while accessing the returned definition and the DOI
575 * definition reference count is decremented when the caller is done.
570 * 576 *
571 */ 577 */
572struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) 578struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
573{ 579{
574 return cipso_v4_doi_search(doi); 580 struct cipso_v4_doi *doi_def;
581
582 rcu_read_lock();
583 doi_def = cipso_v4_doi_search(doi);
584 if (doi_def == NULL)
585 goto doi_getdef_return;
586 if (!atomic_inc_not_zero(&doi_def->refcount))
587 doi_def = NULL;
588
589doi_getdef_return:
590 rcu_read_unlock();
591 return doi_def;
592}
593
594/**
595 * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
596 * @doi_def: the DOI definition
597 *
598 * Description:
599 * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
600 *
601 */
602void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
603{
604 if (doi_def == NULL)
605 return;
606
607 if (!atomic_dec_and_test(&doi_def->refcount))
608 return;
609 spin_lock(&cipso_v4_doi_list_lock);
610 list_del_rcu(&doi_def->list);
611 spin_unlock(&cipso_v4_doi_list_lock);
612
613 cipso_v4_cache_invalidate();
614 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
575} 615}
576 616
577/** 617/**
@@ -597,7 +637,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
597 637
598 rcu_read_lock(); 638 rcu_read_lock();
599 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) 639 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
600 if (iter_doi->valid) { 640 if (atomic_read(&iter_doi->refcount) > 0) {
601 if (doi_cnt++ < *skip_cnt) 641 if (doi_cnt++ < *skip_cnt)
602 continue; 642 continue;
603 ret_val = callback(iter_doi, cb_arg); 643 ret_val = callback(iter_doi, cb_arg);
@@ -613,85 +653,6 @@ doi_walk_return:
613 return ret_val; 653 return ret_val;
614} 654}
615 655
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/* 656/*
696 * Label Mapping Functions 657 * Label Mapping Functions
697 */ 658 */