Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f09354a authored by Huw Davies's avatar Huw Davies Committed by Paul Moore
Browse files

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: default avatarHuw Davies <huw@codeweavers.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent 4fee5242
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -445,6 +445,14 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
			       const struct in_addr *addr,
			       const struct in_addr *mask,
			       struct netlbl_audit *audit_info);
int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
			   struct netlbl_audit *audit_info);
void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info);
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);
/*
 * LSM security attribute operations
 */
@@ -561,6 +569,24 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
{
	return -ENOSYS;
}
static inline int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
					 struct netlbl_audit *audit_info)
{
	return -ENOSYS;
}
static inline void netlbl_cfg_calipso_del(u32 doi,
					  struct netlbl_audit *audit_info)
{
	return;
}
static inline 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)
{
	return -ENOSYS;
}
static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap,
				     u32 offset)
{
+66 −0
Original line number Diff line number Diff line
@@ -725,6 +725,72 @@ int netlbl_domhsh_remove_af4(const char *domain,
	return -ENOENT;
}

#if IS_ENABLED(CONFIG_IPV6)
/**
 * netlbl_domhsh_remove_af6 - Removes an address selector entry
 * @domain: the domain
 * @addr: IPv6 address
 * @mask: IPv6 address mask
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Removes an individual address selector from a domain mapping and potentially
 * the entire mapping if it is empty.  Returns zero on success, negative values
 * on failure.
 *
 */
int netlbl_domhsh_remove_af6(const char *domain,
			     const struct in6_addr *addr,
			     const struct in6_addr *mask,
			     struct netlbl_audit *audit_info)
{
	struct netlbl_dom_map *entry_map;
	struct netlbl_af6list *entry_addr;
	struct netlbl_af4list *iter4;
	struct netlbl_af6list *iter6;
	struct netlbl_domaddr6_map *entry;

	rcu_read_lock();

	if (domain)
		entry_map = netlbl_domhsh_search(domain, AF_INET6);
	else
		entry_map = netlbl_domhsh_search_def(domain, AF_INET6);
	if (entry_map == NULL ||
	    entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
		goto remove_af6_failure;

	spin_lock(&netlbl_domhsh_lock);
	entry_addr = netlbl_af6list_remove(addr, mask,
					   &entry_map->def.addrsel->list6);
	spin_unlock(&netlbl_domhsh_lock);

	if (entry_addr == NULL)
		goto remove_af6_failure;
	netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
		goto remove_af6_single_addr;
	netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
		goto remove_af6_single_addr;
	/* the domain mapping is empty so remove it from the mapping table */
	netlbl_domhsh_remove_entry(entry_map, audit_info);

remove_af6_single_addr:
	rcu_read_unlock();
	/* yick, we can't use call_rcu here because we don't have a rcu head
	 * pointer but hopefully this should be a rare case so the pause
	 * shouldn't be a problem */
	synchronize_rcu();
	entry = netlbl_domhsh_addr6_entry(entry_addr);
	calipso_doi_putdef(entry->def.calipso);
	kfree(entry);
	return 0;

remove_af6_failure:
	rcu_read_unlock();
	return -ENOENT;
}
#endif /* IPv6 */

/**
 * netlbl_domhsh_remove - Removes an entry from the domain hash table
 * @domain: the domain to remove
+8 −0
Original line number Diff line number Diff line
@@ -93,6 +93,10 @@ int netlbl_domhsh_remove_af4(const char *domain,
			     const struct in_addr *addr,
			     const struct in_addr *mask,
			     struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_af6(const char *domain,
			     const struct in6_addr *addr,
			     const struct in6_addr *mask,
			     struct netlbl_audit *audit_info);
int netlbl_domhsh_remove(const char *domain, u16 family,
			 struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info);
@@ -102,6 +106,10 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
#if IS_ENABLED(CONFIG_IPV6)
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
						   const struct in6_addr *addr);
int netlbl_domhsh_remove_af6(const char *domain,
			     const struct in6_addr *addr,
			     const struct in6_addr *mask,
			     struct netlbl_audit *audit_info);
#endif /* IPv6 */

int netlbl_domhsh_walk(u32 *skip_bkt,
+138 −0
Original line number Diff line number Diff line
@@ -80,6 +80,11 @@ int netlbl_cfg_map_del(const char *domain,
		case AF_INET:
			return netlbl_domhsh_remove_af4(domain, addr, mask,
							audit_info);
#if IS_ENABLED(CONFIG_IPV6)
		case AF_INET6:
			return netlbl_domhsh_remove_af6(domain, addr, mask,
							audit_info);
#endif /* IPv6 */
		default:
			return -EPFNOSUPPORT;
		}
@@ -403,6 +408,139 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
	return ret_val;
}

/**
 * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
 * @doi_def: CALIPSO DOI definition
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Add a new CALIPSO DOI definition as defined by @doi_def.  Returns zero on
 * success and negative values on failure.
 *
 */
int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
			   struct netlbl_audit *audit_info)
{
#if IS_ENABLED(CONFIG_IPV6)
	return calipso_doi_add(doi_def, audit_info);
#else /* IPv6 */
	return -ENOSYS;
#endif /* IPv6 */
}

/**
 * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
 * @doi: CALIPSO DOI
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Remove an existing CALIPSO DOI definition matching @doi.  Returns zero on
 * success and negative values on failure.
 *
 */
void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
{
#if IS_ENABLED(CONFIG_IPV6)
	calipso_doi_remove(doi, audit_info);
#endif /* IPv6 */
}

/**
 * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
 * @doi: the CALIPSO DOI
 * @domain: the domain mapping to add
 * @addr: IP address
 * @mask: IP address mask
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
 * NetLabel subsystem.  A @domain value of NULL adds a new default domain
 * mapping.  Returns zero on success, negative values on failure.
 *
 */
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)
{
#if IS_ENABLED(CONFIG_IPV6)
	int ret_val = -ENOMEM;
	struct calipso_doi *doi_def;
	struct netlbl_dom_map *entry;
	struct netlbl_domaddr_map *addrmap = NULL;
	struct netlbl_domaddr6_map *addrinfo = NULL;

	doi_def = calipso_doi_getdef(doi);
	if (doi_def == NULL)
		return -ENOENT;

	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
	if (entry == NULL)
		goto out_entry;
	entry->family = AF_INET6;
	if (domain != NULL) {
		entry->domain = kstrdup(domain, GFP_ATOMIC);
		if (entry->domain == NULL)
			goto out_domain;
	}

	if (addr == NULL && mask == NULL) {
		entry->def.calipso = doi_def;
		entry->def.type = NETLBL_NLTYPE_CALIPSO;
	} else if (addr != NULL && mask != NULL) {
		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
		if (addrmap == NULL)
			goto out_addrmap;
		INIT_LIST_HEAD(&addrmap->list4);
		INIT_LIST_HEAD(&addrmap->list6);

		addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
		if (addrinfo == NULL)
			goto out_addrinfo;
		addrinfo->def.calipso = doi_def;
		addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
		addrinfo->list.addr = *addr;
		addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
		addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
		addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
		addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
		addrinfo->list.mask = *mask;
		addrinfo->list.valid = 1;
		ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
		if (ret_val != 0)
			goto cfg_calipso_map_add_failure;

		entry->def.addrsel = addrmap;
		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
	} else {
		ret_val = -EINVAL;
		goto out_addrmap;
	}

	ret_val = netlbl_domhsh_add(entry, audit_info);
	if (ret_val != 0)
		goto cfg_calipso_map_add_failure;

	return 0;

cfg_calipso_map_add_failure:
	kfree(addrinfo);
out_addrinfo:
	kfree(addrmap);
out_addrmap:
	kfree(entry->domain);
out_domain:
	kfree(entry);
out_entry:
	calipso_doi_putdef(doi_def);
	return ret_val;
#else /* IPv6 */
	return -ENOSYS;
#endif /* IPv6 */
}

/*
 * Security Attribute Functions
 */