xref: /linux/net/netlabel/netlabel_kapi.c (revision 1b294a1f35616977caddaddf3e9d28e576a1adbc)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d15c345fSPaul Moore /*
3d15c345fSPaul Moore  * NetLabel Kernel API
4d15c345fSPaul Moore  *
5d15c345fSPaul Moore  * This file defines the kernel API for the NetLabel system.  The NetLabel
6d15c345fSPaul Moore  * system manages static and dynamic label mappings for network protocols such
7d15c345fSPaul Moore  * as CIPSO and RIPSO.
8d15c345fSPaul Moore  *
982c21bfaSPaul Moore  * Author: Paul Moore <paul@paul-moore.com>
10d15c345fSPaul Moore  */
11d15c345fSPaul Moore 
12d15c345fSPaul Moore /*
13014ab19aSPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14d15c345fSPaul Moore  */
15d15c345fSPaul Moore 
16d15c345fSPaul Moore #include <linux/init.h>
17d15c345fSPaul Moore #include <linux/types.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19eda61d32SPaul Moore #include <linux/audit.h>
206c2e8ac0SPaul Moore #include <linux/in.h>
216c2e8ac0SPaul Moore #include <linux/in6.h>
22d15c345fSPaul Moore #include <net/ip.h>
236c2e8ac0SPaul Moore #include <net/ipv6.h>
24d15c345fSPaul Moore #include <net/netlabel.h>
25d15c345fSPaul Moore #include <net/cipso_ipv4.h>
26ceba1832SHuw Davies #include <net/calipso.h>
27d15c345fSPaul Moore #include <asm/bug.h>
2860063497SArun Sharma #include <linux/atomic.h>
29d15c345fSPaul Moore 
30d15c345fSPaul Moore #include "netlabel_domainhash.h"
31d15c345fSPaul Moore #include "netlabel_unlabeled.h"
32eda61d32SPaul Moore #include "netlabel_cipso_v4.h"
33ceba1832SHuw Davies #include "netlabel_calipso.h"
34d15c345fSPaul Moore #include "netlabel_user.h"
3523bcdc1aSPaul Moore #include "netlabel_mgmt.h"
366c2e8ac0SPaul Moore #include "netlabel_addrlist.h"
37d15c345fSPaul Moore 
38d15c345fSPaul Moore /*
39eda61d32SPaul Moore  * Configuration Functions
40eda61d32SPaul Moore  */
41eda61d32SPaul Moore 
42eda61d32SPaul Moore /**
43eda61d32SPaul Moore  * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
44eda61d32SPaul Moore  * @domain: the domain mapping to remove
456c2e8ac0SPaul Moore  * @family: address family
466c2e8ac0SPaul Moore  * @addr: IP address
476c2e8ac0SPaul Moore  * @mask: IP address mask
48eda61d32SPaul Moore  * @audit_info: NetLabel audit information
49eda61d32SPaul Moore  *
50eda61d32SPaul Moore  * Description:
51eda61d32SPaul Moore  * Removes a NetLabel/LSM domain mapping.  A @domain value of NULL causes the
52eda61d32SPaul Moore  * default domain mapping to be removed.  Returns zero on success, negative
53eda61d32SPaul Moore  * values on failure.
54eda61d32SPaul Moore  *
55eda61d32SPaul Moore  */
netlbl_cfg_map_del(const char * domain,u16 family,const void * addr,const void * mask,struct netlbl_audit * audit_info)566c2e8ac0SPaul Moore int netlbl_cfg_map_del(const char *domain,
576c2e8ac0SPaul Moore 		       u16 family,
586c2e8ac0SPaul Moore 		       const void *addr,
596c2e8ac0SPaul Moore 		       const void *mask,
606c2e8ac0SPaul Moore 		       struct netlbl_audit *audit_info)
61eda61d32SPaul Moore {
626c2e8ac0SPaul Moore 	if (addr == NULL && mask == NULL) {
638f18e675SHuw Davies 		return netlbl_domhsh_remove(domain, family, audit_info);
646c2e8ac0SPaul Moore 	} else if (addr != NULL && mask != NULL) {
656c2e8ac0SPaul Moore 		switch (family) {
666c2e8ac0SPaul Moore 		case AF_INET:
676c2e8ac0SPaul Moore 			return netlbl_domhsh_remove_af4(domain, addr, mask,
686c2e8ac0SPaul Moore 							audit_info);
693f09354aSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
703f09354aSHuw Davies 		case AF_INET6:
713f09354aSHuw Davies 			return netlbl_domhsh_remove_af6(domain, addr, mask,
723f09354aSHuw Davies 							audit_info);
733f09354aSHuw Davies #endif /* IPv6 */
746c2e8ac0SPaul Moore 		default:
756c2e8ac0SPaul Moore 			return -EPFNOSUPPORT;
766c2e8ac0SPaul Moore 		}
776c2e8ac0SPaul Moore 	} else
786c2e8ac0SPaul Moore 		return -EINVAL;
79eda61d32SPaul Moore }
80eda61d32SPaul Moore 
81eda61d32SPaul Moore /**
826c2e8ac0SPaul Moore  * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
83eda61d32SPaul Moore  * @domain: the domain mapping to add
846c2e8ac0SPaul Moore  * @family: address family
856c2e8ac0SPaul Moore  * @addr: IP address
866c2e8ac0SPaul Moore  * @mask: IP address mask
87eda61d32SPaul Moore  * @audit_info: NetLabel audit information
88eda61d32SPaul Moore  *
89eda61d32SPaul Moore  * Description:
90eda61d32SPaul Moore  * Adds a new unlabeled NetLabel/LSM domain mapping.  A @domain value of NULL
91eda61d32SPaul Moore  * causes a new default domain mapping to be added.  Returns zero on success,
92eda61d32SPaul Moore  * negative values on failure.
93eda61d32SPaul Moore  *
94eda61d32SPaul Moore  */
netlbl_cfg_unlbl_map_add(const char * domain,u16 family,const void * addr,const void * mask,struct netlbl_audit * audit_info)956c2e8ac0SPaul Moore int netlbl_cfg_unlbl_map_add(const char *domain,
966c2e8ac0SPaul Moore 			     u16 family,
976c2e8ac0SPaul Moore 			     const void *addr,
986c2e8ac0SPaul Moore 			     const void *mask,
99eda61d32SPaul Moore 			     struct netlbl_audit *audit_info)
100eda61d32SPaul Moore {
101eda61d32SPaul Moore 	int ret_val = -ENOMEM;
102eda61d32SPaul Moore 	struct netlbl_dom_map *entry;
1036c2e8ac0SPaul Moore 	struct netlbl_domaddr_map *addrmap = NULL;
1046c2e8ac0SPaul Moore 	struct netlbl_domaddr4_map *map4 = NULL;
1056c2e8ac0SPaul Moore 	struct netlbl_domaddr6_map *map6 = NULL;
106eda61d32SPaul Moore 
107eda61d32SPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
108eda61d32SPaul Moore 	if (entry == NULL)
109948a7243SPaul Moore 		return -ENOMEM;
110eda61d32SPaul Moore 	if (domain != NULL) {
111eda61d32SPaul Moore 		entry->domain = kstrdup(domain, GFP_ATOMIC);
112eda61d32SPaul Moore 		if (entry->domain == NULL)
1136c2e8ac0SPaul Moore 			goto cfg_unlbl_map_add_failure;
114eda61d32SPaul Moore 	}
1158f18e675SHuw Davies 	entry->family = family;
1166c2e8ac0SPaul Moore 
1176c2e8ac0SPaul Moore 	if (addr == NULL && mask == NULL)
1186a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_UNLABELED;
1196c2e8ac0SPaul Moore 	else if (addr != NULL && mask != NULL) {
1206c2e8ac0SPaul Moore 		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
1216c2e8ac0SPaul Moore 		if (addrmap == NULL)
1226c2e8ac0SPaul Moore 			goto cfg_unlbl_map_add_failure;
1236c2e8ac0SPaul Moore 		INIT_LIST_HEAD(&addrmap->list4);
1246c2e8ac0SPaul Moore 		INIT_LIST_HEAD(&addrmap->list6);
1256c2e8ac0SPaul Moore 
1266c2e8ac0SPaul Moore 		switch (family) {
1271281bc25SPaul Moore 		case AF_INET: {
1281281bc25SPaul Moore 			const struct in_addr *addr4 = addr;
1291281bc25SPaul Moore 			const struct in_addr *mask4 = mask;
1306c2e8ac0SPaul Moore 			map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
1316c2e8ac0SPaul Moore 			if (map4 == NULL)
1326c2e8ac0SPaul Moore 				goto cfg_unlbl_map_add_failure;
1336a8b7f0cSPaul Moore 			map4->def.type = NETLBL_NLTYPE_UNLABELED;
1346c2e8ac0SPaul Moore 			map4->list.addr = addr4->s_addr & mask4->s_addr;
1356c2e8ac0SPaul Moore 			map4->list.mask = mask4->s_addr;
1366c2e8ac0SPaul Moore 			map4->list.valid = 1;
1376c2e8ac0SPaul Moore 			ret_val = netlbl_af4list_add(&map4->list,
1386c2e8ac0SPaul Moore 						     &addrmap->list4);
1396c2e8ac0SPaul Moore 			if (ret_val != 0)
1406c2e8ac0SPaul Moore 				goto cfg_unlbl_map_add_failure;
1416c2e8ac0SPaul Moore 			break;
1421281bc25SPaul Moore 			}
143dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1441281bc25SPaul Moore 		case AF_INET6: {
1451281bc25SPaul Moore 			const struct in6_addr *addr6 = addr;
1461281bc25SPaul Moore 			const struct in6_addr *mask6 = mask;
1476c2e8ac0SPaul Moore 			map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
148ca7daea6SJulia Lawall 			if (map6 == NULL)
1496c2e8ac0SPaul Moore 				goto cfg_unlbl_map_add_failure;
1506a8b7f0cSPaul Moore 			map6->def.type = NETLBL_NLTYPE_UNLABELED;
1514e3fd7a0SAlexey Dobriyan 			map6->list.addr = *addr6;
1526c2e8ac0SPaul Moore 			map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
1536c2e8ac0SPaul Moore 			map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
1546c2e8ac0SPaul Moore 			map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
1556c2e8ac0SPaul Moore 			map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
1564e3fd7a0SAlexey Dobriyan 			map6->list.mask = *mask6;
1576c2e8ac0SPaul Moore 			map6->list.valid = 1;
15842ca0203SDan Carpenter 			ret_val = netlbl_af6list_add(&map6->list,
15942ca0203SDan Carpenter 						     &addrmap->list6);
1606c2e8ac0SPaul Moore 			if (ret_val != 0)
1616c2e8ac0SPaul Moore 				goto cfg_unlbl_map_add_failure;
1626c2e8ac0SPaul Moore 			break;
1631281bc25SPaul Moore 			}
1641281bc25SPaul Moore #endif /* IPv6 */
1656c2e8ac0SPaul Moore 		default:
1666c2e8ac0SPaul Moore 			goto cfg_unlbl_map_add_failure;
1676c2e8ac0SPaul Moore 		}
1686c2e8ac0SPaul Moore 
1696a8b7f0cSPaul Moore 		entry->def.addrsel = addrmap;
1706a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
1716c2e8ac0SPaul Moore 	} else {
1726c2e8ac0SPaul Moore 		ret_val = -EINVAL;
1736c2e8ac0SPaul Moore 		goto cfg_unlbl_map_add_failure;
1746c2e8ac0SPaul Moore 	}
175eda61d32SPaul Moore 
176eda61d32SPaul Moore 	ret_val = netlbl_domhsh_add(entry, audit_info);
177eda61d32SPaul Moore 	if (ret_val != 0)
1786c2e8ac0SPaul Moore 		goto cfg_unlbl_map_add_failure;
179eda61d32SPaul Moore 
180eda61d32SPaul Moore 	return 0;
181eda61d32SPaul Moore 
1826c2e8ac0SPaul Moore cfg_unlbl_map_add_failure:
183eda61d32SPaul Moore 	kfree(entry->domain);
184eda61d32SPaul Moore 	kfree(entry);
1856c2e8ac0SPaul Moore 	kfree(addrmap);
1866c2e8ac0SPaul Moore 	kfree(map4);
1876c2e8ac0SPaul Moore 	kfree(map6);
188eda61d32SPaul Moore 	return ret_val;
189eda61d32SPaul Moore }
190eda61d32SPaul Moore 
1916c2e8ac0SPaul Moore 
192eda61d32SPaul Moore /**
1936c2e8ac0SPaul Moore  * netlbl_cfg_unlbl_static_add - Adds a new static label
1946c2e8ac0SPaul Moore  * @net: network namespace
1956c2e8ac0SPaul Moore  * @dev_name: interface name
1966c2e8ac0SPaul Moore  * @addr: IP address in network byte order (struct in[6]_addr)
1976c2e8ac0SPaul Moore  * @mask: address mask in network byte order (struct in[6]_addr)
1986c2e8ac0SPaul Moore  * @family: address family
1996c2e8ac0SPaul Moore  * @secid: LSM secid value for the entry
200eda61d32SPaul Moore  * @audit_info: NetLabel audit information
201eda61d32SPaul Moore  *
202eda61d32SPaul Moore  * Description:
2036c2e8ac0SPaul Moore  * Adds a new NetLabel static label to be used when protocol provided labels
2046c2e8ac0SPaul Moore  * are not present on incoming traffic.  If @dev_name is NULL then the default
2056c2e8ac0SPaul Moore  * interface will be used.  Returns zero on success, negative values on failure.
206eda61d32SPaul Moore  *
207eda61d32SPaul Moore  */
netlbl_cfg_unlbl_static_add(struct net * net,const char * dev_name,const void * addr,const void * mask,u16 family,u32 secid,struct netlbl_audit * audit_info)2086c2e8ac0SPaul Moore int netlbl_cfg_unlbl_static_add(struct net *net,
2096c2e8ac0SPaul Moore 				const char *dev_name,
2106c2e8ac0SPaul Moore 				const void *addr,
2116c2e8ac0SPaul Moore 				const void *mask,
2126c2e8ac0SPaul Moore 				u16 family,
2136c2e8ac0SPaul Moore 				u32 secid,
2146c2e8ac0SPaul Moore 				struct netlbl_audit *audit_info)
2156c2e8ac0SPaul Moore {
2166c2e8ac0SPaul Moore 	u32 addr_len;
2176c2e8ac0SPaul Moore 
2186c2e8ac0SPaul Moore 	switch (family) {
2196c2e8ac0SPaul Moore 	case AF_INET:
2206c2e8ac0SPaul Moore 		addr_len = sizeof(struct in_addr);
2216c2e8ac0SPaul Moore 		break;
222dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
2236c2e8ac0SPaul Moore 	case AF_INET6:
2246c2e8ac0SPaul Moore 		addr_len = sizeof(struct in6_addr);
2256c2e8ac0SPaul Moore 		break;
2261281bc25SPaul Moore #endif /* IPv6 */
2276c2e8ac0SPaul Moore 	default:
2286c2e8ac0SPaul Moore 		return -EPFNOSUPPORT;
2296c2e8ac0SPaul Moore 	}
2306c2e8ac0SPaul Moore 
2316c2e8ac0SPaul Moore 	return netlbl_unlhsh_add(net,
2326c2e8ac0SPaul Moore 				 dev_name, addr, mask, addr_len,
2336c2e8ac0SPaul Moore 				 secid, audit_info);
2346c2e8ac0SPaul Moore }
2356c2e8ac0SPaul Moore 
2366c2e8ac0SPaul Moore /**
2376c2e8ac0SPaul Moore  * netlbl_cfg_unlbl_static_del - Removes an existing static label
2386c2e8ac0SPaul Moore  * @net: network namespace
2396c2e8ac0SPaul Moore  * @dev_name: interface name
2406c2e8ac0SPaul Moore  * @addr: IP address in network byte order (struct in[6]_addr)
2416c2e8ac0SPaul Moore  * @mask: address mask in network byte order (struct in[6]_addr)
2426c2e8ac0SPaul Moore  * @family: address family
2436c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
2446c2e8ac0SPaul Moore  *
2456c2e8ac0SPaul Moore  * Description:
2466c2e8ac0SPaul Moore  * Removes an existing NetLabel static label used when protocol provided labels
2476c2e8ac0SPaul Moore  * are not present on incoming traffic.  If @dev_name is NULL then the default
2486c2e8ac0SPaul Moore  * interface will be used.  Returns zero on success, negative values on failure.
2496c2e8ac0SPaul Moore  *
2506c2e8ac0SPaul Moore  */
netlbl_cfg_unlbl_static_del(struct net * net,const char * dev_name,const void * addr,const void * mask,u16 family,struct netlbl_audit * audit_info)2516c2e8ac0SPaul Moore int netlbl_cfg_unlbl_static_del(struct net *net,
2526c2e8ac0SPaul Moore 				const char *dev_name,
2536c2e8ac0SPaul Moore 				const void *addr,
2546c2e8ac0SPaul Moore 				const void *mask,
2556c2e8ac0SPaul Moore 				u16 family,
2566c2e8ac0SPaul Moore 				struct netlbl_audit *audit_info)
2576c2e8ac0SPaul Moore {
2586c2e8ac0SPaul Moore 	u32 addr_len;
2596c2e8ac0SPaul Moore 
2606c2e8ac0SPaul Moore 	switch (family) {
2616c2e8ac0SPaul Moore 	case AF_INET:
2626c2e8ac0SPaul Moore 		addr_len = sizeof(struct in_addr);
2636c2e8ac0SPaul Moore 		break;
264dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
2656c2e8ac0SPaul Moore 	case AF_INET6:
2666c2e8ac0SPaul Moore 		addr_len = sizeof(struct in6_addr);
2676c2e8ac0SPaul Moore 		break;
2681281bc25SPaul Moore #endif /* IPv6 */
2696c2e8ac0SPaul Moore 	default:
2706c2e8ac0SPaul Moore 		return -EPFNOSUPPORT;
2716c2e8ac0SPaul Moore 	}
2726c2e8ac0SPaul Moore 
2736c2e8ac0SPaul Moore 	return netlbl_unlhsh_remove(net,
2746c2e8ac0SPaul Moore 				    dev_name, addr, mask, addr_len,
2756c2e8ac0SPaul Moore 				    audit_info);
2766c2e8ac0SPaul Moore }
2776c2e8ac0SPaul Moore 
2786c2e8ac0SPaul Moore /**
2796c2e8ac0SPaul Moore  * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
2806c2e8ac0SPaul Moore  * @doi_def: CIPSO DOI definition
2816c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
2826c2e8ac0SPaul Moore  *
2836c2e8ac0SPaul Moore  * Description:
2846c2e8ac0SPaul Moore  * Add a new CIPSO DOI definition as defined by @doi_def.  Returns zero on
2856c2e8ac0SPaul Moore  * success and negative values on failure.
2866c2e8ac0SPaul Moore  *
2876c2e8ac0SPaul Moore  */
netlbl_cfg_cipsov4_add(struct cipso_v4_doi * doi_def,struct netlbl_audit * audit_info)2886c2e8ac0SPaul Moore int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
2896c2e8ac0SPaul Moore 			   struct netlbl_audit *audit_info)
2906c2e8ac0SPaul Moore {
2916c2e8ac0SPaul Moore 	return cipso_v4_doi_add(doi_def, audit_info);
2926c2e8ac0SPaul Moore }
2936c2e8ac0SPaul Moore 
2946c2e8ac0SPaul Moore /**
2956c2e8ac0SPaul Moore  * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
2966c2e8ac0SPaul Moore  * @doi: CIPSO DOI
2976c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
2986c2e8ac0SPaul Moore  *
2996c2e8ac0SPaul Moore  * Description:
3006c2e8ac0SPaul Moore  * Remove an existing CIPSO DOI definition matching @doi.  Returns zero on
3016c2e8ac0SPaul Moore  * success and negative values on failure.
3026c2e8ac0SPaul Moore  *
3036c2e8ac0SPaul Moore  */
netlbl_cfg_cipsov4_del(u32 doi,struct netlbl_audit * audit_info)3046c2e8ac0SPaul Moore void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
3056c2e8ac0SPaul Moore {
3066c2e8ac0SPaul Moore 	cipso_v4_doi_remove(doi, audit_info);
3076c2e8ac0SPaul Moore }
3086c2e8ac0SPaul Moore 
3096c2e8ac0SPaul Moore /**
3106c2e8ac0SPaul Moore  * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
3116c2e8ac0SPaul Moore  * @doi: the CIPSO DOI
3126c2e8ac0SPaul Moore  * @domain: the domain mapping to add
3136c2e8ac0SPaul Moore  * @addr: IP address
3146c2e8ac0SPaul Moore  * @mask: IP address mask
3156c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
3166c2e8ac0SPaul Moore  *
3176c2e8ac0SPaul Moore  * Description:
3186c2e8ac0SPaul Moore  * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
3196c2e8ac0SPaul Moore  * subsystem.  A @domain value of NULL adds a new default domain mapping.
3206c2e8ac0SPaul Moore  * Returns zero on success, negative values on failure.
3216c2e8ac0SPaul Moore  *
3226c2e8ac0SPaul Moore  */
netlbl_cfg_cipsov4_map_add(u32 doi,const char * domain,const struct in_addr * addr,const struct in_addr * mask,struct netlbl_audit * audit_info)3236c2e8ac0SPaul Moore int netlbl_cfg_cipsov4_map_add(u32 doi,
324eda61d32SPaul Moore 			       const char *domain,
3256c2e8ac0SPaul Moore 			       const struct in_addr *addr,
3266c2e8ac0SPaul Moore 			       const struct in_addr *mask,
327eda61d32SPaul Moore 			       struct netlbl_audit *audit_info)
328eda61d32SPaul Moore {
329eda61d32SPaul Moore 	int ret_val = -ENOMEM;
3306c2e8ac0SPaul Moore 	struct cipso_v4_doi *doi_def;
331eda61d32SPaul Moore 	struct netlbl_dom_map *entry;
3326c2e8ac0SPaul Moore 	struct netlbl_domaddr_map *addrmap = NULL;
3336c2e8ac0SPaul Moore 	struct netlbl_domaddr4_map *addrinfo = NULL;
334eda61d32SPaul Moore 
3356c2e8ac0SPaul Moore 	doi_def = cipso_v4_doi_getdef(doi);
3366c2e8ac0SPaul Moore 	if (doi_def == NULL)
3376c2e8ac0SPaul Moore 		return -ENOENT;
338b1edeb10SPaul Moore 
339eda61d32SPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
340eda61d32SPaul Moore 	if (entry == NULL)
34194a80d63SJulia Lawall 		goto out_entry;
3428f18e675SHuw Davies 	entry->family = AF_INET;
343eda61d32SPaul Moore 	if (domain != NULL) {
344eda61d32SPaul Moore 		entry->domain = kstrdup(domain, GFP_ATOMIC);
345eda61d32SPaul Moore 		if (entry->domain == NULL)
34694a80d63SJulia Lawall 			goto out_domain;
347eda61d32SPaul Moore 	}
348eda61d32SPaul Moore 
3496c2e8ac0SPaul Moore 	if (addr == NULL && mask == NULL) {
3506a8b7f0cSPaul Moore 		entry->def.cipso = doi_def;
3516a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_CIPSOV4;
3526c2e8ac0SPaul Moore 	} else if (addr != NULL && mask != NULL) {
3536c2e8ac0SPaul Moore 		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
3546c2e8ac0SPaul Moore 		if (addrmap == NULL)
35594a80d63SJulia Lawall 			goto out_addrmap;
3566c2e8ac0SPaul Moore 		INIT_LIST_HEAD(&addrmap->list4);
3576c2e8ac0SPaul Moore 		INIT_LIST_HEAD(&addrmap->list6);
3586c2e8ac0SPaul Moore 
3596c2e8ac0SPaul Moore 		addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
3606c2e8ac0SPaul Moore 		if (addrinfo == NULL)
36194a80d63SJulia Lawall 			goto out_addrinfo;
3626a8b7f0cSPaul Moore 		addrinfo->def.cipso = doi_def;
3636a8b7f0cSPaul Moore 		addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4;
3646c2e8ac0SPaul Moore 		addrinfo->list.addr = addr->s_addr & mask->s_addr;
3656c2e8ac0SPaul Moore 		addrinfo->list.mask = mask->s_addr;
3666c2e8ac0SPaul Moore 		addrinfo->list.valid = 1;
3676c2e8ac0SPaul Moore 		ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
3686c2e8ac0SPaul Moore 		if (ret_val != 0)
3696c2e8ac0SPaul Moore 			goto cfg_cipsov4_map_add_failure;
3706c2e8ac0SPaul Moore 
3716a8b7f0cSPaul Moore 		entry->def.addrsel = addrmap;
3726a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
3736c2e8ac0SPaul Moore 	} else {
3746c2e8ac0SPaul Moore 		ret_val = -EINVAL;
37594a80d63SJulia Lawall 		goto out_addrmap;
376b1edeb10SPaul Moore 	}
3776c2e8ac0SPaul Moore 
378eda61d32SPaul Moore 	ret_val = netlbl_domhsh_add(entry, audit_info);
379eda61d32SPaul Moore 	if (ret_val != 0)
3806c2e8ac0SPaul Moore 		goto cfg_cipsov4_map_add_failure;
381eda61d32SPaul Moore 
3826c2e8ac0SPaul Moore 	return 0;
383b1edeb10SPaul Moore 
3846c2e8ac0SPaul Moore cfg_cipsov4_map_add_failure:
3856c2e8ac0SPaul Moore 	kfree(addrinfo);
38694a80d63SJulia Lawall out_addrinfo:
38794a80d63SJulia Lawall 	kfree(addrmap);
38894a80d63SJulia Lawall out_addrmap:
38994a80d63SJulia Lawall 	kfree(entry->domain);
39094a80d63SJulia Lawall out_domain:
39194a80d63SJulia Lawall 	kfree(entry);
39294a80d63SJulia Lawall out_entry:
39394a80d63SJulia Lawall 	cipso_v4_doi_putdef(doi_def);
3946c2e8ac0SPaul Moore 	return ret_val;
395eda61d32SPaul Moore }
396eda61d32SPaul Moore 
3973f09354aSHuw Davies /**
3983f09354aSHuw Davies  * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
3993f09354aSHuw Davies  * @doi_def: CALIPSO DOI definition
4003f09354aSHuw Davies  * @audit_info: NetLabel audit information
4013f09354aSHuw Davies  *
4023f09354aSHuw Davies  * Description:
4033f09354aSHuw Davies  * Add a new CALIPSO DOI definition as defined by @doi_def.  Returns zero on
4043f09354aSHuw Davies  * success and negative values on failure.
4053f09354aSHuw Davies  *
4063f09354aSHuw Davies  */
netlbl_cfg_calipso_add(struct calipso_doi * doi_def,struct netlbl_audit * audit_info)4073f09354aSHuw Davies int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
4083f09354aSHuw Davies 			   struct netlbl_audit *audit_info)
4093f09354aSHuw Davies {
4103f09354aSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
4113f09354aSHuw Davies 	return calipso_doi_add(doi_def, audit_info);
4123f09354aSHuw Davies #else /* IPv6 */
4133f09354aSHuw Davies 	return -ENOSYS;
4143f09354aSHuw Davies #endif /* IPv6 */
4153f09354aSHuw Davies }
4163f09354aSHuw Davies 
4173f09354aSHuw Davies /**
4183f09354aSHuw Davies  * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
4193f09354aSHuw Davies  * @doi: CALIPSO DOI
4203f09354aSHuw Davies  * @audit_info: NetLabel audit information
4213f09354aSHuw Davies  *
4223f09354aSHuw Davies  * Description:
4233f09354aSHuw Davies  * Remove an existing CALIPSO DOI definition matching @doi.  Returns zero on
4243f09354aSHuw Davies  * success and negative values on failure.
4253f09354aSHuw Davies  *
4263f09354aSHuw Davies  */
netlbl_cfg_calipso_del(u32 doi,struct netlbl_audit * audit_info)4273f09354aSHuw Davies void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
4283f09354aSHuw Davies {
4293f09354aSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
4303f09354aSHuw Davies 	calipso_doi_remove(doi, audit_info);
4313f09354aSHuw Davies #endif /* IPv6 */
4323f09354aSHuw Davies }
4333f09354aSHuw Davies 
4343f09354aSHuw Davies /**
4353f09354aSHuw Davies  * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
4363f09354aSHuw Davies  * @doi: the CALIPSO DOI
4373f09354aSHuw Davies  * @domain: the domain mapping to add
4383f09354aSHuw Davies  * @addr: IP address
4393f09354aSHuw Davies  * @mask: IP address mask
4403f09354aSHuw Davies  * @audit_info: NetLabel audit information
4413f09354aSHuw Davies  *
4423f09354aSHuw Davies  * Description:
4433f09354aSHuw Davies  * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
4443f09354aSHuw Davies  * NetLabel subsystem.  A @domain value of NULL adds a new default domain
4453f09354aSHuw Davies  * mapping.  Returns zero on success, negative values on failure.
4463f09354aSHuw Davies  *
4473f09354aSHuw Davies  */
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)4483f09354aSHuw Davies int netlbl_cfg_calipso_map_add(u32 doi,
4493f09354aSHuw Davies 			       const char *domain,
4503f09354aSHuw Davies 			       const struct in6_addr *addr,
4513f09354aSHuw Davies 			       const struct in6_addr *mask,
4523f09354aSHuw Davies 			       struct netlbl_audit *audit_info)
4533f09354aSHuw Davies {
4543f09354aSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
4553f09354aSHuw Davies 	int ret_val = -ENOMEM;
4563f09354aSHuw Davies 	struct calipso_doi *doi_def;
4573f09354aSHuw Davies 	struct netlbl_dom_map *entry;
4583f09354aSHuw Davies 	struct netlbl_domaddr_map *addrmap = NULL;
4593f09354aSHuw Davies 	struct netlbl_domaddr6_map *addrinfo = NULL;
4603f09354aSHuw Davies 
4613f09354aSHuw Davies 	doi_def = calipso_doi_getdef(doi);
4623f09354aSHuw Davies 	if (doi_def == NULL)
4633f09354aSHuw Davies 		return -ENOENT;
4643f09354aSHuw Davies 
4653f09354aSHuw Davies 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
4663f09354aSHuw Davies 	if (entry == NULL)
4673f09354aSHuw Davies 		goto out_entry;
4683f09354aSHuw Davies 	entry->family = AF_INET6;
4693f09354aSHuw Davies 	if (domain != NULL) {
4703f09354aSHuw Davies 		entry->domain = kstrdup(domain, GFP_ATOMIC);
4713f09354aSHuw Davies 		if (entry->domain == NULL)
4723f09354aSHuw Davies 			goto out_domain;
4733f09354aSHuw Davies 	}
4743f09354aSHuw Davies 
4753f09354aSHuw Davies 	if (addr == NULL && mask == NULL) {
4763f09354aSHuw Davies 		entry->def.calipso = doi_def;
4773f09354aSHuw Davies 		entry->def.type = NETLBL_NLTYPE_CALIPSO;
4783f09354aSHuw Davies 	} else if (addr != NULL && mask != NULL) {
4793f09354aSHuw Davies 		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
4803f09354aSHuw Davies 		if (addrmap == NULL)
4813f09354aSHuw Davies 			goto out_addrmap;
4823f09354aSHuw Davies 		INIT_LIST_HEAD(&addrmap->list4);
4833f09354aSHuw Davies 		INIT_LIST_HEAD(&addrmap->list6);
4843f09354aSHuw Davies 
4853f09354aSHuw Davies 		addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
4863f09354aSHuw Davies 		if (addrinfo == NULL)
4873f09354aSHuw Davies 			goto out_addrinfo;
4883f09354aSHuw Davies 		addrinfo->def.calipso = doi_def;
4893f09354aSHuw Davies 		addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
4903f09354aSHuw Davies 		addrinfo->list.addr = *addr;
4913f09354aSHuw Davies 		addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
4923f09354aSHuw Davies 		addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
4933f09354aSHuw Davies 		addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
4943f09354aSHuw Davies 		addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
4953f09354aSHuw Davies 		addrinfo->list.mask = *mask;
4963f09354aSHuw Davies 		addrinfo->list.valid = 1;
4973f09354aSHuw Davies 		ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
4983f09354aSHuw Davies 		if (ret_val != 0)
4993f09354aSHuw Davies 			goto cfg_calipso_map_add_failure;
5003f09354aSHuw Davies 
5013f09354aSHuw Davies 		entry->def.addrsel = addrmap;
5023f09354aSHuw Davies 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
5033f09354aSHuw Davies 	} else {
5043f09354aSHuw Davies 		ret_val = -EINVAL;
5053f09354aSHuw Davies 		goto out_addrmap;
5063f09354aSHuw Davies 	}
5073f09354aSHuw Davies 
5083f09354aSHuw Davies 	ret_val = netlbl_domhsh_add(entry, audit_info);
5093f09354aSHuw Davies 	if (ret_val != 0)
5103f09354aSHuw Davies 		goto cfg_calipso_map_add_failure;
5113f09354aSHuw Davies 
5123f09354aSHuw Davies 	return 0;
5133f09354aSHuw Davies 
5143f09354aSHuw Davies cfg_calipso_map_add_failure:
5153f09354aSHuw Davies 	kfree(addrinfo);
5163f09354aSHuw Davies out_addrinfo:
5173f09354aSHuw Davies 	kfree(addrmap);
5183f09354aSHuw Davies out_addrmap:
5193f09354aSHuw Davies 	kfree(entry->domain);
5203f09354aSHuw Davies out_domain:
5213f09354aSHuw Davies 	kfree(entry);
5223f09354aSHuw Davies out_entry:
5233f09354aSHuw Davies 	calipso_doi_putdef(doi_def);
5243f09354aSHuw Davies 	return ret_val;
5253f09354aSHuw Davies #else /* IPv6 */
5263f09354aSHuw Davies 	return -ENOSYS;
5273f09354aSHuw Davies #endif /* IPv6 */
5283f09354aSHuw Davies }
5293f09354aSHuw Davies 
530eda61d32SPaul Moore /*
53102752760SPaul Moore  * Security Attribute Functions
53202752760SPaul Moore  */
53302752760SPaul Moore 
5344b8feff2SPaul Moore #define _CM_F_NONE	0x00000000
5354b8feff2SPaul Moore #define _CM_F_ALLOC	0x00000001
536d960a618SPaul Moore #define _CM_F_WALK	0x00000002
5374b8feff2SPaul Moore 
5384b8feff2SPaul Moore /**
5394fbe63d1SPaul Moore  * _netlbl_catmap_getnode - Get a individual node from a catmap
5404b8feff2SPaul Moore  * @catmap: pointer to the category bitmap
5414b8feff2SPaul Moore  * @offset: the requested offset
5424b8feff2SPaul Moore  * @cm_flags: catmap flags, see _CM_F_*
5434b8feff2SPaul Moore  * @gfp_flags: memory allocation flags
5444b8feff2SPaul Moore  *
5454b8feff2SPaul Moore  * Description:
546d960a618SPaul Moore  * Iterate through the catmap looking for the node associated with @offset.
547d960a618SPaul Moore  * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node,
548d960a618SPaul Moore  * one will be created and inserted into the catmap.  If the _CM_F_WALK flag is
549d960a618SPaul Moore  * set in @cm_flags and there is no associated node, the next highest node will
550d960a618SPaul Moore  * be returned.  Returns a pointer to the node on success, NULL on failure.
5514b8feff2SPaul Moore  *
5524b8feff2SPaul Moore  */
_netlbl_catmap_getnode(struct netlbl_lsm_catmap ** catmap,u32 offset,unsigned int cm_flags,gfp_t gfp_flags)5534fbe63d1SPaul Moore static struct netlbl_lsm_catmap *_netlbl_catmap_getnode(
5544fbe63d1SPaul Moore 					     struct netlbl_lsm_catmap **catmap,
5554b8feff2SPaul Moore 					     u32 offset,
5564b8feff2SPaul Moore 					     unsigned int cm_flags,
5574b8feff2SPaul Moore 					     gfp_t gfp_flags)
5584b8feff2SPaul Moore {
5594fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *iter = *catmap;
5604fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *prev = NULL;
5614b8feff2SPaul Moore 
562d960a618SPaul Moore 	if (iter == NULL)
5634fbe63d1SPaul Moore 		goto catmap_getnode_alloc;
564d960a618SPaul Moore 	if (offset < iter->startbit)
5654fbe63d1SPaul Moore 		goto catmap_getnode_walk;
5664b8feff2SPaul Moore 	while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
5674b8feff2SPaul Moore 		prev = iter;
5684b8feff2SPaul Moore 		iter = iter->next;
5694b8feff2SPaul Moore 	}
5704b8feff2SPaul Moore 	if (iter == NULL || offset < iter->startbit)
5714fbe63d1SPaul Moore 		goto catmap_getnode_walk;
5724b8feff2SPaul Moore 
5734b8feff2SPaul Moore 	return iter;
5744b8feff2SPaul Moore 
5754fbe63d1SPaul Moore catmap_getnode_walk:
576d960a618SPaul Moore 	if (cm_flags & _CM_F_WALK)
577d960a618SPaul Moore 		return iter;
5784fbe63d1SPaul Moore catmap_getnode_alloc:
5794b8feff2SPaul Moore 	if (!(cm_flags & _CM_F_ALLOC))
5804b8feff2SPaul Moore 		return NULL;
5814b8feff2SPaul Moore 
5824fbe63d1SPaul Moore 	iter = netlbl_catmap_alloc(gfp_flags);
5834b8feff2SPaul Moore 	if (iter == NULL)
5844b8feff2SPaul Moore 		return NULL;
5854b8feff2SPaul Moore 	iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1);
5864b8feff2SPaul Moore 
5874b8feff2SPaul Moore 	if (prev == NULL) {
5884b8feff2SPaul Moore 		iter->next = *catmap;
5894b8feff2SPaul Moore 		*catmap = iter;
5904b8feff2SPaul Moore 	} else {
5914b8feff2SPaul Moore 		iter->next = prev->next;
5924b8feff2SPaul Moore 		prev->next = iter;
5934b8feff2SPaul Moore 	}
5944b8feff2SPaul Moore 
5954b8feff2SPaul Moore 	return iter;
5964b8feff2SPaul Moore }
5974b8feff2SPaul Moore 
59802752760SPaul Moore /**
5994fbe63d1SPaul Moore  * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit
60002752760SPaul Moore  * @catmap: the category bitmap
60102752760SPaul Moore  * @offset: the offset to start searching at, in bits
60202752760SPaul Moore  *
60302752760SPaul Moore  * Description:
60402752760SPaul Moore  * This function walks a LSM secattr category bitmap starting at @offset and
60502752760SPaul Moore  * returns the spot of the first set bit or -ENOENT if no bits are set.
60602752760SPaul Moore  *
60702752760SPaul Moore  */
netlbl_catmap_walk(struct netlbl_lsm_catmap * catmap,u32 offset)6084fbe63d1SPaul Moore int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
60902752760SPaul Moore {
61056fcd40fSColin Ian King 	struct netlbl_lsm_catmap *iter;
611d960a618SPaul Moore 	u32 idx;
612d960a618SPaul Moore 	u32 bit;
61323c5ae6dSGeorge Guo 	u64 bitmap;
61402752760SPaul Moore 
6154fbe63d1SPaul Moore 	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
61602752760SPaul Moore 	if (iter == NULL)
61702752760SPaul Moore 		return -ENOENT;
618d960a618SPaul Moore 	if (offset > iter->startbit) {
619d960a618SPaul Moore 		offset -= iter->startbit;
620d960a618SPaul Moore 		idx = offset / NETLBL_CATMAP_MAPSIZE;
621d960a618SPaul Moore 		bit = offset % NETLBL_CATMAP_MAPSIZE;
62202752760SPaul Moore 	} else {
623d960a618SPaul Moore 		idx = 0;
624d960a618SPaul Moore 		bit = 0;
62502752760SPaul Moore 	}
626d960a618SPaul Moore 	bitmap = iter->bitmap[idx] >> bit;
62702752760SPaul Moore 
62802752760SPaul Moore 	for (;;) {
62902752760SPaul Moore 		if (bitmap != 0) {
63002752760SPaul Moore 			while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
63102752760SPaul Moore 				bitmap >>= 1;
632d960a618SPaul Moore 				bit++;
63302752760SPaul Moore 			}
63402752760SPaul Moore 			return iter->startbit +
635d960a618SPaul Moore 			       (NETLBL_CATMAP_MAPSIZE * idx) + bit;
63602752760SPaul Moore 		}
637d960a618SPaul Moore 		if (++idx >= NETLBL_CATMAP_MAPCNT) {
63802752760SPaul Moore 			if (iter->next != NULL) {
63902752760SPaul Moore 				iter = iter->next;
640d960a618SPaul Moore 				idx = 0;
64102752760SPaul Moore 			} else
64202752760SPaul Moore 				return -ENOENT;
64302752760SPaul Moore 		}
644d960a618SPaul Moore 		bitmap = iter->bitmap[idx];
645d960a618SPaul Moore 		bit = 0;
64602752760SPaul Moore 	}
64702752760SPaul Moore 
64802752760SPaul Moore 	return -ENOENT;
64902752760SPaul Moore }
650ceba1832SHuw Davies EXPORT_SYMBOL(netlbl_catmap_walk);
65102752760SPaul Moore 
65202752760SPaul Moore /**
6534fbe63d1SPaul Moore  * netlbl_catmap_walkrng - Find the end of a string of set bits
65402752760SPaul Moore  * @catmap: the category bitmap
65502752760SPaul Moore  * @offset: the offset to start searching at, in bits
65602752760SPaul Moore  *
65702752760SPaul Moore  * Description:
65802752760SPaul Moore  * This function walks a LSM secattr category bitmap starting at @offset and
65902752760SPaul Moore  * returns the spot of the first cleared bit or -ENOENT if the offset is past
66002752760SPaul Moore  * the end of the bitmap.
66102752760SPaul Moore  *
66202752760SPaul Moore  */
netlbl_catmap_walkrng(struct netlbl_lsm_catmap * catmap,u32 offset)6634fbe63d1SPaul Moore int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset)
66402752760SPaul Moore {
6654fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *iter;
6664fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *prev = NULL;
667d960a618SPaul Moore 	u32 idx;
668d960a618SPaul Moore 	u32 bit;
66923c5ae6dSGeorge Guo 	u64 bitmask;
67023c5ae6dSGeorge Guo 	u64 bitmap;
67102752760SPaul Moore 
6724fbe63d1SPaul Moore 	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
67302752760SPaul Moore 	if (iter == NULL)
67402752760SPaul Moore 		return -ENOENT;
675d960a618SPaul Moore 	if (offset > iter->startbit) {
676d960a618SPaul Moore 		offset -= iter->startbit;
677d960a618SPaul Moore 		idx = offset / NETLBL_CATMAP_MAPSIZE;
678d960a618SPaul Moore 		bit = offset % NETLBL_CATMAP_MAPSIZE;
67902752760SPaul Moore 	} else {
680d960a618SPaul Moore 		idx = 0;
681d960a618SPaul Moore 		bit = 0;
68202752760SPaul Moore 	}
683d960a618SPaul Moore 	bitmask = NETLBL_CATMAP_BIT << bit;
68402752760SPaul Moore 
68502752760SPaul Moore 	for (;;) {
686d960a618SPaul Moore 		bitmap = iter->bitmap[idx];
68702752760SPaul Moore 		while (bitmask != 0 && (bitmap & bitmask) != 0) {
68802752760SPaul Moore 			bitmask <<= 1;
689d960a618SPaul Moore 			bit++;
69002752760SPaul Moore 		}
69102752760SPaul Moore 
692d960a618SPaul Moore 		if (prev && idx == 0 && bit == 0)
693d960a618SPaul Moore 			return prev->startbit + NETLBL_CATMAP_SIZE - 1;
694d960a618SPaul Moore 		else if (bitmask != 0)
69502752760SPaul Moore 			return iter->startbit +
696d960a618SPaul Moore 				(NETLBL_CATMAP_MAPSIZE * idx) + bit - 1;
697d960a618SPaul Moore 		else if (++idx >= NETLBL_CATMAP_MAPCNT) {
69802752760SPaul Moore 			if (iter->next == NULL)
69902752760SPaul Moore 				return iter->startbit + NETLBL_CATMAP_SIZE - 1;
700d960a618SPaul Moore 			prev = iter;
70102752760SPaul Moore 			iter = iter->next;
702d960a618SPaul Moore 			idx = 0;
70302752760SPaul Moore 		}
70402752760SPaul Moore 		bitmask = NETLBL_CATMAP_BIT;
705d960a618SPaul Moore 		bit = 0;
70602752760SPaul Moore 	}
70702752760SPaul Moore 
70802752760SPaul Moore 	return -ENOENT;
70902752760SPaul Moore }
71002752760SPaul Moore 
71102752760SPaul Moore /**
7124fbe63d1SPaul Moore  * netlbl_catmap_getlong - Export an unsigned long bitmap
7134b8feff2SPaul Moore  * @catmap: pointer to the category bitmap
7144b8feff2SPaul Moore  * @offset: pointer to the requested offset
7154b8feff2SPaul Moore  * @bitmap: the exported bitmap
7164b8feff2SPaul Moore  *
7174b8feff2SPaul Moore  * Description:
7184b8feff2SPaul Moore  * Export a bitmap with an offset greater than or equal to @offset and return
7194b8feff2SPaul Moore  * it in @bitmap.  The @offset must be aligned to an unsigned long and will be
7204b8feff2SPaul Moore  * updated on return if different from what was requested; if the catmap is
7214b8feff2SPaul Moore  * empty at the requested offset and beyond, the @offset is set to (u32)-1.
72284a57ae9SZheng Yongjun  * Returns zero on success, negative values on failure.
7234b8feff2SPaul Moore  *
7244b8feff2SPaul Moore  */
netlbl_catmap_getlong(struct netlbl_lsm_catmap * catmap,u32 * offset,unsigned long * bitmap)7254fbe63d1SPaul Moore int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
7264b8feff2SPaul Moore 			  u32 *offset,
7274b8feff2SPaul Moore 			  unsigned long *bitmap)
7284b8feff2SPaul Moore {
7294fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *iter;
7304b8feff2SPaul Moore 	u32 off = *offset;
7314b8feff2SPaul Moore 	u32 idx;
7324b8feff2SPaul Moore 
7334b8feff2SPaul Moore 	/* only allow aligned offsets */
7344b8feff2SPaul Moore 	if ((off & (BITS_PER_LONG - 1)) != 0)
7354b8feff2SPaul Moore 		return -EINVAL;
7364b8feff2SPaul Moore 
737eead1c2eSPaolo Abeni 	/* a null catmap is equivalent to an empty one */
738eead1c2eSPaolo Abeni 	if (!catmap) {
739eead1c2eSPaolo Abeni 		*offset = (u32)-1;
740eead1c2eSPaolo Abeni 		return 0;
741eead1c2eSPaolo Abeni 	}
742eead1c2eSPaolo Abeni 
7434b8feff2SPaul Moore 	if (off < catmap->startbit) {
7444b8feff2SPaul Moore 		off = catmap->startbit;
7454b8feff2SPaul Moore 		*offset = off;
7464b8feff2SPaul Moore 	}
74750b8629aSPaul Moore 	iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0);
7484b8feff2SPaul Moore 	if (iter == NULL) {
7494b8feff2SPaul Moore 		*offset = (u32)-1;
7504b8feff2SPaul Moore 		return 0;
7514b8feff2SPaul Moore 	}
7524b8feff2SPaul Moore 
7534b8feff2SPaul Moore 	if (off < iter->startbit) {
75450b8629aSPaul Moore 		*offset = iter->startbit;
75550b8629aSPaul Moore 		off = 0;
7564b8feff2SPaul Moore 	} else
7574b8feff2SPaul Moore 		off -= iter->startbit;
7584b8feff2SPaul Moore 	idx = off / NETLBL_CATMAP_MAPSIZE;
75950b8629aSPaul Moore 	*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
7604b8feff2SPaul Moore 
7614b8feff2SPaul Moore 	return 0;
7624b8feff2SPaul Moore }
7634b8feff2SPaul Moore 
7644b8feff2SPaul Moore /**
7654fbe63d1SPaul Moore  * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap
76641c3bd20SPaul Moore  * @catmap: pointer to the category bitmap
76702752760SPaul Moore  * @bit: the bit to set
76802752760SPaul Moore  * @flags: memory allocation flags
76902752760SPaul Moore  *
77002752760SPaul Moore  * Description:
77102752760SPaul Moore  * Set the bit specified by @bit in @catmap.  Returns zero on success,
77202752760SPaul Moore  * negative values on failure.
77302752760SPaul Moore  *
77402752760SPaul Moore  */
netlbl_catmap_setbit(struct netlbl_lsm_catmap ** catmap,u32 bit,gfp_t flags)7754fbe63d1SPaul Moore int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
77602752760SPaul Moore 			 u32 bit,
77702752760SPaul Moore 			 gfp_t flags)
77802752760SPaul Moore {
7794fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *iter;
7804b8feff2SPaul Moore 	u32 idx;
78102752760SPaul Moore 
7824fbe63d1SPaul Moore 	iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
78341c3bd20SPaul Moore 	if (iter == NULL)
78441c3bd20SPaul Moore 		return -ENOMEM;
78502752760SPaul Moore 
7864b8feff2SPaul Moore 	bit -= iter->startbit;
7874b8feff2SPaul Moore 	idx = bit / NETLBL_CATMAP_MAPSIZE;
7884b8feff2SPaul Moore 	iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
78902752760SPaul Moore 
79002752760SPaul Moore 	return 0;
79102752760SPaul Moore }
792ceba1832SHuw Davies EXPORT_SYMBOL(netlbl_catmap_setbit);
79302752760SPaul Moore 
79402752760SPaul Moore /**
7954fbe63d1SPaul Moore  * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
79641c3bd20SPaul Moore  * @catmap: pointer to the category bitmap
79702752760SPaul Moore  * @start: the starting bit
79802752760SPaul Moore  * @end: the last bit in the string
79902752760SPaul Moore  * @flags: memory allocation flags
80002752760SPaul Moore  *
80102752760SPaul Moore  * Description:
80202752760SPaul Moore  * Set a range of bits, starting at @start and ending with @end.  Returns zero
80302752760SPaul Moore  * on success, negative values on failure.
80402752760SPaul Moore  *
80502752760SPaul Moore  */
netlbl_catmap_setrng(struct netlbl_lsm_catmap ** catmap,u32 start,u32 end,gfp_t flags)8064fbe63d1SPaul Moore int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
80702752760SPaul Moore 			 u32 start,
80802752760SPaul Moore 			 u32 end,
80902752760SPaul Moore 			 gfp_t flags)
81002752760SPaul Moore {
8114b8feff2SPaul Moore 	int rc = 0;
8124b8feff2SPaul Moore 	u32 spot = start;
81302752760SPaul Moore 
8144b8feff2SPaul Moore 	while (rc == 0 && spot <= end) {
815341e0cb5SJanak Desai 		if (((spot & (BITS_PER_LONG - 1)) == 0) &&
8164b8feff2SPaul Moore 		    ((end - spot) > BITS_PER_LONG)) {
8174fbe63d1SPaul Moore 			rc = netlbl_catmap_setlong(catmap,
8184b8feff2SPaul Moore 						   spot,
8194b8feff2SPaul Moore 						   (unsigned long)-1,
8204b8feff2SPaul Moore 						   flags);
8214b8feff2SPaul Moore 			spot += BITS_PER_LONG;
8224b8feff2SPaul Moore 		} else
8234fbe63d1SPaul Moore 			rc = netlbl_catmap_setbit(catmap, spot++, flags);
82402752760SPaul Moore 	}
82502752760SPaul Moore 
8264b8feff2SPaul Moore 	return rc;
8274b8feff2SPaul Moore }
8284b8feff2SPaul Moore 
8294b8feff2SPaul Moore /**
8304fbe63d1SPaul Moore  * netlbl_catmap_setlong - Import an unsigned long bitmap
8314b8feff2SPaul Moore  * @catmap: pointer to the category bitmap
8324b8feff2SPaul Moore  * @offset: offset to the start of the imported bitmap
8334b8feff2SPaul Moore  * @bitmap: the bitmap to import
8344b8feff2SPaul Moore  * @flags: memory allocation flags
8354b8feff2SPaul Moore  *
8364b8feff2SPaul Moore  * Description:
8374b8feff2SPaul Moore  * Import the bitmap specified in @bitmap into @catmap, using the offset
8384b8feff2SPaul Moore  * in @offset.  The offset must be aligned to an unsigned long.  Returns zero
8394b8feff2SPaul Moore  * on success, negative values on failure.
8404b8feff2SPaul Moore  *
8414b8feff2SPaul Moore  */
netlbl_catmap_setlong(struct netlbl_lsm_catmap ** catmap,u32 offset,unsigned long bitmap,gfp_t flags)8424fbe63d1SPaul Moore int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
8434b8feff2SPaul Moore 			  u32 offset,
8444b8feff2SPaul Moore 			  unsigned long bitmap,
8454b8feff2SPaul Moore 			  gfp_t flags)
8464b8feff2SPaul Moore {
8474fbe63d1SPaul Moore 	struct netlbl_lsm_catmap *iter;
8484b8feff2SPaul Moore 	u32 idx;
8494b8feff2SPaul Moore 
8504b8feff2SPaul Moore 	/* only allow aligned offsets */
8514b8feff2SPaul Moore 	if ((offset & (BITS_PER_LONG - 1)) != 0)
8524b8feff2SPaul Moore 		return -EINVAL;
8534b8feff2SPaul Moore 
8544fbe63d1SPaul Moore 	iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags);
8554b8feff2SPaul Moore 	if (iter == NULL)
8564b8feff2SPaul Moore 		return -ENOMEM;
8574b8feff2SPaul Moore 
8584b8feff2SPaul Moore 	offset -= iter->startbit;
8594b8feff2SPaul Moore 	idx = offset / NETLBL_CATMAP_MAPSIZE;
86023c5ae6dSGeorge Guo 	iter->bitmap[idx] |= (u64)bitmap
861b403643dSDmitry Mastykin 			     << (offset % NETLBL_CATMAP_MAPSIZE);
8624b8feff2SPaul Moore 
8634b8feff2SPaul Moore 	return 0;
86402752760SPaul Moore }
86502752760SPaul Moore 
8663faa8f98SHuw Davies /* Bitmap functions
8673faa8f98SHuw Davies  */
8683faa8f98SHuw Davies 
8693faa8f98SHuw Davies /**
8703faa8f98SHuw Davies  * netlbl_bitmap_walk - Walk a bitmap looking for a bit
8713faa8f98SHuw Davies  * @bitmap: the bitmap
8723faa8f98SHuw Davies  * @bitmap_len: length in bits
8733faa8f98SHuw Davies  * @offset: starting offset
8743faa8f98SHuw Davies  * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
8753faa8f98SHuw Davies  *
8763faa8f98SHuw Davies  * Description:
8773faa8f98SHuw Davies  * Starting at @offset, walk the bitmap from left to right until either the
8783faa8f98SHuw Davies  * desired bit is found or we reach the end.  Return the bit offset, -1 if
8799ff74d77SZhengchao Shao  * not found.
8803faa8f98SHuw Davies  */
netlbl_bitmap_walk(const unsigned char * bitmap,u32 bitmap_len,u32 offset,u8 state)8813faa8f98SHuw Davies int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
8823faa8f98SHuw Davies 		       u32 offset, u8 state)
8833faa8f98SHuw Davies {
8843faa8f98SHuw Davies 	u32 bit_spot;
8853faa8f98SHuw Davies 	u32 byte_offset;
8863faa8f98SHuw Davies 	unsigned char bitmask;
8873faa8f98SHuw Davies 	unsigned char byte;
8883faa8f98SHuw Davies 
889f22881deSWang Yufen 	if (offset >= bitmap_len)
890f22881deSWang Yufen 		return -1;
8913faa8f98SHuw Davies 	byte_offset = offset / 8;
8923faa8f98SHuw Davies 	byte = bitmap[byte_offset];
8933faa8f98SHuw Davies 	bit_spot = offset;
8943faa8f98SHuw Davies 	bitmask = 0x80 >> (offset % 8);
8953faa8f98SHuw Davies 
8963faa8f98SHuw Davies 	while (bit_spot < bitmap_len) {
8973faa8f98SHuw Davies 		if ((state && (byte & bitmask) == bitmask) ||
8983faa8f98SHuw Davies 		    (state == 0 && (byte & bitmask) == 0))
8993faa8f98SHuw Davies 			return bit_spot;
9003faa8f98SHuw Davies 
9015578de48SPaul Moore 		if (++bit_spot >= bitmap_len)
9025578de48SPaul Moore 			return -1;
9033faa8f98SHuw Davies 		bitmask >>= 1;
9043faa8f98SHuw Davies 		if (bitmask == 0) {
9053faa8f98SHuw Davies 			byte = bitmap[++byte_offset];
9063faa8f98SHuw Davies 			bitmask = 0x80;
9073faa8f98SHuw Davies 		}
9083faa8f98SHuw Davies 	}
9093faa8f98SHuw Davies 
9103faa8f98SHuw Davies 	return -1;
9113faa8f98SHuw Davies }
9123faa8f98SHuw Davies EXPORT_SYMBOL(netlbl_bitmap_walk);
9133faa8f98SHuw Davies 
9143faa8f98SHuw Davies /**
9153faa8f98SHuw Davies  * netlbl_bitmap_setbit - Sets a single bit in a bitmap
9163faa8f98SHuw Davies  * @bitmap: the bitmap
9173faa8f98SHuw Davies  * @bit: the bit
9183faa8f98SHuw Davies  * @state: if non-zero, set the bit (1) else clear the bit (0)
9193faa8f98SHuw Davies  *
9203faa8f98SHuw Davies  * Description:
9213faa8f98SHuw Davies  * Set a single bit in the bitmask.  Returns zero on success, negative values
9223faa8f98SHuw Davies  * on error.
9233faa8f98SHuw Davies  */
netlbl_bitmap_setbit(unsigned char * bitmap,u32 bit,u8 state)9243faa8f98SHuw Davies void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state)
9253faa8f98SHuw Davies {
9263faa8f98SHuw Davies 	u32 byte_spot;
9273faa8f98SHuw Davies 	u8 bitmask;
9283faa8f98SHuw Davies 
9293faa8f98SHuw Davies 	/* gcc always rounds to zero when doing integer division */
9303faa8f98SHuw Davies 	byte_spot = bit / 8;
9313faa8f98SHuw Davies 	bitmask = 0x80 >> (bit % 8);
9323faa8f98SHuw Davies 	if (state)
9333faa8f98SHuw Davies 		bitmap[byte_spot] |= bitmask;
9343faa8f98SHuw Davies 	else
9353faa8f98SHuw Davies 		bitmap[byte_spot] &= ~bitmask;
9363faa8f98SHuw Davies }
9373faa8f98SHuw Davies EXPORT_SYMBOL(netlbl_bitmap_setbit);
9383faa8f98SHuw Davies 
93902752760SPaul Moore /*
940d15c345fSPaul Moore  * LSM Functions
941d15c345fSPaul Moore  */
942d15c345fSPaul Moore 
943d15c345fSPaul Moore /**
94423bcdc1aSPaul Moore  * netlbl_enabled - Determine if the NetLabel subsystem is enabled
94523bcdc1aSPaul Moore  *
94623bcdc1aSPaul Moore  * Description:
94723bcdc1aSPaul Moore  * The LSM can use this function to determine if it should use NetLabel
94823bcdc1aSPaul Moore  * security attributes in it's enforcement mechanism.  Currently, NetLabel is
94923bcdc1aSPaul Moore  * considered to be enabled when it's configuration contains a valid setup for
95023bcdc1aSPaul Moore  * at least one labeled protocol (i.e. NetLabel can understand incoming
95123bcdc1aSPaul Moore  * labeled packets of at least one type); otherwise NetLabel is considered to
95223bcdc1aSPaul Moore  * be disabled.
95323bcdc1aSPaul Moore  *
95423bcdc1aSPaul Moore  */
netlbl_enabled(void)95523bcdc1aSPaul Moore int netlbl_enabled(void)
95623bcdc1aSPaul Moore {
95723bcdc1aSPaul Moore 	/* At some point we probably want to expose this mechanism to the user
95823bcdc1aSPaul Moore 	 * as well so that admins can toggle NetLabel regardless of the
95923bcdc1aSPaul Moore 	 * configuration */
960c783f1ceSPaul Moore 	return (atomic_read(&netlabel_mgmt_protocount) > 0);
96123bcdc1aSPaul Moore }
96223bcdc1aSPaul Moore 
96323bcdc1aSPaul Moore /**
964389fb800SPaul Moore  * netlbl_sock_setattr - Label a socket using the correct protocol
965ba6ff9f2SPaul Moore  * @sk: the socket to label
966389fb800SPaul Moore  * @family: protocol family
967d15c345fSPaul Moore  * @secattr: the security attributes
968*8ec9897eSDavide Caratti  * @sk_locked: true if caller holds the socket lock
969d15c345fSPaul Moore  *
970d15c345fSPaul Moore  * Description:
971d15c345fSPaul Moore  * Attach the correct label to the given socket using the security attributes
972ba6ff9f2SPaul Moore  * specified in @secattr.  This function requires exclusive access to @sk,
973ba6ff9f2SPaul Moore  * which means it either needs to be in the process of being created or locked.
97463c41688SPaul Moore  * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
97563c41688SPaul Moore  * network address selectors (can't blindly label the socket), and negative
97663c41688SPaul Moore  * values on all other failures.
977d15c345fSPaul Moore  *
978d15c345fSPaul Moore  */
netlbl_sock_setattr(struct sock * sk,u16 family,const struct netlbl_lsm_secattr * secattr,bool sk_locked)979ba6ff9f2SPaul Moore int netlbl_sock_setattr(struct sock *sk,
980389fb800SPaul Moore 			u16 family,
981*8ec9897eSDavide Caratti 			const struct netlbl_lsm_secattr *secattr,
982*8ec9897eSDavide Caratti 			bool sk_locked)
983d15c345fSPaul Moore {
984389fb800SPaul Moore 	int ret_val;
985d15c345fSPaul Moore 	struct netlbl_dom_map *dom_entry;
986d15c345fSPaul Moore 
987d15c345fSPaul Moore 	rcu_read_lock();
9888f18e675SHuw Davies 	dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
989389fb800SPaul Moore 	if (dom_entry == NULL) {
990389fb800SPaul Moore 		ret_val = -ENOENT;
991d15c345fSPaul Moore 		goto socket_setattr_return;
992389fb800SPaul Moore 	}
993389fb800SPaul Moore 	switch (family) {
994389fb800SPaul Moore 	case AF_INET:
9956a8b7f0cSPaul Moore 		switch (dom_entry->def.type) {
99663c41688SPaul Moore 		case NETLBL_NLTYPE_ADDRSELECT:
99763c41688SPaul Moore 			ret_val = -EDESTADDRREQ;
99863c41688SPaul Moore 			break;
999d15c345fSPaul Moore 		case NETLBL_NLTYPE_CIPSOV4:
1000ba6ff9f2SPaul Moore 			ret_val = cipso_v4_sock_setattr(sk,
10016a8b7f0cSPaul Moore 							dom_entry->def.cipso,
1002*8ec9897eSDavide Caratti 							secattr, sk_locked);
1003d15c345fSPaul Moore 			break;
1004d15c345fSPaul Moore 		case NETLBL_NLTYPE_UNLABELED:
1005d15c345fSPaul Moore 			ret_val = 0;
1006d15c345fSPaul Moore 			break;
1007d15c345fSPaul Moore 		default:
1008d15c345fSPaul Moore 			ret_val = -ENOENT;
1009d15c345fSPaul Moore 		}
1010389fb800SPaul Moore 		break;
1011dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1012389fb800SPaul Moore 	case AF_INET6:
1013ceba1832SHuw Davies 		switch (dom_entry->def.type) {
1014ceba1832SHuw Davies 		case NETLBL_NLTYPE_ADDRSELECT:
1015ceba1832SHuw Davies 			ret_val = -EDESTADDRREQ;
1016ceba1832SHuw Davies 			break;
1017ceba1832SHuw Davies 		case NETLBL_NLTYPE_CALIPSO:
1018ceba1832SHuw Davies 			ret_val = calipso_sock_setattr(sk,
1019ceba1832SHuw Davies 						       dom_entry->def.calipso,
1020ceba1832SHuw Davies 						       secattr);
1021ceba1832SHuw Davies 			break;
1022ceba1832SHuw Davies 		case NETLBL_NLTYPE_UNLABELED:
1023389fb800SPaul Moore 			ret_val = 0;
1024389fb800SPaul Moore 			break;
1025ceba1832SHuw Davies 		default:
1026ceba1832SHuw Davies 			ret_val = -ENOENT;
1027ceba1832SHuw Davies 		}
1028ceba1832SHuw Davies 		break;
1029389fb800SPaul Moore #endif /* IPv6 */
1030389fb800SPaul Moore 	default:
1031389fb800SPaul Moore 		ret_val = -EPROTONOSUPPORT;
1032389fb800SPaul Moore 	}
1033d15c345fSPaul Moore 
1034d15c345fSPaul Moore socket_setattr_return:
1035d15c345fSPaul Moore 	rcu_read_unlock();
1036d15c345fSPaul Moore 	return ret_val;
1037d15c345fSPaul Moore }
1038d15c345fSPaul Moore 
1039d15c345fSPaul Moore /**
1040014ab19aSPaul Moore  * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
1041014ab19aSPaul Moore  * @sk: the socket
1042014ab19aSPaul Moore  *
1043014ab19aSPaul Moore  * Description:
1044014ab19aSPaul Moore  * Remove all the NetLabel labeling from @sk.  The caller is responsible for
1045014ab19aSPaul Moore  * ensuring that @sk is locked.
1046014ab19aSPaul Moore  *
1047014ab19aSPaul Moore  */
netlbl_sock_delattr(struct sock * sk)1048014ab19aSPaul Moore void netlbl_sock_delattr(struct sock *sk)
1049014ab19aSPaul Moore {
10500e0e3677SPaul Moore 	switch (sk->sk_family) {
10510e0e3677SPaul Moore 	case AF_INET:
1052014ab19aSPaul Moore 		cipso_v4_sock_delattr(sk);
10530e0e3677SPaul Moore 		break;
1054ceba1832SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
1055ceba1832SHuw Davies 	case AF_INET6:
1056ceba1832SHuw Davies 		calipso_sock_delattr(sk);
1057ceba1832SHuw Davies 		break;
1058ceba1832SHuw Davies #endif /* IPv6 */
10590e0e3677SPaul Moore 	}
1060014ab19aSPaul Moore }
1061014ab19aSPaul Moore 
1062014ab19aSPaul Moore /**
106314a72f53SPaul Moore  * netlbl_sock_getattr - Determine the security attributes of a sock
106414a72f53SPaul Moore  * @sk: the sock
106514a72f53SPaul Moore  * @secattr: the security attributes
106614a72f53SPaul Moore  *
106714a72f53SPaul Moore  * Description:
10688cc44579SPaul Moore  * Examines the given sock to see if any NetLabel style labeling has been
106914a72f53SPaul Moore  * applied to the sock, if so it parses the socket label and returns the
107014a72f53SPaul Moore  * security attributes in @secattr.  Returns zero on success, negative values
107114a72f53SPaul Moore  * on failure.
107214a72f53SPaul Moore  *
107314a72f53SPaul Moore  */
netlbl_sock_getattr(struct sock * sk,struct netlbl_lsm_secattr * secattr)1074389fb800SPaul Moore int netlbl_sock_getattr(struct sock *sk,
1075389fb800SPaul Moore 			struct netlbl_lsm_secattr *secattr)
107614a72f53SPaul Moore {
1077389fb800SPaul Moore 	int ret_val;
1078389fb800SPaul Moore 
1079389fb800SPaul Moore 	switch (sk->sk_family) {
1080389fb800SPaul Moore 	case AF_INET:
1081389fb800SPaul Moore 		ret_val = cipso_v4_sock_getattr(sk, secattr);
1082389fb800SPaul Moore 		break;
1083dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1084389fb800SPaul Moore 	case AF_INET6:
1085ceba1832SHuw Davies 		ret_val = calipso_sock_getattr(sk, secattr);
1086389fb800SPaul Moore 		break;
1087389fb800SPaul Moore #endif /* IPv6 */
1088389fb800SPaul Moore 	default:
1089389fb800SPaul Moore 		ret_val = -EPROTONOSUPPORT;
1090389fb800SPaul Moore 	}
1091389fb800SPaul Moore 
1092389fb800SPaul Moore 	return ret_val;
109314a72f53SPaul Moore }
109414a72f53SPaul Moore 
109514a72f53SPaul Moore /**
1096*8ec9897eSDavide Caratti  * netlbl_sk_lock_check - Check if the socket lock has been acquired.
1097*8ec9897eSDavide Caratti  * @sk: the socket to be checked
1098*8ec9897eSDavide Caratti  *
1099*8ec9897eSDavide Caratti  * Return: true if socket @sk is locked or if lock debugging is disabled at
1100*8ec9897eSDavide Caratti  * runtime or compile-time; false otherwise
1101*8ec9897eSDavide Caratti  *
1102*8ec9897eSDavide Caratti  */
1103*8ec9897eSDavide Caratti #ifdef CONFIG_LOCKDEP
netlbl_sk_lock_check(struct sock * sk)1104*8ec9897eSDavide Caratti bool netlbl_sk_lock_check(struct sock *sk)
1105*8ec9897eSDavide Caratti {
1106*8ec9897eSDavide Caratti 	if (debug_locks)
1107*8ec9897eSDavide Caratti 		return lockdep_sock_is_held(sk);
1108*8ec9897eSDavide Caratti 	return true;
1109*8ec9897eSDavide Caratti }
1110*8ec9897eSDavide Caratti #else
netlbl_sk_lock_check(struct sock * sk)1111*8ec9897eSDavide Caratti bool netlbl_sk_lock_check(struct sock *sk)
1112*8ec9897eSDavide Caratti {
1113*8ec9897eSDavide Caratti 	return true;
1114*8ec9897eSDavide Caratti }
1115*8ec9897eSDavide Caratti #endif
1116*8ec9897eSDavide Caratti 
1117*8ec9897eSDavide Caratti /**
1118014ab19aSPaul Moore  * netlbl_conn_setattr - Label a connected socket using the correct protocol
1119014ab19aSPaul Moore  * @sk: the socket to label
1120014ab19aSPaul Moore  * @addr: the destination address
1121014ab19aSPaul Moore  * @secattr: the security attributes
1122014ab19aSPaul Moore  *
1123014ab19aSPaul Moore  * Description:
1124014ab19aSPaul Moore  * Attach the correct label to the given connected socket using the security
1125014ab19aSPaul Moore  * attributes specified in @secattr.  The caller is responsible for ensuring
1126014ab19aSPaul Moore  * that @sk is locked.  Returns zero on success, negative values on failure.
1127014ab19aSPaul Moore  *
1128014ab19aSPaul Moore  */
netlbl_conn_setattr(struct sock * sk,struct sockaddr * addr,const struct netlbl_lsm_secattr * secattr)1129014ab19aSPaul Moore int netlbl_conn_setattr(struct sock *sk,
1130014ab19aSPaul Moore 			struct sockaddr *addr,
1131014ab19aSPaul Moore 			const struct netlbl_lsm_secattr *secattr)
1132014ab19aSPaul Moore {
1133014ab19aSPaul Moore 	int ret_val;
1134014ab19aSPaul Moore 	struct sockaddr_in *addr4;
1135ceba1832SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
1136ceba1832SHuw Davies 	struct sockaddr_in6 *addr6;
1137ceba1832SHuw Davies #endif
11386a8b7f0cSPaul Moore 	struct netlbl_dommap_def *entry;
1139014ab19aSPaul Moore 
1140014ab19aSPaul Moore 	rcu_read_lock();
1141014ab19aSPaul Moore 	switch (addr->sa_family) {
1142014ab19aSPaul Moore 	case AF_INET:
1143014ab19aSPaul Moore 		addr4 = (struct sockaddr_in *)addr;
11446a8b7f0cSPaul Moore 		entry = netlbl_domhsh_getentry_af4(secattr->domain,
1145014ab19aSPaul Moore 						   addr4->sin_addr.s_addr);
11466a8b7f0cSPaul Moore 		if (entry == NULL) {
1147014ab19aSPaul Moore 			ret_val = -ENOENT;
1148014ab19aSPaul Moore 			goto conn_setattr_return;
1149014ab19aSPaul Moore 		}
11506a8b7f0cSPaul Moore 		switch (entry->type) {
1151014ab19aSPaul Moore 		case NETLBL_NLTYPE_CIPSOV4:
1152014ab19aSPaul Moore 			ret_val = cipso_v4_sock_setattr(sk,
1153*8ec9897eSDavide Caratti 							entry->cipso, secattr,
1154*8ec9897eSDavide Caratti 							netlbl_sk_lock_check(sk));
1155014ab19aSPaul Moore 			break;
1156014ab19aSPaul Moore 		case NETLBL_NLTYPE_UNLABELED:
1157014ab19aSPaul Moore 			/* just delete the protocols we support for right now
1158014ab19aSPaul Moore 			 * but we could remove other protocols if needed */
1159ceba1832SHuw Davies 			netlbl_sock_delattr(sk);
1160014ab19aSPaul Moore 			ret_val = 0;
1161014ab19aSPaul Moore 			break;
1162014ab19aSPaul Moore 		default:
1163014ab19aSPaul Moore 			ret_val = -ENOENT;
1164014ab19aSPaul Moore 		}
1165014ab19aSPaul Moore 		break;
1166dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1167014ab19aSPaul Moore 	case AF_INET6:
1168ceba1832SHuw Davies 		addr6 = (struct sockaddr_in6 *)addr;
1169ceba1832SHuw Davies 		entry = netlbl_domhsh_getentry_af6(secattr->domain,
1170ceba1832SHuw Davies 						   &addr6->sin6_addr);
1171ceba1832SHuw Davies 		if (entry == NULL) {
1172ceba1832SHuw Davies 			ret_val = -ENOENT;
1173ceba1832SHuw Davies 			goto conn_setattr_return;
1174ceba1832SHuw Davies 		}
1175ceba1832SHuw Davies 		switch (entry->type) {
1176ceba1832SHuw Davies 		case NETLBL_NLTYPE_CALIPSO:
1177ceba1832SHuw Davies 			ret_val = calipso_sock_setattr(sk,
1178ceba1832SHuw Davies 						       entry->calipso, secattr);
1179ceba1832SHuw Davies 			break;
1180ceba1832SHuw Davies 		case NETLBL_NLTYPE_UNLABELED:
1181ceba1832SHuw Davies 			/* just delete the protocols we support for right now
1182ceba1832SHuw Davies 			 * but we could remove other protocols if needed */
1183ceba1832SHuw Davies 			netlbl_sock_delattr(sk);
1184014ab19aSPaul Moore 			ret_val = 0;
1185014ab19aSPaul Moore 			break;
1186ceba1832SHuw Davies 		default:
1187ceba1832SHuw Davies 			ret_val = -ENOENT;
1188ceba1832SHuw Davies 		}
1189ceba1832SHuw Davies 		break;
1190014ab19aSPaul Moore #endif /* IPv6 */
1191014ab19aSPaul Moore 	default:
1192389fb800SPaul Moore 		ret_val = -EPROTONOSUPPORT;
1193014ab19aSPaul Moore 	}
1194014ab19aSPaul Moore 
1195014ab19aSPaul Moore conn_setattr_return:
1196014ab19aSPaul Moore 	rcu_read_unlock();
1197014ab19aSPaul Moore 	return ret_val;
1198014ab19aSPaul Moore }
1199014ab19aSPaul Moore 
1200014ab19aSPaul Moore /**
1201389fb800SPaul Moore  * netlbl_req_setattr - Label a request socket using the correct protocol
1202389fb800SPaul Moore  * @req: the request socket to label
1203389fb800SPaul Moore  * @secattr: the security attributes
1204389fb800SPaul Moore  *
1205389fb800SPaul Moore  * Description:
1206389fb800SPaul Moore  * Attach the correct label to the given socket using the security attributes
1207389fb800SPaul Moore  * specified in @secattr.  Returns zero on success, negative values on failure.
1208389fb800SPaul Moore  *
1209389fb800SPaul Moore  */
netlbl_req_setattr(struct request_sock * req,const struct netlbl_lsm_secattr * secattr)1210389fb800SPaul Moore int netlbl_req_setattr(struct request_sock *req,
1211389fb800SPaul Moore 		       const struct netlbl_lsm_secattr *secattr)
1212389fb800SPaul Moore {
1213389fb800SPaul Moore 	int ret_val;
12146a8b7f0cSPaul Moore 	struct netlbl_dommap_def *entry;
1215e1adea92SHuw Davies 	struct inet_request_sock *ireq = inet_rsk(req);
1216389fb800SPaul Moore 
1217389fb800SPaul Moore 	rcu_read_lock();
1218389fb800SPaul Moore 	switch (req->rsk_ops->family) {
1219389fb800SPaul Moore 	case AF_INET:
12206a8b7f0cSPaul Moore 		entry = netlbl_domhsh_getentry_af4(secattr->domain,
1221e1adea92SHuw Davies 						   ireq->ir_rmt_addr);
12226a8b7f0cSPaul Moore 		if (entry == NULL) {
1223389fb800SPaul Moore 			ret_val = -ENOENT;
1224389fb800SPaul Moore 			goto req_setattr_return;
1225389fb800SPaul Moore 		}
12266a8b7f0cSPaul Moore 		switch (entry->type) {
1227389fb800SPaul Moore 		case NETLBL_NLTYPE_CIPSOV4:
12286a8b7f0cSPaul Moore 			ret_val = cipso_v4_req_setattr(req,
12296a8b7f0cSPaul Moore 						       entry->cipso, secattr);
1230389fb800SPaul Moore 			break;
1231389fb800SPaul Moore 		case NETLBL_NLTYPE_UNLABELED:
1232e1adea92SHuw Davies 			netlbl_req_delattr(req);
1233389fb800SPaul Moore 			ret_val = 0;
1234389fb800SPaul Moore 			break;
1235389fb800SPaul Moore 		default:
1236389fb800SPaul Moore 			ret_val = -ENOENT;
1237389fb800SPaul Moore 		}
1238389fb800SPaul Moore 		break;
1239dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1240389fb800SPaul Moore 	case AF_INET6:
1241e1adea92SHuw Davies 		entry = netlbl_domhsh_getentry_af6(secattr->domain,
1242e1adea92SHuw Davies 						   &ireq->ir_v6_rmt_addr);
1243e1adea92SHuw Davies 		if (entry == NULL) {
1244e1adea92SHuw Davies 			ret_val = -ENOENT;
1245e1adea92SHuw Davies 			goto req_setattr_return;
1246e1adea92SHuw Davies 		}
1247e1adea92SHuw Davies 		switch (entry->type) {
1248e1adea92SHuw Davies 		case NETLBL_NLTYPE_CALIPSO:
1249e1adea92SHuw Davies 			ret_val = calipso_req_setattr(req,
1250e1adea92SHuw Davies 						      entry->calipso, secattr);
1251e1adea92SHuw Davies 			break;
1252e1adea92SHuw Davies 		case NETLBL_NLTYPE_UNLABELED:
1253e1adea92SHuw Davies 			netlbl_req_delattr(req);
1254389fb800SPaul Moore 			ret_val = 0;
1255389fb800SPaul Moore 			break;
1256e1adea92SHuw Davies 		default:
1257e1adea92SHuw Davies 			ret_val = -ENOENT;
1258e1adea92SHuw Davies 		}
1259e1adea92SHuw Davies 		break;
1260389fb800SPaul Moore #endif /* IPv6 */
1261389fb800SPaul Moore 	default:
1262389fb800SPaul Moore 		ret_val = -EPROTONOSUPPORT;
1263389fb800SPaul Moore 	}
1264389fb800SPaul Moore 
1265389fb800SPaul Moore req_setattr_return:
1266389fb800SPaul Moore 	rcu_read_unlock();
1267389fb800SPaul Moore 	return ret_val;
1268389fb800SPaul Moore }
1269389fb800SPaul Moore 
1270389fb800SPaul Moore /**
127107feee8fSPaul Moore * netlbl_req_delattr - Delete all the NetLabel labels on a socket
127207feee8fSPaul Moore * @req: the socket
127307feee8fSPaul Moore *
127407feee8fSPaul Moore * Description:
127507feee8fSPaul Moore * Remove all the NetLabel labeling from @req.
127607feee8fSPaul Moore *
127707feee8fSPaul Moore */
netlbl_req_delattr(struct request_sock * req)127807feee8fSPaul Moore void netlbl_req_delattr(struct request_sock *req)
127907feee8fSPaul Moore {
12800e0e3677SPaul Moore 	switch (req->rsk_ops->family) {
12810e0e3677SPaul Moore 	case AF_INET:
128207feee8fSPaul Moore 		cipso_v4_req_delattr(req);
12830e0e3677SPaul Moore 		break;
1284e1adea92SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
1285e1adea92SHuw Davies 	case AF_INET6:
1286e1adea92SHuw Davies 		calipso_req_delattr(req);
1287e1adea92SHuw Davies 		break;
1288e1adea92SHuw Davies #endif /* IPv6 */
12890e0e3677SPaul Moore 	}
129007feee8fSPaul Moore }
129107feee8fSPaul Moore 
129207feee8fSPaul Moore /**
1293948bf85cSPaul Moore  * netlbl_skbuff_setattr - Label a packet using the correct protocol
1294948bf85cSPaul Moore  * @skb: the packet
1295948bf85cSPaul Moore  * @family: protocol family
1296948bf85cSPaul Moore  * @secattr: the security attributes
1297948bf85cSPaul Moore  *
1298948bf85cSPaul Moore  * Description:
1299948bf85cSPaul Moore  * Attach the correct label to the given packet using the security attributes
1300948bf85cSPaul Moore  * specified in @secattr.  Returns zero on success, negative values on failure.
1301948bf85cSPaul Moore  *
1302948bf85cSPaul Moore  */
netlbl_skbuff_setattr(struct sk_buff * skb,u16 family,const struct netlbl_lsm_secattr * secattr)1303948bf85cSPaul Moore int netlbl_skbuff_setattr(struct sk_buff *skb,
1304948bf85cSPaul Moore 			  u16 family,
1305948bf85cSPaul Moore 			  const struct netlbl_lsm_secattr *secattr)
1306948bf85cSPaul Moore {
1307948bf85cSPaul Moore 	int ret_val;
1308948bf85cSPaul Moore 	struct iphdr *hdr4;
13092917f57bSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
13102917f57bSHuw Davies 	struct ipv6hdr *hdr6;
13112917f57bSHuw Davies #endif
13126a8b7f0cSPaul Moore 	struct netlbl_dommap_def *entry;
1313948bf85cSPaul Moore 
1314948bf85cSPaul Moore 	rcu_read_lock();
1315948bf85cSPaul Moore 	switch (family) {
1316948bf85cSPaul Moore 	case AF_INET:
1317948bf85cSPaul Moore 		hdr4 = ip_hdr(skb);
13182917f57bSHuw Davies 		entry = netlbl_domhsh_getentry_af4(secattr->domain,
13192917f57bSHuw Davies 						   hdr4->daddr);
13206a8b7f0cSPaul Moore 		if (entry == NULL) {
1321948bf85cSPaul Moore 			ret_val = -ENOENT;
1322948bf85cSPaul Moore 			goto skbuff_setattr_return;
1323948bf85cSPaul Moore 		}
13246a8b7f0cSPaul Moore 		switch (entry->type) {
1325948bf85cSPaul Moore 		case NETLBL_NLTYPE_CIPSOV4:
13266a8b7f0cSPaul Moore 			ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso,
1327948bf85cSPaul Moore 							  secattr);
1328948bf85cSPaul Moore 			break;
1329948bf85cSPaul Moore 		case NETLBL_NLTYPE_UNLABELED:
1330948bf85cSPaul Moore 			/* just delete the protocols we support for right now
1331948bf85cSPaul Moore 			 * but we could remove other protocols if needed */
1332948bf85cSPaul Moore 			ret_val = cipso_v4_skbuff_delattr(skb);
1333948bf85cSPaul Moore 			break;
1334948bf85cSPaul Moore 		default:
1335948bf85cSPaul Moore 			ret_val = -ENOENT;
1336948bf85cSPaul Moore 		}
1337948bf85cSPaul Moore 		break;
1338dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1339948bf85cSPaul Moore 	case AF_INET6:
13402917f57bSHuw Davies 		hdr6 = ipv6_hdr(skb);
13412917f57bSHuw Davies 		entry = netlbl_domhsh_getentry_af6(secattr->domain,
13422917f57bSHuw Davies 						   &hdr6->daddr);
13432917f57bSHuw Davies 		if (entry == NULL) {
13442917f57bSHuw Davies 			ret_val = -ENOENT;
13452917f57bSHuw Davies 			goto skbuff_setattr_return;
13462917f57bSHuw Davies 		}
13472917f57bSHuw Davies 		switch (entry->type) {
13482917f57bSHuw Davies 		case NETLBL_NLTYPE_CALIPSO:
13492917f57bSHuw Davies 			ret_val = calipso_skbuff_setattr(skb, entry->calipso,
13502917f57bSHuw Davies 							 secattr);
13512917f57bSHuw Davies 			break;
13522917f57bSHuw Davies 		case NETLBL_NLTYPE_UNLABELED:
13532917f57bSHuw Davies 			/* just delete the protocols we support for right now
13542917f57bSHuw Davies 			 * but we could remove other protocols if needed */
13552917f57bSHuw Davies 			ret_val = calipso_skbuff_delattr(skb);
13562917f57bSHuw Davies 			break;
13572917f57bSHuw Davies 		default:
13582917f57bSHuw Davies 			ret_val = -ENOENT;
13592917f57bSHuw Davies 		}
1360948bf85cSPaul Moore 		break;
1361948bf85cSPaul Moore #endif /* IPv6 */
1362948bf85cSPaul Moore 	default:
1363389fb800SPaul Moore 		ret_val = -EPROTONOSUPPORT;
1364948bf85cSPaul Moore 	}
1365948bf85cSPaul Moore 
1366948bf85cSPaul Moore skbuff_setattr_return:
1367948bf85cSPaul Moore 	rcu_read_unlock();
1368948bf85cSPaul Moore 	return ret_val;
1369948bf85cSPaul Moore }
1370948bf85cSPaul Moore 
1371948bf85cSPaul Moore /**
1372d15c345fSPaul Moore  * netlbl_skbuff_getattr - Determine the security attributes of a packet
1373d15c345fSPaul Moore  * @skb: the packet
137475e22910SPaul Moore  * @family: protocol family
1375d15c345fSPaul Moore  * @secattr: the security attributes
1376d15c345fSPaul Moore  *
1377d15c345fSPaul Moore  * Description:
1378d15c345fSPaul Moore  * Examines the given packet to see if a recognized form of packet labeling
1379d15c345fSPaul Moore  * is present, if so it parses the packet label and returns the security
1380d15c345fSPaul Moore  * attributes in @secattr.  Returns zero on success, negative values on
1381d15c345fSPaul Moore  * failure.
1382d15c345fSPaul Moore  *
1383d15c345fSPaul Moore  */
netlbl_skbuff_getattr(const struct sk_buff * skb,u16 family,struct netlbl_lsm_secattr * secattr)1384d15c345fSPaul Moore int netlbl_skbuff_getattr(const struct sk_buff *skb,
138575e22910SPaul Moore 			  u16 family,
1386d15c345fSPaul Moore 			  struct netlbl_lsm_secattr *secattr)
1387d15c345fSPaul Moore {
138804f81f01SPaul Moore 	unsigned char *ptr;
138904f81f01SPaul Moore 
1390389fb800SPaul Moore 	switch (family) {
1391389fb800SPaul Moore 	case AF_INET:
139204f81f01SPaul Moore 		ptr = cipso_v4_optptr(skb);
139304f81f01SPaul Moore 		if (ptr && cipso_v4_getattr(ptr, secattr) == 0)
1394d15c345fSPaul Moore 			return 0;
1395389fb800SPaul Moore 		break;
1396dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
1397389fb800SPaul Moore 	case AF_INET6:
13982917f57bSHuw Davies 		ptr = calipso_optptr(skb);
13992917f57bSHuw Davies 		if (ptr && calipso_getattr(ptr, secattr) == 0)
14002917f57bSHuw Davies 			return 0;
1401389fb800SPaul Moore 		break;
1402389fb800SPaul Moore #endif /* IPv6 */
1403389fb800SPaul Moore 	}
1404d15c345fSPaul Moore 
14058cc44579SPaul Moore 	return netlbl_unlabel_getattr(skb, family, secattr);
1406d15c345fSPaul Moore }
1407d15c345fSPaul Moore 
1408d15c345fSPaul Moore /**
1409d15c345fSPaul Moore  * netlbl_skbuff_err - Handle a LSM error on a sk_buff
1410d15c345fSPaul Moore  * @skb: the packet
1411a04e71f6SHuw Davies  * @family: the family
1412d15c345fSPaul Moore  * @error: the error code
1413dfaebe98SPaul Moore  * @gateway: true if host is acting as a gateway, false otherwise
1414d15c345fSPaul Moore  *
1415d15c345fSPaul Moore  * Description:
1416d15c345fSPaul Moore  * Deal with a LSM problem when handling the packet in @skb, typically this is
1417d15c345fSPaul Moore  * a permission denied problem (-EACCES).  The correct action is determined
1418d15c345fSPaul Moore  * according to the packet's labeling protocol.
1419d15c345fSPaul Moore  *
1420d15c345fSPaul Moore  */
netlbl_skbuff_err(struct sk_buff * skb,u16 family,int error,int gateway)1421a04e71f6SHuw Davies void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway)
1422d15c345fSPaul Moore {
1423a04e71f6SHuw Davies 	switch (family) {
1424a04e71f6SHuw Davies 	case AF_INET:
142504f81f01SPaul Moore 		if (cipso_v4_optptr(skb))
1426dfaebe98SPaul Moore 			cipso_v4_error(skb, error, gateway);
1427a04e71f6SHuw Davies 		break;
1428a04e71f6SHuw Davies 	}
1429d15c345fSPaul Moore }
1430d15c345fSPaul Moore 
1431d15c345fSPaul Moore /**
1432d15c345fSPaul Moore  * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
1433d15c345fSPaul Moore  *
1434d15c345fSPaul Moore  * Description:
1435d15c345fSPaul Moore  * For all of the NetLabel protocols that support some form of label mapping
1436d15c345fSPaul Moore  * cache, invalidate the cache.  Returns zero on success, negative values on
1437d15c345fSPaul Moore  * error.
1438d15c345fSPaul Moore  *
1439d15c345fSPaul Moore  */
netlbl_cache_invalidate(void)1440d15c345fSPaul Moore void netlbl_cache_invalidate(void)
1441d15c345fSPaul Moore {
1442d15c345fSPaul Moore 	cipso_v4_cache_invalidate();
14434fee5242SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
14444fee5242SHuw Davies 	calipso_cache_invalidate();
14454fee5242SHuw Davies #endif /* IPv6 */
1446d15c345fSPaul Moore }
1447d15c345fSPaul Moore 
1448d15c345fSPaul Moore /**
1449d15c345fSPaul Moore  * netlbl_cache_add - Add an entry to a NetLabel protocol cache
1450d15c345fSPaul Moore  * @skb: the packet
14514fee5242SHuw Davies  * @family: the family
1452d15c345fSPaul Moore  * @secattr: the packet's security attributes
1453d15c345fSPaul Moore  *
1454d15c345fSPaul Moore  * Description:
1455d15c345fSPaul Moore  * Add the LSM security attributes for the given packet to the underlying
1456d15c345fSPaul Moore  * NetLabel protocol's label mapping cache.  Returns zero on success, negative
1457d15c345fSPaul Moore  * values on error.
1458d15c345fSPaul Moore  *
1459d15c345fSPaul Moore  */
netlbl_cache_add(const struct sk_buff * skb,u16 family,const struct netlbl_lsm_secattr * secattr)14604fee5242SHuw Davies int netlbl_cache_add(const struct sk_buff *skb, u16 family,
1461d15c345fSPaul Moore 		     const struct netlbl_lsm_secattr *secattr)
1462d15c345fSPaul Moore {
146304f81f01SPaul Moore 	unsigned char *ptr;
146404f81f01SPaul Moore 
1465701a90baSPaul Moore 	if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
1466d15c345fSPaul Moore 		return -ENOMSG;
1467d15c345fSPaul Moore 
14684fee5242SHuw Davies 	switch (family) {
14694fee5242SHuw Davies 	case AF_INET:
147004f81f01SPaul Moore 		ptr = cipso_v4_optptr(skb);
147104f81f01SPaul Moore 		if (ptr)
147204f81f01SPaul Moore 			return cipso_v4_cache_add(ptr, secattr);
14734fee5242SHuw Davies 		break;
14744fee5242SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
14754fee5242SHuw Davies 	case AF_INET6:
14764fee5242SHuw Davies 		ptr = calipso_optptr(skb);
14774fee5242SHuw Davies 		if (ptr)
14784fee5242SHuw Davies 			return calipso_cache_add(ptr, secattr);
14794fee5242SHuw Davies 		break;
14804fee5242SHuw Davies #endif /* IPv6 */
14814fee5242SHuw Davies 	}
1482d15c345fSPaul Moore 	return -ENOMSG;
1483d15c345fSPaul Moore }
1484d15c345fSPaul Moore 
1485d15c345fSPaul Moore /*
14866c2e8ac0SPaul Moore  * Protocol Engine Functions
14876c2e8ac0SPaul Moore  */
14886c2e8ac0SPaul Moore 
14896c2e8ac0SPaul Moore /**
14906c2e8ac0SPaul Moore  * netlbl_audit_start - Start an audit message
14916c2e8ac0SPaul Moore  * @type: audit message type
14926c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
14936c2e8ac0SPaul Moore  *
14946c2e8ac0SPaul Moore  * Description:
14956c2e8ac0SPaul Moore  * Start an audit message using the type specified in @type and fill the audit
14966c2e8ac0SPaul Moore  * message with some fields common to all NetLabel audit messages.  This
14976c2e8ac0SPaul Moore  * function should only be used by protocol engines, not LSMs.  Returns a
14986c2e8ac0SPaul Moore  * pointer to the audit buffer on success, NULL on failure.
14996c2e8ac0SPaul Moore  *
15006c2e8ac0SPaul Moore  */
netlbl_audit_start(int type,struct netlbl_audit * audit_info)15016c2e8ac0SPaul Moore struct audit_buffer *netlbl_audit_start(int type,
15026c2e8ac0SPaul Moore 					struct netlbl_audit *audit_info)
15036c2e8ac0SPaul Moore {
15046c2e8ac0SPaul Moore 	return netlbl_audit_start_common(type, audit_info);
15056c2e8ac0SPaul Moore }
1506cb72d382SHuw Davies EXPORT_SYMBOL(netlbl_audit_start);
15076c2e8ac0SPaul Moore 
15086c2e8ac0SPaul Moore /*
1509d15c345fSPaul Moore  * Setup Functions
1510d15c345fSPaul Moore  */
1511d15c345fSPaul Moore 
1512d15c345fSPaul Moore /**
1513d15c345fSPaul Moore  * netlbl_init - Initialize NetLabel
1514d15c345fSPaul Moore  *
1515d15c345fSPaul Moore  * Description:
1516d15c345fSPaul Moore  * Perform the required NetLabel initialization before first use.
1517d15c345fSPaul Moore  *
1518d15c345fSPaul Moore  */
netlbl_init(void)1519d15c345fSPaul Moore static int __init netlbl_init(void)
1520d15c345fSPaul Moore {
1521d15c345fSPaul Moore 	int ret_val;
1522d15c345fSPaul Moore 
1523d15c345fSPaul Moore 	printk(KERN_INFO "NetLabel: Initializing\n");
1524d15c345fSPaul Moore 	printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
1525d15c345fSPaul Moore 	       (1 << NETLBL_DOMHSH_BITSIZE));
1526bcd5e1a4SPaul Moore 	printk(KERN_INFO "NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO\n");
1527d15c345fSPaul Moore 
1528d15c345fSPaul Moore 	ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
1529d15c345fSPaul Moore 	if (ret_val != 0)
1530d15c345fSPaul Moore 		goto init_failure;
1531d15c345fSPaul Moore 
15328cc44579SPaul Moore 	ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
15338cc44579SPaul Moore 	if (ret_val != 0)
15348cc44579SPaul Moore 		goto init_failure;
15358cc44579SPaul Moore 
1536d15c345fSPaul Moore 	ret_val = netlbl_netlink_init();
1537d15c345fSPaul Moore 	if (ret_val != 0)
1538d15c345fSPaul Moore 		goto init_failure;
1539d15c345fSPaul Moore 
1540d15c345fSPaul Moore 	ret_val = netlbl_unlabel_defconf();
1541d15c345fSPaul Moore 	if (ret_val != 0)
1542d15c345fSPaul Moore 		goto init_failure;
1543d15c345fSPaul Moore 	printk(KERN_INFO "NetLabel:  unlabeled traffic allowed by default\n");
1544d15c345fSPaul Moore 
1545d15c345fSPaul Moore 	return 0;
1546d15c345fSPaul Moore 
1547d15c345fSPaul Moore init_failure:
1548d15c345fSPaul Moore 	panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
1549d15c345fSPaul Moore }
1550d15c345fSPaul Moore 
1551d15c345fSPaul Moore subsys_initcall(netlbl_init);
1552