cipso_ipv4.c (9fec6060d9e48ed7db0dac0e16d0f0f0e615b7f6) cipso_ipv4.c (b1edeb102397546438ab4624489c6ccd7b410d97)
1/*
2 * CIPSO - Commercial IP Security Option
3 *
4 * This is an implementation of the CIPSO 2.2 protocol as specified in
5 * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
6 * FIPS-188, copies of both documents can be found in the Documentation
7 * directory. While CIPSO never became a full IETF RFC standard many vendors
8 * have chosen to adopt the protocol and over the years it has become a

--- 33 unchanged lines hidden (view full) ---

42#include <net/icmp.h>
43#include <net/tcp.h>
44#include <net/netlabel.h>
45#include <net/cipso_ipv4.h>
46#include <asm/atomic.h>
47#include <asm/bug.h>
48#include <asm/unaligned.h>
49
1/*
2 * CIPSO - Commercial IP Security Option
3 *
4 * This is an implementation of the CIPSO 2.2 protocol as specified in
5 * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
6 * FIPS-188, copies of both documents can be found in the Documentation
7 * directory. While CIPSO never became a full IETF RFC standard many vendors
8 * have chosen to adopt the protocol and over the years it has become a

--- 33 unchanged lines hidden (view full) ---

42#include <net/icmp.h>
43#include <net/tcp.h>
44#include <net/netlabel.h>
45#include <net/cipso_ipv4.h>
46#include <asm/atomic.h>
47#include <asm/bug.h>
48#include <asm/unaligned.h>
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,
62 * 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
64 * can do quick lookups. */
65static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
66static LIST_HEAD(cipso_v4_doi_list);
67
68/* Label mapping cache */

--- 120 unchanged lines hidden (view full) ---

189 bitmask = 0x80 >> (bit % 8);
190 if (state)
191 bitmap[byte_spot] |= bitmask;
192 else
193 bitmap[byte_spot] &= ~bitmask;
194}
195
196/**
51/* XXX - This currently assumes a minimal number of different DOIs in use,
52 * if in practice there are a lot of different DOIs this list should
53 * probably be turned into a hash table or something similar so we
54 * can do quick lookups. */
55static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
56static LIST_HEAD(cipso_v4_doi_list);
57
58/* Label mapping cache */

--- 120 unchanged lines hidden (view full) ---

179 bitmask = 0x80 >> (bit % 8);
180 if (state)
181 bitmap[byte_spot] |= bitmask;
182 else
183 bitmap[byte_spot] &= ~bitmask;
184}
185
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
217 * @entry: the entry to free
218 *
219 * Description:
220 * This function frees the memory associated with a cache entry including the
221 * LSM cache data if there are no longer any users, i.e. reference count == 0.
222 *
223 */

--- 228 unchanged lines hidden (view full) ---

452 * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
453 * Returns a pointer to the DOI definition on success and NULL on failure.
454 */
455static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
456{
457 struct cipso_v4_doi *iter;
458
459 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
187 * cipso_v4_cache_entry_free - Frees a cache entry
188 * @entry: the entry to free
189 *
190 * Description:
191 * This function frees the memory associated with a cache entry including the
192 * LSM cache data if there are no longer any users, i.e. reference count == 0.
193 *
194 */

--- 228 unchanged lines hidden (view full) ---

423 * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
424 * Returns a pointer to the DOI definition on success and NULL on failure.
425 */
426static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
427{
428 struct cipso_v4_doi *iter;
429
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;
462 return NULL;
463}
464
465/**
466 * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
467 * @doi_def: the DOI structure
468 *

--- 27 unchanged lines hidden (view full) ---

496 if (doi_def->type != CIPSO_V4_MAP_PASS)
497 return -EINVAL;
498 break;
499 default:
500 return -EINVAL;
501 }
502 }
503
432 return iter;
433 return NULL;
434}
435
436/**
437 * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
438 * @doi_def: the DOI structure
439 *

--- 27 unchanged lines hidden (view full) ---

467 if (doi_def->type != CIPSO_V4_MAP_PASS)
468 return -EINVAL;
469 break;
470 default:
471 return -EINVAL;
472 }
473 }
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
508 spin_lock(&cipso_v4_doi_list_lock);
509 if (cipso_v4_doi_search(doi_def->doi) != NULL)
510 goto doi_add_failure;
511 list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
512 spin_unlock(&cipso_v4_doi_list_lock);
513
514 return 0;
515
516doi_add_failure:
517 spin_unlock(&cipso_v4_doi_list_lock);
518 return -EEXIST;
519}
520
521/**
477
478 spin_lock(&cipso_v4_doi_list_lock);
479 if (cipso_v4_doi_search(doi_def->doi) != NULL)
480 goto doi_add_failure;
481 list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
482 spin_unlock(&cipso_v4_doi_list_lock);
483
484 return 0;
485
486doi_add_failure:
487 spin_unlock(&cipso_v4_doi_list_lock);
488 return -EEXIST;
489}
490
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
523 * @doi: the DOI value
524 * @audit_secid: the LSM secid to use in the audit message
534 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
535 * @doi: the DOI value
536 * @audit_secid: the LSM secid to use in the audit message
525 * @callback: the DOI cleanup/free callback
526 *
527 * Description:
537 *
538 * Description:
528 * Removes a DOI definition from the CIPSO engine, @callback is called to
529 * free any memory. The NetLabel routines will be called to release their own
530 * LSM domain mappings as well as our own domain list. Returns zero on
531 * success and negative values on failure.
539 * Removes a DOI definition from the CIPSO engine. The NetLabel routines will
540 * be called to release their own LSM domain mappings as well as our own
541 * domain list. Returns zero on success and negative values on failure.
532 *
533 */
542 *
543 */
534int cipso_v4_doi_remove(u32 doi,
535 struct netlbl_audit *audit_info,
536 void (*callback) (struct rcu_head * head))
544int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
537{
538 struct cipso_v4_doi *doi_def;
545{
546 struct cipso_v4_doi *doi_def;
539 struct cipso_v4_domhsh_entry *dom_iter;
540
541 spin_lock(&cipso_v4_doi_list_lock);
542 doi_def = cipso_v4_doi_search(doi);
547
548 spin_lock(&cipso_v4_doi_list_lock);
549 doi_def = cipso_v4_doi_search(doi);
543 if (doi_def != NULL) {
544 doi_def->valid = 0;
545 list_del_rcu(&doi_def->list);
550 if (doi_def == NULL) {
546 spin_unlock(&cipso_v4_doi_list_lock);
551 spin_unlock(&cipso_v4_doi_list_lock);
547 rcu_read_lock();
548 list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
549 if (dom_iter->valid)
550 netlbl_cfg_map_del(dom_iter->domain,
551 audit_info);
552 rcu_read_unlock();
553 cipso_v4_cache_invalidate();
554 call_rcu(&doi_def->rcu, callback);
555 return 0;
552 return -ENOENT;
556 }
553 }
554 if (!atomic_dec_and_test(&doi_def->refcount)) {
555 spin_unlock(&cipso_v4_doi_list_lock);
556 return -EBUSY;
557 }
558 list_del_rcu(&doi_def->list);
557 spin_unlock(&cipso_v4_doi_list_lock);
558
559 spin_unlock(&cipso_v4_doi_list_lock);
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}
561
562/**
565}
566
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
565 *
566 * Description:
567 * 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
569 * @doi: the DOI value
570 *
571 * Description:
572 * Searches for a valid DOI definition and if one is found it is returned to
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 *
571 */
572struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
573{
576 *
577 */
578struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
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;
575}
576
577/**
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);
615}
616
617/**
578 * cipso_v4_doi_walk - Iterate through the DOI definitions
579 * @skip_cnt: skip past this number of DOI definitions, updated
580 * @callback: callback for each DOI definition
581 * @cb_arg: argument for the callback function
582 *
583 * Description:
584 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
585 * For each entry call @callback, if @callback returns a negative value stop

--- 6 unchanged lines hidden (view full) ---

592 void *cb_arg)
593{
594 int ret_val = -ENOENT;
595 u32 doi_cnt = 0;
596 struct cipso_v4_doi *iter_doi;
597
598 rcu_read_lock();
599 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
618 * cipso_v4_doi_walk - Iterate through the DOI definitions
619 * @skip_cnt: skip past this number of DOI definitions, updated
620 * @callback: callback for each DOI definition
621 * @cb_arg: argument for the callback function
622 *
623 * Description:
624 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
625 * For each entry call @callback, if @callback returns a negative value stop

--- 6 unchanged lines hidden (view full) ---

632 void *cb_arg)
633{
634 int ret_val = -ENOENT;
635 u32 doi_cnt = 0;
636 struct cipso_v4_doi *iter_doi;
637
638 rcu_read_lock();
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)
602 continue;
603 ret_val = callback(iter_doi, cb_arg);
604 if (ret_val < 0) {
605 doi_cnt--;
606 goto doi_walk_return;
607 }
608 }
609
610doi_walk_return:
611 rcu_read_unlock();
612 *skip_cnt = doi_cnt;
613 return ret_val;
614}
615
641 if (doi_cnt++ < *skip_cnt)
642 continue;
643 ret_val = callback(iter_doi, cb_arg);
644 if (ret_val < 0) {
645 doi_cnt--;
646 goto doi_walk_return;
647 }
648 }
649
650doi_walk_return:
651 rcu_read_unlock();
652 *skip_cnt = doi_cnt;
653 return ret_val;
654}
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/*
696 * Label Mapping Functions
697 */
698
699/**
700 * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
701 * @doi_def: the DOI definition
702 * @level: the level to check

--- 1233 unchanged lines hidden ---
656/*
657 * Label Mapping Functions
658 */
659
660/**
661 * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
662 * @doi_def: the DOI definition
663 * @level: the level to check

--- 1233 unchanged lines hidden ---