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 --- |