Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netlabel: Implement CALIPSO config functions for SMACK.

SMACK uses similar functions to control CIPSO, these are
the equivalent functions for CALIPSO and follow exactly
the same semantics.

int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
struct netlbl_audit *audit_info)
Adds a CALIPSO doi.

void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
Removes a CALIPSO doi.

int netlbl_cfg_calipso_map_add(u32 doi, const char *domain,
const struct in6_addr *addr,
const struct in6_addr *mask,
struct netlbl_audit *audit_info)
Creates a mapping between a domain and a CALIPSO doi. If
addr and mask are non-NULL this creates an address-selector
type mapping.

This also extends netlbl_cfg_map_del() to remove IPv6 address-selector
mappings.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>

authored by

Huw Davies and committed by
Paul Moore
3f09354a 4fee5242

+238
+26
include/net/netlabel.h
··· 445 445 const struct in_addr *addr, 446 446 const struct in_addr *mask, 447 447 struct netlbl_audit *audit_info); 448 + int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, 449 + struct netlbl_audit *audit_info); 450 + void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info); 451 + int netlbl_cfg_calipso_map_add(u32 doi, 452 + const char *domain, 453 + const struct in6_addr *addr, 454 + const struct in6_addr *mask, 455 + struct netlbl_audit *audit_info); 448 456 /* 449 457 * LSM security attribute operations 450 458 */ ··· 565 557 const char *domain, 566 558 const struct in_addr *addr, 567 559 const struct in_addr *mask, 560 + struct netlbl_audit *audit_info) 561 + { 562 + return -ENOSYS; 563 + } 564 + static inline int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, 565 + struct netlbl_audit *audit_info) 566 + { 567 + return -ENOSYS; 568 + } 569 + static inline void netlbl_cfg_calipso_del(u32 doi, 570 + struct netlbl_audit *audit_info) 571 + { 572 + return; 573 + } 574 + static inline int netlbl_cfg_calipso_map_add(u32 doi, 575 + const char *domain, 576 + const struct in6_addr *addr, 577 + const struct in6_addr *mask, 568 578 struct netlbl_audit *audit_info) 569 579 { 570 580 return -ENOSYS;
+66
net/netlabel/netlabel_domainhash.c
··· 725 725 return -ENOENT; 726 726 } 727 727 728 + #if IS_ENABLED(CONFIG_IPV6) 729 + /** 730 + * netlbl_domhsh_remove_af6 - Removes an address selector entry 731 + * @domain: the domain 732 + * @addr: IPv6 address 733 + * @mask: IPv6 address mask 734 + * @audit_info: NetLabel audit information 735 + * 736 + * Description: 737 + * Removes an individual address selector from a domain mapping and potentially 738 + * the entire mapping if it is empty. Returns zero on success, negative values 739 + * on failure. 740 + * 741 + */ 742 + int netlbl_domhsh_remove_af6(const char *domain, 743 + const struct in6_addr *addr, 744 + const struct in6_addr *mask, 745 + struct netlbl_audit *audit_info) 746 + { 747 + struct netlbl_dom_map *entry_map; 748 + struct netlbl_af6list *entry_addr; 749 + struct netlbl_af4list *iter4; 750 + struct netlbl_af6list *iter6; 751 + struct netlbl_domaddr6_map *entry; 752 + 753 + rcu_read_lock(); 754 + 755 + if (domain) 756 + entry_map = netlbl_domhsh_search(domain, AF_INET6); 757 + else 758 + entry_map = netlbl_domhsh_search_def(domain, AF_INET6); 759 + if (entry_map == NULL || 760 + entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) 761 + goto remove_af6_failure; 762 + 763 + spin_lock(&netlbl_domhsh_lock); 764 + entry_addr = netlbl_af6list_remove(addr, mask, 765 + &entry_map->def.addrsel->list6); 766 + spin_unlock(&netlbl_domhsh_lock); 767 + 768 + if (entry_addr == NULL) 769 + goto remove_af6_failure; 770 + netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4) 771 + goto remove_af6_single_addr; 772 + netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6) 773 + goto remove_af6_single_addr; 774 + /* the domain mapping is empty so remove it from the mapping table */ 775 + netlbl_domhsh_remove_entry(entry_map, audit_info); 776 + 777 + remove_af6_single_addr: 778 + rcu_read_unlock(); 779 + /* yick, we can't use call_rcu here because we don't have a rcu head 780 + * pointer but hopefully this should be a rare case so the pause 781 + * shouldn't be a problem */ 782 + synchronize_rcu(); 783 + entry = netlbl_domhsh_addr6_entry(entry_addr); 784 + calipso_doi_putdef(entry->def.calipso); 785 + kfree(entry); 786 + return 0; 787 + 788 + remove_af6_failure: 789 + rcu_read_unlock(); 790 + return -ENOENT; 791 + } 792 + #endif /* IPv6 */ 793 + 728 794 /** 729 795 * netlbl_domhsh_remove - Removes an entry from the domain hash table 730 796 * @domain: the domain to remove
+8
net/netlabel/netlabel_domainhash.h
··· 93 93 const struct in_addr *addr, 94 94 const struct in_addr *mask, 95 95 struct netlbl_audit *audit_info); 96 + int netlbl_domhsh_remove_af6(const char *domain, 97 + const struct in6_addr *addr, 98 + const struct in6_addr *mask, 99 + struct netlbl_audit *audit_info); 96 100 int netlbl_domhsh_remove(const char *domain, u16 family, 97 101 struct netlbl_audit *audit_info); 98 102 int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info); ··· 106 102 #if IS_ENABLED(CONFIG_IPV6) 107 103 struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, 108 104 const struct in6_addr *addr); 105 + int netlbl_domhsh_remove_af6(const char *domain, 106 + const struct in6_addr *addr, 107 + const struct in6_addr *mask, 108 + struct netlbl_audit *audit_info); 109 109 #endif /* IPv6 */ 110 110 111 111 int netlbl_domhsh_walk(u32 *skip_bkt,
+138
net/netlabel/netlabel_kapi.c
··· 80 80 case AF_INET: 81 81 return netlbl_domhsh_remove_af4(domain, addr, mask, 82 82 audit_info); 83 + #if IS_ENABLED(CONFIG_IPV6) 84 + case AF_INET6: 85 + return netlbl_domhsh_remove_af6(domain, addr, mask, 86 + audit_info); 87 + #endif /* IPv6 */ 83 88 default: 84 89 return -EPFNOSUPPORT; 85 90 } ··· 406 401 out_entry: 407 402 cipso_v4_doi_putdef(doi_def); 408 403 return ret_val; 404 + } 405 + 406 + /** 407 + * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition 408 + * @doi_def: CALIPSO DOI definition 409 + * @audit_info: NetLabel audit information 410 + * 411 + * Description: 412 + * Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on 413 + * success and negative values on failure. 414 + * 415 + */ 416 + int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, 417 + struct netlbl_audit *audit_info) 418 + { 419 + #if IS_ENABLED(CONFIG_IPV6) 420 + return calipso_doi_add(doi_def, audit_info); 421 + #else /* IPv6 */ 422 + return -ENOSYS; 423 + #endif /* IPv6 */ 424 + } 425 + 426 + /** 427 + * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition 428 + * @doi: CALIPSO DOI 429 + * @audit_info: NetLabel audit information 430 + * 431 + * Description: 432 + * Remove an existing CALIPSO DOI definition matching @doi. Returns zero on 433 + * success and negative values on failure. 434 + * 435 + */ 436 + void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info) 437 + { 438 + #if IS_ENABLED(CONFIG_IPV6) 439 + calipso_doi_remove(doi, audit_info); 440 + #endif /* IPv6 */ 441 + } 442 + 443 + /** 444 + * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping 445 + * @doi: the CALIPSO DOI 446 + * @domain: the domain mapping to add 447 + * @addr: IP address 448 + * @mask: IP address mask 449 + * @audit_info: NetLabel audit information 450 + * 451 + * Description: 452 + * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the 453 + * NetLabel subsystem. A @domain value of NULL adds a new default domain 454 + * mapping. Returns zero on success, negative values on failure. 455 + * 456 + */ 457 + int netlbl_cfg_calipso_map_add(u32 doi, 458 + const char *domain, 459 + const struct in6_addr *addr, 460 + const struct in6_addr *mask, 461 + struct netlbl_audit *audit_info) 462 + { 463 + #if IS_ENABLED(CONFIG_IPV6) 464 + int ret_val = -ENOMEM; 465 + struct calipso_doi *doi_def; 466 + struct netlbl_dom_map *entry; 467 + struct netlbl_domaddr_map *addrmap = NULL; 468 + struct netlbl_domaddr6_map *addrinfo = NULL; 469 + 470 + doi_def = calipso_doi_getdef(doi); 471 + if (doi_def == NULL) 472 + return -ENOENT; 473 + 474 + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 475 + if (entry == NULL) 476 + goto out_entry; 477 + entry->family = AF_INET6; 478 + if (domain != NULL) { 479 + entry->domain = kstrdup(domain, GFP_ATOMIC); 480 + if (entry->domain == NULL) 481 + goto out_domain; 482 + } 483 + 484 + if (addr == NULL && mask == NULL) { 485 + entry->def.calipso = doi_def; 486 + entry->def.type = NETLBL_NLTYPE_CALIPSO; 487 + } else if (addr != NULL && mask != NULL) { 488 + addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); 489 + if (addrmap == NULL) 490 + goto out_addrmap; 491 + INIT_LIST_HEAD(&addrmap->list4); 492 + INIT_LIST_HEAD(&addrmap->list6); 493 + 494 + addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); 495 + if (addrinfo == NULL) 496 + goto out_addrinfo; 497 + addrinfo->def.calipso = doi_def; 498 + addrinfo->def.type = NETLBL_NLTYPE_CALIPSO; 499 + addrinfo->list.addr = *addr; 500 + addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 501 + addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 502 + addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 503 + addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 504 + addrinfo->list.mask = *mask; 505 + addrinfo->list.valid = 1; 506 + ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6); 507 + if (ret_val != 0) 508 + goto cfg_calipso_map_add_failure; 509 + 510 + entry->def.addrsel = addrmap; 511 + entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 512 + } else { 513 + ret_val = -EINVAL; 514 + goto out_addrmap; 515 + } 516 + 517 + ret_val = netlbl_domhsh_add(entry, audit_info); 518 + if (ret_val != 0) 519 + goto cfg_calipso_map_add_failure; 520 + 521 + return 0; 522 + 523 + cfg_calipso_map_add_failure: 524 + kfree(addrinfo); 525 + out_addrinfo: 526 + kfree(addrmap); 527 + out_addrmap: 528 + kfree(entry->domain); 529 + out_domain: 530 + kfree(entry); 531 + out_entry: 532 + calipso_doi_putdef(doi_def); 533 + return ret_val; 534 + #else /* IPv6 */ 535 + return -ENOSYS; 536 + #endif /* IPv6 */ 409 537 } 410 538 411 539 /*