cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netlabel_kapi.c (38335B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NetLabel Kernel API
      4 *
      5 * This file defines the kernel API for the NetLabel system.  The NetLabel
      6 * system manages static and dynamic label mappings for network protocols such
      7 * as CIPSO and RIPSO.
      8 *
      9 * Author: Paul Moore <paul@paul-moore.com>
     10 */
     11
     12/*
     13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
     14 */
     15
     16#include <linux/init.h>
     17#include <linux/types.h>
     18#include <linux/slab.h>
     19#include <linux/audit.h>
     20#include <linux/in.h>
     21#include <linux/in6.h>
     22#include <net/ip.h>
     23#include <net/ipv6.h>
     24#include <net/netlabel.h>
     25#include <net/cipso_ipv4.h>
     26#include <net/calipso.h>
     27#include <asm/bug.h>
     28#include <linux/atomic.h>
     29
     30#include "netlabel_domainhash.h"
     31#include "netlabel_unlabeled.h"
     32#include "netlabel_cipso_v4.h"
     33#include "netlabel_calipso.h"
     34#include "netlabel_user.h"
     35#include "netlabel_mgmt.h"
     36#include "netlabel_addrlist.h"
     37
     38/*
     39 * Configuration Functions
     40 */
     41
     42/**
     43 * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
     44 * @domain: the domain mapping to remove
     45 * @family: address family
     46 * @addr: IP address
     47 * @mask: IP address mask
     48 * @audit_info: NetLabel audit information
     49 *
     50 * Description:
     51 * Removes a NetLabel/LSM domain mapping.  A @domain value of NULL causes the
     52 * default domain mapping to be removed.  Returns zero on success, negative
     53 * values on failure.
     54 *
     55 */
     56int netlbl_cfg_map_del(const char *domain,
     57		       u16 family,
     58		       const void *addr,
     59		       const void *mask,
     60		       struct netlbl_audit *audit_info)
     61{
     62	if (addr == NULL && mask == NULL) {
     63		return netlbl_domhsh_remove(domain, family, audit_info);
     64	} else if (addr != NULL && mask != NULL) {
     65		switch (family) {
     66		case AF_INET:
     67			return netlbl_domhsh_remove_af4(domain, addr, mask,
     68							audit_info);
     69#if IS_ENABLED(CONFIG_IPV6)
     70		case AF_INET6:
     71			return netlbl_domhsh_remove_af6(domain, addr, mask,
     72							audit_info);
     73#endif /* IPv6 */
     74		default:
     75			return -EPFNOSUPPORT;
     76		}
     77	} else
     78		return -EINVAL;
     79}
     80
     81/**
     82 * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
     83 * @domain: the domain mapping to add
     84 * @family: address family
     85 * @addr: IP address
     86 * @mask: IP address mask
     87 * @audit_info: NetLabel audit information
     88 *
     89 * Description:
     90 * Adds a new unlabeled NetLabel/LSM domain mapping.  A @domain value of NULL
     91 * causes a new default domain mapping to be added.  Returns zero on success,
     92 * negative values on failure.
     93 *
     94 */
     95int netlbl_cfg_unlbl_map_add(const char *domain,
     96			     u16 family,
     97			     const void *addr,
     98			     const void *mask,
     99			     struct netlbl_audit *audit_info)
    100{
    101	int ret_val = -ENOMEM;
    102	struct netlbl_dom_map *entry;
    103	struct netlbl_domaddr_map *addrmap = NULL;
    104	struct netlbl_domaddr4_map *map4 = NULL;
    105	struct netlbl_domaddr6_map *map6 = NULL;
    106
    107	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    108	if (entry == NULL)
    109		return -ENOMEM;
    110	if (domain != NULL) {
    111		entry->domain = kstrdup(domain, GFP_ATOMIC);
    112		if (entry->domain == NULL)
    113			goto cfg_unlbl_map_add_failure;
    114	}
    115	entry->family = family;
    116
    117	if (addr == NULL && mask == NULL)
    118		entry->def.type = NETLBL_NLTYPE_UNLABELED;
    119	else if (addr != NULL && mask != NULL) {
    120		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
    121		if (addrmap == NULL)
    122			goto cfg_unlbl_map_add_failure;
    123		INIT_LIST_HEAD(&addrmap->list4);
    124		INIT_LIST_HEAD(&addrmap->list6);
    125
    126		switch (family) {
    127		case AF_INET: {
    128			const struct in_addr *addr4 = addr;
    129			const struct in_addr *mask4 = mask;
    130			map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
    131			if (map4 == NULL)
    132				goto cfg_unlbl_map_add_failure;
    133			map4->def.type = NETLBL_NLTYPE_UNLABELED;
    134			map4->list.addr = addr4->s_addr & mask4->s_addr;
    135			map4->list.mask = mask4->s_addr;
    136			map4->list.valid = 1;
    137			ret_val = netlbl_af4list_add(&map4->list,
    138						     &addrmap->list4);
    139			if (ret_val != 0)
    140				goto cfg_unlbl_map_add_failure;
    141			break;
    142			}
    143#if IS_ENABLED(CONFIG_IPV6)
    144		case AF_INET6: {
    145			const struct in6_addr *addr6 = addr;
    146			const struct in6_addr *mask6 = mask;
    147			map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
    148			if (map6 == NULL)
    149				goto cfg_unlbl_map_add_failure;
    150			map6->def.type = NETLBL_NLTYPE_UNLABELED;
    151			map6->list.addr = *addr6;
    152			map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
    153			map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
    154			map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
    155			map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
    156			map6->list.mask = *mask6;
    157			map6->list.valid = 1;
    158			ret_val = netlbl_af6list_add(&map6->list,
    159						     &addrmap->list6);
    160			if (ret_val != 0)
    161				goto cfg_unlbl_map_add_failure;
    162			break;
    163			}
    164#endif /* IPv6 */
    165		default:
    166			goto cfg_unlbl_map_add_failure;
    167		}
    168
    169		entry->def.addrsel = addrmap;
    170		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
    171	} else {
    172		ret_val = -EINVAL;
    173		goto cfg_unlbl_map_add_failure;
    174	}
    175
    176	ret_val = netlbl_domhsh_add(entry, audit_info);
    177	if (ret_val != 0)
    178		goto cfg_unlbl_map_add_failure;
    179
    180	return 0;
    181
    182cfg_unlbl_map_add_failure:
    183	kfree(entry->domain);
    184	kfree(entry);
    185	kfree(addrmap);
    186	kfree(map4);
    187	kfree(map6);
    188	return ret_val;
    189}
    190
    191
    192/**
    193 * netlbl_cfg_unlbl_static_add - Adds a new static label
    194 * @net: network namespace
    195 * @dev_name: interface name
    196 * @addr: IP address in network byte order (struct in[6]_addr)
    197 * @mask: address mask in network byte order (struct in[6]_addr)
    198 * @family: address family
    199 * @secid: LSM secid value for the entry
    200 * @audit_info: NetLabel audit information
    201 *
    202 * Description:
    203 * Adds a new NetLabel static label to be used when protocol provided labels
    204 * are not present on incoming traffic.  If @dev_name is NULL then the default
    205 * interface will be used.  Returns zero on success, negative values on failure.
    206 *
    207 */
    208int netlbl_cfg_unlbl_static_add(struct net *net,
    209				const char *dev_name,
    210				const void *addr,
    211				const void *mask,
    212				u16 family,
    213				u32 secid,
    214				struct netlbl_audit *audit_info)
    215{
    216	u32 addr_len;
    217
    218	switch (family) {
    219	case AF_INET:
    220		addr_len = sizeof(struct in_addr);
    221		break;
    222#if IS_ENABLED(CONFIG_IPV6)
    223	case AF_INET6:
    224		addr_len = sizeof(struct in6_addr);
    225		break;
    226#endif /* IPv6 */
    227	default:
    228		return -EPFNOSUPPORT;
    229	}
    230
    231	return netlbl_unlhsh_add(net,
    232				 dev_name, addr, mask, addr_len,
    233				 secid, audit_info);
    234}
    235
    236/**
    237 * netlbl_cfg_unlbl_static_del - Removes an existing static label
    238 * @net: network namespace
    239 * @dev_name: interface name
    240 * @addr: IP address in network byte order (struct in[6]_addr)
    241 * @mask: address mask in network byte order (struct in[6]_addr)
    242 * @family: address family
    243 * @audit_info: NetLabel audit information
    244 *
    245 * Description:
    246 * Removes an existing NetLabel static label used when protocol provided labels
    247 * are not present on incoming traffic.  If @dev_name is NULL then the default
    248 * interface will be used.  Returns zero on success, negative values on failure.
    249 *
    250 */
    251int netlbl_cfg_unlbl_static_del(struct net *net,
    252				const char *dev_name,
    253				const void *addr,
    254				const void *mask,
    255				u16 family,
    256				struct netlbl_audit *audit_info)
    257{
    258	u32 addr_len;
    259
    260	switch (family) {
    261	case AF_INET:
    262		addr_len = sizeof(struct in_addr);
    263		break;
    264#if IS_ENABLED(CONFIG_IPV6)
    265	case AF_INET6:
    266		addr_len = sizeof(struct in6_addr);
    267		break;
    268#endif /* IPv6 */
    269	default:
    270		return -EPFNOSUPPORT;
    271	}
    272
    273	return netlbl_unlhsh_remove(net,
    274				    dev_name, addr, mask, addr_len,
    275				    audit_info);
    276}
    277
    278/**
    279 * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
    280 * @doi_def: CIPSO DOI definition
    281 * @audit_info: NetLabel audit information
    282 *
    283 * Description:
    284 * Add a new CIPSO DOI definition as defined by @doi_def.  Returns zero on
    285 * success and negative values on failure.
    286 *
    287 */
    288int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
    289			   struct netlbl_audit *audit_info)
    290{
    291	return cipso_v4_doi_add(doi_def, audit_info);
    292}
    293
    294/**
    295 * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
    296 * @doi: CIPSO DOI
    297 * @audit_info: NetLabel audit information
    298 *
    299 * Description:
    300 * Remove an existing CIPSO DOI definition matching @doi.  Returns zero on
    301 * success and negative values on failure.
    302 *
    303 */
    304void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
    305{
    306	cipso_v4_doi_remove(doi, audit_info);
    307}
    308
    309/**
    310 * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
    311 * @doi: the CIPSO DOI
    312 * @domain: the domain mapping to add
    313 * @addr: IP address
    314 * @mask: IP address mask
    315 * @audit_info: NetLabel audit information
    316 *
    317 * Description:
    318 * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
    319 * subsystem.  A @domain value of NULL adds a new default domain mapping.
    320 * Returns zero on success, negative values on failure.
    321 *
    322 */
    323int netlbl_cfg_cipsov4_map_add(u32 doi,
    324			       const char *domain,
    325			       const struct in_addr *addr,
    326			       const struct in_addr *mask,
    327			       struct netlbl_audit *audit_info)
    328{
    329	int ret_val = -ENOMEM;
    330	struct cipso_v4_doi *doi_def;
    331	struct netlbl_dom_map *entry;
    332	struct netlbl_domaddr_map *addrmap = NULL;
    333	struct netlbl_domaddr4_map *addrinfo = NULL;
    334
    335	doi_def = cipso_v4_doi_getdef(doi);
    336	if (doi_def == NULL)
    337		return -ENOENT;
    338
    339	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    340	if (entry == NULL)
    341		goto out_entry;
    342	entry->family = AF_INET;
    343	if (domain != NULL) {
    344		entry->domain = kstrdup(domain, GFP_ATOMIC);
    345		if (entry->domain == NULL)
    346			goto out_domain;
    347	}
    348
    349	if (addr == NULL && mask == NULL) {
    350		entry->def.cipso = doi_def;
    351		entry->def.type = NETLBL_NLTYPE_CIPSOV4;
    352	} else if (addr != NULL && mask != NULL) {
    353		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
    354		if (addrmap == NULL)
    355			goto out_addrmap;
    356		INIT_LIST_HEAD(&addrmap->list4);
    357		INIT_LIST_HEAD(&addrmap->list6);
    358
    359		addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
    360		if (addrinfo == NULL)
    361			goto out_addrinfo;
    362		addrinfo->def.cipso = doi_def;
    363		addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4;
    364		addrinfo->list.addr = addr->s_addr & mask->s_addr;
    365		addrinfo->list.mask = mask->s_addr;
    366		addrinfo->list.valid = 1;
    367		ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
    368		if (ret_val != 0)
    369			goto cfg_cipsov4_map_add_failure;
    370
    371		entry->def.addrsel = addrmap;
    372		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
    373	} else {
    374		ret_val = -EINVAL;
    375		goto out_addrmap;
    376	}
    377
    378	ret_val = netlbl_domhsh_add(entry, audit_info);
    379	if (ret_val != 0)
    380		goto cfg_cipsov4_map_add_failure;
    381
    382	return 0;
    383
    384cfg_cipsov4_map_add_failure:
    385	kfree(addrinfo);
    386out_addrinfo:
    387	kfree(addrmap);
    388out_addrmap:
    389	kfree(entry->domain);
    390out_domain:
    391	kfree(entry);
    392out_entry:
    393	cipso_v4_doi_putdef(doi_def);
    394	return ret_val;
    395}
    396
    397/**
    398 * netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
    399 * @doi_def: CALIPSO DOI definition
    400 * @audit_info: NetLabel audit information
    401 *
    402 * Description:
    403 * Add a new CALIPSO DOI definition as defined by @doi_def.  Returns zero on
    404 * success and negative values on failure.
    405 *
    406 */
    407int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
    408			   struct netlbl_audit *audit_info)
    409{
    410#if IS_ENABLED(CONFIG_IPV6)
    411	return calipso_doi_add(doi_def, audit_info);
    412#else /* IPv6 */
    413	return -ENOSYS;
    414#endif /* IPv6 */
    415}
    416
    417/**
    418 * netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
    419 * @doi: CALIPSO DOI
    420 * @audit_info: NetLabel audit information
    421 *
    422 * Description:
    423 * Remove an existing CALIPSO DOI definition matching @doi.  Returns zero on
    424 * success and negative values on failure.
    425 *
    426 */
    427void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
    428{
    429#if IS_ENABLED(CONFIG_IPV6)
    430	calipso_doi_remove(doi, audit_info);
    431#endif /* IPv6 */
    432}
    433
    434/**
    435 * netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
    436 * @doi: the CALIPSO DOI
    437 * @domain: the domain mapping to add
    438 * @addr: IP address
    439 * @mask: IP address mask
    440 * @audit_info: NetLabel audit information
    441 *
    442 * Description:
    443 * Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
    444 * NetLabel subsystem.  A @domain value of NULL adds a new default domain
    445 * mapping.  Returns zero on success, negative values on failure.
    446 *
    447 */
    448int netlbl_cfg_calipso_map_add(u32 doi,
    449			       const char *domain,
    450			       const struct in6_addr *addr,
    451			       const struct in6_addr *mask,
    452			       struct netlbl_audit *audit_info)
    453{
    454#if IS_ENABLED(CONFIG_IPV6)
    455	int ret_val = -ENOMEM;
    456	struct calipso_doi *doi_def;
    457	struct netlbl_dom_map *entry;
    458	struct netlbl_domaddr_map *addrmap = NULL;
    459	struct netlbl_domaddr6_map *addrinfo = NULL;
    460
    461	doi_def = calipso_doi_getdef(doi);
    462	if (doi_def == NULL)
    463		return -ENOENT;
    464
    465	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
    466	if (entry == NULL)
    467		goto out_entry;
    468	entry->family = AF_INET6;
    469	if (domain != NULL) {
    470		entry->domain = kstrdup(domain, GFP_ATOMIC);
    471		if (entry->domain == NULL)
    472			goto out_domain;
    473	}
    474
    475	if (addr == NULL && mask == NULL) {
    476		entry->def.calipso = doi_def;
    477		entry->def.type = NETLBL_NLTYPE_CALIPSO;
    478	} else if (addr != NULL && mask != NULL) {
    479		addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
    480		if (addrmap == NULL)
    481			goto out_addrmap;
    482		INIT_LIST_HEAD(&addrmap->list4);
    483		INIT_LIST_HEAD(&addrmap->list6);
    484
    485		addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
    486		if (addrinfo == NULL)
    487			goto out_addrinfo;
    488		addrinfo->def.calipso = doi_def;
    489		addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
    490		addrinfo->list.addr = *addr;
    491		addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
    492		addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
    493		addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
    494		addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
    495		addrinfo->list.mask = *mask;
    496		addrinfo->list.valid = 1;
    497		ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
    498		if (ret_val != 0)
    499			goto cfg_calipso_map_add_failure;
    500
    501		entry->def.addrsel = addrmap;
    502		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
    503	} else {
    504		ret_val = -EINVAL;
    505		goto out_addrmap;
    506	}
    507
    508	ret_val = netlbl_domhsh_add(entry, audit_info);
    509	if (ret_val != 0)
    510		goto cfg_calipso_map_add_failure;
    511
    512	return 0;
    513
    514cfg_calipso_map_add_failure:
    515	kfree(addrinfo);
    516out_addrinfo:
    517	kfree(addrmap);
    518out_addrmap:
    519	kfree(entry->domain);
    520out_domain:
    521	kfree(entry);
    522out_entry:
    523	calipso_doi_putdef(doi_def);
    524	return ret_val;
    525#else /* IPv6 */
    526	return -ENOSYS;
    527#endif /* IPv6 */
    528}
    529
    530/*
    531 * Security Attribute Functions
    532 */
    533
    534#define _CM_F_NONE	0x00000000
    535#define _CM_F_ALLOC	0x00000001
    536#define _CM_F_WALK	0x00000002
    537
    538/**
    539 * _netlbl_catmap_getnode - Get a individual node from a catmap
    540 * @catmap: pointer to the category bitmap
    541 * @offset: the requested offset
    542 * @cm_flags: catmap flags, see _CM_F_*
    543 * @gfp_flags: memory allocation flags
    544 *
    545 * Description:
    546 * Iterate through the catmap looking for the node associated with @offset.
    547 * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node,
    548 * one will be created and inserted into the catmap.  If the _CM_F_WALK flag is
    549 * set in @cm_flags and there is no associated node, the next highest node will
    550 * be returned.  Returns a pointer to the node on success, NULL on failure.
    551 *
    552 */
    553static struct netlbl_lsm_catmap *_netlbl_catmap_getnode(
    554					     struct netlbl_lsm_catmap **catmap,
    555					     u32 offset,
    556					     unsigned int cm_flags,
    557					     gfp_t gfp_flags)
    558{
    559	struct netlbl_lsm_catmap *iter = *catmap;
    560	struct netlbl_lsm_catmap *prev = NULL;
    561
    562	if (iter == NULL)
    563		goto catmap_getnode_alloc;
    564	if (offset < iter->startbit)
    565		goto catmap_getnode_walk;
    566	while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
    567		prev = iter;
    568		iter = iter->next;
    569	}
    570	if (iter == NULL || offset < iter->startbit)
    571		goto catmap_getnode_walk;
    572
    573	return iter;
    574
    575catmap_getnode_walk:
    576	if (cm_flags & _CM_F_WALK)
    577		return iter;
    578catmap_getnode_alloc:
    579	if (!(cm_flags & _CM_F_ALLOC))
    580		return NULL;
    581
    582	iter = netlbl_catmap_alloc(gfp_flags);
    583	if (iter == NULL)
    584		return NULL;
    585	iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1);
    586
    587	if (prev == NULL) {
    588		iter->next = *catmap;
    589		*catmap = iter;
    590	} else {
    591		iter->next = prev->next;
    592		prev->next = iter;
    593	}
    594
    595	return iter;
    596}
    597
    598/**
    599 * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit
    600 * @catmap: the category bitmap
    601 * @offset: the offset to start searching at, in bits
    602 *
    603 * Description:
    604 * This function walks a LSM secattr category bitmap starting at @offset and
    605 * returns the spot of the first set bit or -ENOENT if no bits are set.
    606 *
    607 */
    608int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
    609{
    610	struct netlbl_lsm_catmap *iter;
    611	u32 idx;
    612	u32 bit;
    613	NETLBL_CATMAP_MAPTYPE bitmap;
    614
    615	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
    616	if (iter == NULL)
    617		return -ENOENT;
    618	if (offset > iter->startbit) {
    619		offset -= iter->startbit;
    620		idx = offset / NETLBL_CATMAP_MAPSIZE;
    621		bit = offset % NETLBL_CATMAP_MAPSIZE;
    622	} else {
    623		idx = 0;
    624		bit = 0;
    625	}
    626	bitmap = iter->bitmap[idx] >> bit;
    627
    628	for (;;) {
    629		if (bitmap != 0) {
    630			while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
    631				bitmap >>= 1;
    632				bit++;
    633			}
    634			return iter->startbit +
    635			       (NETLBL_CATMAP_MAPSIZE * idx) + bit;
    636		}
    637		if (++idx >= NETLBL_CATMAP_MAPCNT) {
    638			if (iter->next != NULL) {
    639				iter = iter->next;
    640				idx = 0;
    641			} else
    642				return -ENOENT;
    643		}
    644		bitmap = iter->bitmap[idx];
    645		bit = 0;
    646	}
    647
    648	return -ENOENT;
    649}
    650EXPORT_SYMBOL(netlbl_catmap_walk);
    651
    652/**
    653 * netlbl_catmap_walkrng - Find the end of a string of set bits
    654 * @catmap: the category bitmap
    655 * @offset: the offset to start searching at, in bits
    656 *
    657 * Description:
    658 * This function walks a LSM secattr category bitmap starting at @offset and
    659 * returns the spot of the first cleared bit or -ENOENT if the offset is past
    660 * the end of the bitmap.
    661 *
    662 */
    663int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset)
    664{
    665	struct netlbl_lsm_catmap *iter;
    666	struct netlbl_lsm_catmap *prev = NULL;
    667	u32 idx;
    668	u32 bit;
    669	NETLBL_CATMAP_MAPTYPE bitmask;
    670	NETLBL_CATMAP_MAPTYPE bitmap;
    671
    672	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
    673	if (iter == NULL)
    674		return -ENOENT;
    675	if (offset > iter->startbit) {
    676		offset -= iter->startbit;
    677		idx = offset / NETLBL_CATMAP_MAPSIZE;
    678		bit = offset % NETLBL_CATMAP_MAPSIZE;
    679	} else {
    680		idx = 0;
    681		bit = 0;
    682	}
    683	bitmask = NETLBL_CATMAP_BIT << bit;
    684
    685	for (;;) {
    686		bitmap = iter->bitmap[idx];
    687		while (bitmask != 0 && (bitmap & bitmask) != 0) {
    688			bitmask <<= 1;
    689			bit++;
    690		}
    691
    692		if (prev && idx == 0 && bit == 0)
    693			return prev->startbit + NETLBL_CATMAP_SIZE - 1;
    694		else if (bitmask != 0)
    695			return iter->startbit +
    696				(NETLBL_CATMAP_MAPSIZE * idx) + bit - 1;
    697		else if (++idx >= NETLBL_CATMAP_MAPCNT) {
    698			if (iter->next == NULL)
    699				return iter->startbit + NETLBL_CATMAP_SIZE - 1;
    700			prev = iter;
    701			iter = iter->next;
    702			idx = 0;
    703		}
    704		bitmask = NETLBL_CATMAP_BIT;
    705		bit = 0;
    706	}
    707
    708	return -ENOENT;
    709}
    710
    711/**
    712 * netlbl_catmap_getlong - Export an unsigned long bitmap
    713 * @catmap: pointer to the category bitmap
    714 * @offset: pointer to the requested offset
    715 * @bitmap: the exported bitmap
    716 *
    717 * Description:
    718 * Export a bitmap with an offset greater than or equal to @offset and return
    719 * it in @bitmap.  The @offset must be aligned to an unsigned long and will be
    720 * updated on return if different from what was requested; if the catmap is
    721 * empty at the requested offset and beyond, the @offset is set to (u32)-1.
    722 * Returns zero on success, negative values on failure.
    723 *
    724 */
    725int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
    726			  u32 *offset,
    727			  unsigned long *bitmap)
    728{
    729	struct netlbl_lsm_catmap *iter;
    730	u32 off = *offset;
    731	u32 idx;
    732
    733	/* only allow aligned offsets */
    734	if ((off & (BITS_PER_LONG - 1)) != 0)
    735		return -EINVAL;
    736
    737	/* a null catmap is equivalent to an empty one */
    738	if (!catmap) {
    739		*offset = (u32)-1;
    740		return 0;
    741	}
    742
    743	if (off < catmap->startbit) {
    744		off = catmap->startbit;
    745		*offset = off;
    746	}
    747	iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0);
    748	if (iter == NULL) {
    749		*offset = (u32)-1;
    750		return 0;
    751	}
    752
    753	if (off < iter->startbit) {
    754		*offset = iter->startbit;
    755		off = 0;
    756	} else
    757		off -= iter->startbit;
    758	idx = off / NETLBL_CATMAP_MAPSIZE;
    759	*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
    760
    761	return 0;
    762}
    763
    764/**
    765 * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap
    766 * @catmap: pointer to the category bitmap
    767 * @bit: the bit to set
    768 * @flags: memory allocation flags
    769 *
    770 * Description:
    771 * Set the bit specified by @bit in @catmap.  Returns zero on success,
    772 * negative values on failure.
    773 *
    774 */
    775int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
    776			 u32 bit,
    777			 gfp_t flags)
    778{
    779	struct netlbl_lsm_catmap *iter;
    780	u32 idx;
    781
    782	iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
    783	if (iter == NULL)
    784		return -ENOMEM;
    785
    786	bit -= iter->startbit;
    787	idx = bit / NETLBL_CATMAP_MAPSIZE;
    788	iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
    789
    790	return 0;
    791}
    792EXPORT_SYMBOL(netlbl_catmap_setbit);
    793
    794/**
    795 * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
    796 * @catmap: pointer to the category bitmap
    797 * @start: the starting bit
    798 * @end: the last bit in the string
    799 * @flags: memory allocation flags
    800 *
    801 * Description:
    802 * Set a range of bits, starting at @start and ending with @end.  Returns zero
    803 * on success, negative values on failure.
    804 *
    805 */
    806int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
    807			 u32 start,
    808			 u32 end,
    809			 gfp_t flags)
    810{
    811	int rc = 0;
    812	u32 spot = start;
    813
    814	while (rc == 0 && spot <= end) {
    815		if (((spot & (BITS_PER_LONG - 1)) == 0) &&
    816		    ((end - spot) > BITS_PER_LONG)) {
    817			rc = netlbl_catmap_setlong(catmap,
    818						   spot,
    819						   (unsigned long)-1,
    820						   flags);
    821			spot += BITS_PER_LONG;
    822		} else
    823			rc = netlbl_catmap_setbit(catmap, spot++, flags);
    824	}
    825
    826	return rc;
    827}
    828
    829/**
    830 * netlbl_catmap_setlong - Import an unsigned long bitmap
    831 * @catmap: pointer to the category bitmap
    832 * @offset: offset to the start of the imported bitmap
    833 * @bitmap: the bitmap to import
    834 * @flags: memory allocation flags
    835 *
    836 * Description:
    837 * Import the bitmap specified in @bitmap into @catmap, using the offset
    838 * in @offset.  The offset must be aligned to an unsigned long.  Returns zero
    839 * on success, negative values on failure.
    840 *
    841 */
    842int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
    843			  u32 offset,
    844			  unsigned long bitmap,
    845			  gfp_t flags)
    846{
    847	struct netlbl_lsm_catmap *iter;
    848	u32 idx;
    849
    850	/* only allow aligned offsets */
    851	if ((offset & (BITS_PER_LONG - 1)) != 0)
    852		return -EINVAL;
    853
    854	iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags);
    855	if (iter == NULL)
    856		return -ENOMEM;
    857
    858	offset -= iter->startbit;
    859	idx = offset / NETLBL_CATMAP_MAPSIZE;
    860	iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE);
    861
    862	return 0;
    863}
    864
    865/* Bitmap functions
    866 */
    867
    868/**
    869 * netlbl_bitmap_walk - Walk a bitmap looking for a bit
    870 * @bitmap: the bitmap
    871 * @bitmap_len: length in bits
    872 * @offset: starting offset
    873 * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
    874 *
    875 * Description:
    876 * Starting at @offset, walk the bitmap from left to right until either the
    877 * desired bit is found or we reach the end.  Return the bit offset, -1 if
    878 * not found, or -2 if error.
    879 */
    880int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
    881		       u32 offset, u8 state)
    882{
    883	u32 bit_spot;
    884	u32 byte_offset;
    885	unsigned char bitmask;
    886	unsigned char byte;
    887
    888	if (offset >= bitmap_len)
    889		return -1;
    890	byte_offset = offset / 8;
    891	byte = bitmap[byte_offset];
    892	bit_spot = offset;
    893	bitmask = 0x80 >> (offset % 8);
    894
    895	while (bit_spot < bitmap_len) {
    896		if ((state && (byte & bitmask) == bitmask) ||
    897		    (state == 0 && (byte & bitmask) == 0))
    898			return bit_spot;
    899
    900		if (++bit_spot >= bitmap_len)
    901			return -1;
    902		bitmask >>= 1;
    903		if (bitmask == 0) {
    904			byte = bitmap[++byte_offset];
    905			bitmask = 0x80;
    906		}
    907	}
    908
    909	return -1;
    910}
    911EXPORT_SYMBOL(netlbl_bitmap_walk);
    912
    913/**
    914 * netlbl_bitmap_setbit - Sets a single bit in a bitmap
    915 * @bitmap: the bitmap
    916 * @bit: the bit
    917 * @state: if non-zero, set the bit (1) else clear the bit (0)
    918 *
    919 * Description:
    920 * Set a single bit in the bitmask.  Returns zero on success, negative values
    921 * on error.
    922 */
    923void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state)
    924{
    925	u32 byte_spot;
    926	u8 bitmask;
    927
    928	/* gcc always rounds to zero when doing integer division */
    929	byte_spot = bit / 8;
    930	bitmask = 0x80 >> (bit % 8);
    931	if (state)
    932		bitmap[byte_spot] |= bitmask;
    933	else
    934		bitmap[byte_spot] &= ~bitmask;
    935}
    936EXPORT_SYMBOL(netlbl_bitmap_setbit);
    937
    938/*
    939 * LSM Functions
    940 */
    941
    942/**
    943 * netlbl_enabled - Determine if the NetLabel subsystem is enabled
    944 *
    945 * Description:
    946 * The LSM can use this function to determine if it should use NetLabel
    947 * security attributes in it's enforcement mechanism.  Currently, NetLabel is
    948 * considered to be enabled when it's configuration contains a valid setup for
    949 * at least one labeled protocol (i.e. NetLabel can understand incoming
    950 * labeled packets of at least one type); otherwise NetLabel is considered to
    951 * be disabled.
    952 *
    953 */
    954int netlbl_enabled(void)
    955{
    956	/* At some point we probably want to expose this mechanism to the user
    957	 * as well so that admins can toggle NetLabel regardless of the
    958	 * configuration */
    959	return (atomic_read(&netlabel_mgmt_protocount) > 0);
    960}
    961
    962/**
    963 * netlbl_sock_setattr - Label a socket using the correct protocol
    964 * @sk: the socket to label
    965 * @family: protocol family
    966 * @secattr: the security attributes
    967 *
    968 * Description:
    969 * Attach the correct label to the given socket using the security attributes
    970 * specified in @secattr.  This function requires exclusive access to @sk,
    971 * which means it either needs to be in the process of being created or locked.
    972 * Returns zero on success, -EDESTADDRREQ if the domain is configured to use
    973 * network address selectors (can't blindly label the socket), and negative
    974 * values on all other failures.
    975 *
    976 */
    977int netlbl_sock_setattr(struct sock *sk,
    978			u16 family,
    979			const struct netlbl_lsm_secattr *secattr)
    980{
    981	int ret_val;
    982	struct netlbl_dom_map *dom_entry;
    983
    984	rcu_read_lock();
    985	dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
    986	if (dom_entry == NULL) {
    987		ret_val = -ENOENT;
    988		goto socket_setattr_return;
    989	}
    990	switch (family) {
    991	case AF_INET:
    992		switch (dom_entry->def.type) {
    993		case NETLBL_NLTYPE_ADDRSELECT:
    994			ret_val = -EDESTADDRREQ;
    995			break;
    996		case NETLBL_NLTYPE_CIPSOV4:
    997			ret_val = cipso_v4_sock_setattr(sk,
    998							dom_entry->def.cipso,
    999							secattr);
   1000			break;
   1001		case NETLBL_NLTYPE_UNLABELED:
   1002			ret_val = 0;
   1003			break;
   1004		default:
   1005			ret_val = -ENOENT;
   1006		}
   1007		break;
   1008#if IS_ENABLED(CONFIG_IPV6)
   1009	case AF_INET6:
   1010		switch (dom_entry->def.type) {
   1011		case NETLBL_NLTYPE_ADDRSELECT:
   1012			ret_val = -EDESTADDRREQ;
   1013			break;
   1014		case NETLBL_NLTYPE_CALIPSO:
   1015			ret_val = calipso_sock_setattr(sk,
   1016						       dom_entry->def.calipso,
   1017						       secattr);
   1018			break;
   1019		case NETLBL_NLTYPE_UNLABELED:
   1020			ret_val = 0;
   1021			break;
   1022		default:
   1023			ret_val = -ENOENT;
   1024		}
   1025		break;
   1026#endif /* IPv6 */
   1027	default:
   1028		ret_val = -EPROTONOSUPPORT;
   1029	}
   1030
   1031socket_setattr_return:
   1032	rcu_read_unlock();
   1033	return ret_val;
   1034}
   1035
   1036/**
   1037 * netlbl_sock_delattr - Delete all the NetLabel labels on a socket
   1038 * @sk: the socket
   1039 *
   1040 * Description:
   1041 * Remove all the NetLabel labeling from @sk.  The caller is responsible for
   1042 * ensuring that @sk is locked.
   1043 *
   1044 */
   1045void netlbl_sock_delattr(struct sock *sk)
   1046{
   1047	switch (sk->sk_family) {
   1048	case AF_INET:
   1049		cipso_v4_sock_delattr(sk);
   1050		break;
   1051#if IS_ENABLED(CONFIG_IPV6)
   1052	case AF_INET6:
   1053		calipso_sock_delattr(sk);
   1054		break;
   1055#endif /* IPv6 */
   1056	}
   1057}
   1058
   1059/**
   1060 * netlbl_sock_getattr - Determine the security attributes of a sock
   1061 * @sk: the sock
   1062 * @secattr: the security attributes
   1063 *
   1064 * Description:
   1065 * Examines the given sock to see if any NetLabel style labeling has been
   1066 * applied to the sock, if so it parses the socket label and returns the
   1067 * security attributes in @secattr.  Returns zero on success, negative values
   1068 * on failure.
   1069 *
   1070 */
   1071int netlbl_sock_getattr(struct sock *sk,
   1072			struct netlbl_lsm_secattr *secattr)
   1073{
   1074	int ret_val;
   1075
   1076	switch (sk->sk_family) {
   1077	case AF_INET:
   1078		ret_val = cipso_v4_sock_getattr(sk, secattr);
   1079		break;
   1080#if IS_ENABLED(CONFIG_IPV6)
   1081	case AF_INET6:
   1082		ret_val = calipso_sock_getattr(sk, secattr);
   1083		break;
   1084#endif /* IPv6 */
   1085	default:
   1086		ret_val = -EPROTONOSUPPORT;
   1087	}
   1088
   1089	return ret_val;
   1090}
   1091
   1092/**
   1093 * netlbl_conn_setattr - Label a connected socket using the correct protocol
   1094 * @sk: the socket to label
   1095 * @addr: the destination address
   1096 * @secattr: the security attributes
   1097 *
   1098 * Description:
   1099 * Attach the correct label to the given connected socket using the security
   1100 * attributes specified in @secattr.  The caller is responsible for ensuring
   1101 * that @sk is locked.  Returns zero on success, negative values on failure.
   1102 *
   1103 */
   1104int netlbl_conn_setattr(struct sock *sk,
   1105			struct sockaddr *addr,
   1106			const struct netlbl_lsm_secattr *secattr)
   1107{
   1108	int ret_val;
   1109	struct sockaddr_in *addr4;
   1110#if IS_ENABLED(CONFIG_IPV6)
   1111	struct sockaddr_in6 *addr6;
   1112#endif
   1113	struct netlbl_dommap_def *entry;
   1114
   1115	rcu_read_lock();
   1116	switch (addr->sa_family) {
   1117	case AF_INET:
   1118		addr4 = (struct sockaddr_in *)addr;
   1119		entry = netlbl_domhsh_getentry_af4(secattr->domain,
   1120						   addr4->sin_addr.s_addr);
   1121		if (entry == NULL) {
   1122			ret_val = -ENOENT;
   1123			goto conn_setattr_return;
   1124		}
   1125		switch (entry->type) {
   1126		case NETLBL_NLTYPE_CIPSOV4:
   1127			ret_val = cipso_v4_sock_setattr(sk,
   1128							entry->cipso, secattr);
   1129			break;
   1130		case NETLBL_NLTYPE_UNLABELED:
   1131			/* just delete the protocols we support for right now
   1132			 * but we could remove other protocols if needed */
   1133			netlbl_sock_delattr(sk);
   1134			ret_val = 0;
   1135			break;
   1136		default:
   1137			ret_val = -ENOENT;
   1138		}
   1139		break;
   1140#if IS_ENABLED(CONFIG_IPV6)
   1141	case AF_INET6:
   1142		addr6 = (struct sockaddr_in6 *)addr;
   1143		entry = netlbl_domhsh_getentry_af6(secattr->domain,
   1144						   &addr6->sin6_addr);
   1145		if (entry == NULL) {
   1146			ret_val = -ENOENT;
   1147			goto conn_setattr_return;
   1148		}
   1149		switch (entry->type) {
   1150		case NETLBL_NLTYPE_CALIPSO:
   1151			ret_val = calipso_sock_setattr(sk,
   1152						       entry->calipso, secattr);
   1153			break;
   1154		case NETLBL_NLTYPE_UNLABELED:
   1155			/* just delete the protocols we support for right now
   1156			 * but we could remove other protocols if needed */
   1157			netlbl_sock_delattr(sk);
   1158			ret_val = 0;
   1159			break;
   1160		default:
   1161			ret_val = -ENOENT;
   1162		}
   1163		break;
   1164#endif /* IPv6 */
   1165	default:
   1166		ret_val = -EPROTONOSUPPORT;
   1167	}
   1168
   1169conn_setattr_return:
   1170	rcu_read_unlock();
   1171	return ret_val;
   1172}
   1173
   1174/**
   1175 * netlbl_req_setattr - Label a request socket using the correct protocol
   1176 * @req: the request socket to label
   1177 * @secattr: the security attributes
   1178 *
   1179 * Description:
   1180 * Attach the correct label to the given socket using the security attributes
   1181 * specified in @secattr.  Returns zero on success, negative values on failure.
   1182 *
   1183 */
   1184int netlbl_req_setattr(struct request_sock *req,
   1185		       const struct netlbl_lsm_secattr *secattr)
   1186{
   1187	int ret_val;
   1188	struct netlbl_dommap_def *entry;
   1189	struct inet_request_sock *ireq = inet_rsk(req);
   1190
   1191	rcu_read_lock();
   1192	switch (req->rsk_ops->family) {
   1193	case AF_INET:
   1194		entry = netlbl_domhsh_getentry_af4(secattr->domain,
   1195						   ireq->ir_rmt_addr);
   1196		if (entry == NULL) {
   1197			ret_val = -ENOENT;
   1198			goto req_setattr_return;
   1199		}
   1200		switch (entry->type) {
   1201		case NETLBL_NLTYPE_CIPSOV4:
   1202			ret_val = cipso_v4_req_setattr(req,
   1203						       entry->cipso, secattr);
   1204			break;
   1205		case NETLBL_NLTYPE_UNLABELED:
   1206			netlbl_req_delattr(req);
   1207			ret_val = 0;
   1208			break;
   1209		default:
   1210			ret_val = -ENOENT;
   1211		}
   1212		break;
   1213#if IS_ENABLED(CONFIG_IPV6)
   1214	case AF_INET6:
   1215		entry = netlbl_domhsh_getentry_af6(secattr->domain,
   1216						   &ireq->ir_v6_rmt_addr);
   1217		if (entry == NULL) {
   1218			ret_val = -ENOENT;
   1219			goto req_setattr_return;
   1220		}
   1221		switch (entry->type) {
   1222		case NETLBL_NLTYPE_CALIPSO:
   1223			ret_val = calipso_req_setattr(req,
   1224						      entry->calipso, secattr);
   1225			break;
   1226		case NETLBL_NLTYPE_UNLABELED:
   1227			netlbl_req_delattr(req);
   1228			ret_val = 0;
   1229			break;
   1230		default:
   1231			ret_val = -ENOENT;
   1232		}
   1233		break;
   1234#endif /* IPv6 */
   1235	default:
   1236		ret_val = -EPROTONOSUPPORT;
   1237	}
   1238
   1239req_setattr_return:
   1240	rcu_read_unlock();
   1241	return ret_val;
   1242}
   1243
   1244/**
   1245* netlbl_req_delattr - Delete all the NetLabel labels on a socket
   1246* @req: the socket
   1247*
   1248* Description:
   1249* Remove all the NetLabel labeling from @req.
   1250*
   1251*/
   1252void netlbl_req_delattr(struct request_sock *req)
   1253{
   1254	switch (req->rsk_ops->family) {
   1255	case AF_INET:
   1256		cipso_v4_req_delattr(req);
   1257		break;
   1258#if IS_ENABLED(CONFIG_IPV6)
   1259	case AF_INET6:
   1260		calipso_req_delattr(req);
   1261		break;
   1262#endif /* IPv6 */
   1263	}
   1264}
   1265
   1266/**
   1267 * netlbl_skbuff_setattr - Label a packet using the correct protocol
   1268 * @skb: the packet
   1269 * @family: protocol family
   1270 * @secattr: the security attributes
   1271 *
   1272 * Description:
   1273 * Attach the correct label to the given packet using the security attributes
   1274 * specified in @secattr.  Returns zero on success, negative values on failure.
   1275 *
   1276 */
   1277int netlbl_skbuff_setattr(struct sk_buff *skb,
   1278			  u16 family,
   1279			  const struct netlbl_lsm_secattr *secattr)
   1280{
   1281	int ret_val;
   1282	struct iphdr *hdr4;
   1283#if IS_ENABLED(CONFIG_IPV6)
   1284	struct ipv6hdr *hdr6;
   1285#endif
   1286	struct netlbl_dommap_def *entry;
   1287
   1288	rcu_read_lock();
   1289	switch (family) {
   1290	case AF_INET:
   1291		hdr4 = ip_hdr(skb);
   1292		entry = netlbl_domhsh_getentry_af4(secattr->domain,
   1293						   hdr4->daddr);
   1294		if (entry == NULL) {
   1295			ret_val = -ENOENT;
   1296			goto skbuff_setattr_return;
   1297		}
   1298		switch (entry->type) {
   1299		case NETLBL_NLTYPE_CIPSOV4:
   1300			ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso,
   1301							  secattr);
   1302			break;
   1303		case NETLBL_NLTYPE_UNLABELED:
   1304			/* just delete the protocols we support for right now
   1305			 * but we could remove other protocols if needed */
   1306			ret_val = cipso_v4_skbuff_delattr(skb);
   1307			break;
   1308		default:
   1309			ret_val = -ENOENT;
   1310		}
   1311		break;
   1312#if IS_ENABLED(CONFIG_IPV6)
   1313	case AF_INET6:
   1314		hdr6 = ipv6_hdr(skb);
   1315		entry = netlbl_domhsh_getentry_af6(secattr->domain,
   1316						   &hdr6->daddr);
   1317		if (entry == NULL) {
   1318			ret_val = -ENOENT;
   1319			goto skbuff_setattr_return;
   1320		}
   1321		switch (entry->type) {
   1322		case NETLBL_NLTYPE_CALIPSO:
   1323			ret_val = calipso_skbuff_setattr(skb, entry->calipso,
   1324							 secattr);
   1325			break;
   1326		case NETLBL_NLTYPE_UNLABELED:
   1327			/* just delete the protocols we support for right now
   1328			 * but we could remove other protocols if needed */
   1329			ret_val = calipso_skbuff_delattr(skb);
   1330			break;
   1331		default:
   1332			ret_val = -ENOENT;
   1333		}
   1334		break;
   1335#endif /* IPv6 */
   1336	default:
   1337		ret_val = -EPROTONOSUPPORT;
   1338	}
   1339
   1340skbuff_setattr_return:
   1341	rcu_read_unlock();
   1342	return ret_val;
   1343}
   1344
   1345/**
   1346 * netlbl_skbuff_getattr - Determine the security attributes of a packet
   1347 * @skb: the packet
   1348 * @family: protocol family
   1349 * @secattr: the security attributes
   1350 *
   1351 * Description:
   1352 * Examines the given packet to see if a recognized form of packet labeling
   1353 * is present, if so it parses the packet label and returns the security
   1354 * attributes in @secattr.  Returns zero on success, negative values on
   1355 * failure.
   1356 *
   1357 */
   1358int netlbl_skbuff_getattr(const struct sk_buff *skb,
   1359			  u16 family,
   1360			  struct netlbl_lsm_secattr *secattr)
   1361{
   1362	unsigned char *ptr;
   1363
   1364	switch (family) {
   1365	case AF_INET:
   1366		ptr = cipso_v4_optptr(skb);
   1367		if (ptr && cipso_v4_getattr(ptr, secattr) == 0)
   1368			return 0;
   1369		break;
   1370#if IS_ENABLED(CONFIG_IPV6)
   1371	case AF_INET6:
   1372		ptr = calipso_optptr(skb);
   1373		if (ptr && calipso_getattr(ptr, secattr) == 0)
   1374			return 0;
   1375		break;
   1376#endif /* IPv6 */
   1377	}
   1378
   1379	return netlbl_unlabel_getattr(skb, family, secattr);
   1380}
   1381
   1382/**
   1383 * netlbl_skbuff_err - Handle a LSM error on a sk_buff
   1384 * @skb: the packet
   1385 * @family: the family
   1386 * @error: the error code
   1387 * @gateway: true if host is acting as a gateway, false otherwise
   1388 *
   1389 * Description:
   1390 * Deal with a LSM problem when handling the packet in @skb, typically this is
   1391 * a permission denied problem (-EACCES).  The correct action is determined
   1392 * according to the packet's labeling protocol.
   1393 *
   1394 */
   1395void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway)
   1396{
   1397	switch (family) {
   1398	case AF_INET:
   1399		if (cipso_v4_optptr(skb))
   1400			cipso_v4_error(skb, error, gateway);
   1401		break;
   1402	}
   1403}
   1404
   1405/**
   1406 * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
   1407 *
   1408 * Description:
   1409 * For all of the NetLabel protocols that support some form of label mapping
   1410 * cache, invalidate the cache.  Returns zero on success, negative values on
   1411 * error.
   1412 *
   1413 */
   1414void netlbl_cache_invalidate(void)
   1415{
   1416	cipso_v4_cache_invalidate();
   1417#if IS_ENABLED(CONFIG_IPV6)
   1418	calipso_cache_invalidate();
   1419#endif /* IPv6 */
   1420}
   1421
   1422/**
   1423 * netlbl_cache_add - Add an entry to a NetLabel protocol cache
   1424 * @skb: the packet
   1425 * @family: the family
   1426 * @secattr: the packet's security attributes
   1427 *
   1428 * Description:
   1429 * Add the LSM security attributes for the given packet to the underlying
   1430 * NetLabel protocol's label mapping cache.  Returns zero on success, negative
   1431 * values on error.
   1432 *
   1433 */
   1434int netlbl_cache_add(const struct sk_buff *skb, u16 family,
   1435		     const struct netlbl_lsm_secattr *secattr)
   1436{
   1437	unsigned char *ptr;
   1438
   1439	if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
   1440		return -ENOMSG;
   1441
   1442	switch (family) {
   1443	case AF_INET:
   1444		ptr = cipso_v4_optptr(skb);
   1445		if (ptr)
   1446			return cipso_v4_cache_add(ptr, secattr);
   1447		break;
   1448#if IS_ENABLED(CONFIG_IPV6)
   1449	case AF_INET6:
   1450		ptr = calipso_optptr(skb);
   1451		if (ptr)
   1452			return calipso_cache_add(ptr, secattr);
   1453		break;
   1454#endif /* IPv6 */
   1455	}
   1456	return -ENOMSG;
   1457}
   1458
   1459/*
   1460 * Protocol Engine Functions
   1461 */
   1462
   1463/**
   1464 * netlbl_audit_start - Start an audit message
   1465 * @type: audit message type
   1466 * @audit_info: NetLabel audit information
   1467 *
   1468 * Description:
   1469 * Start an audit message using the type specified in @type and fill the audit
   1470 * message with some fields common to all NetLabel audit messages.  This
   1471 * function should only be used by protocol engines, not LSMs.  Returns a
   1472 * pointer to the audit buffer on success, NULL on failure.
   1473 *
   1474 */
   1475struct audit_buffer *netlbl_audit_start(int type,
   1476					struct netlbl_audit *audit_info)
   1477{
   1478	return netlbl_audit_start_common(type, audit_info);
   1479}
   1480EXPORT_SYMBOL(netlbl_audit_start);
   1481
   1482/*
   1483 * Setup Functions
   1484 */
   1485
   1486/**
   1487 * netlbl_init - Initialize NetLabel
   1488 *
   1489 * Description:
   1490 * Perform the required NetLabel initialization before first use.
   1491 *
   1492 */
   1493static int __init netlbl_init(void)
   1494{
   1495	int ret_val;
   1496
   1497	printk(KERN_INFO "NetLabel: Initializing\n");
   1498	printk(KERN_INFO "NetLabel:  domain hash size = %u\n",
   1499	       (1 << NETLBL_DOMHSH_BITSIZE));
   1500	printk(KERN_INFO "NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO\n");
   1501
   1502	ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
   1503	if (ret_val != 0)
   1504		goto init_failure;
   1505
   1506	ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
   1507	if (ret_val != 0)
   1508		goto init_failure;
   1509
   1510	ret_val = netlbl_netlink_init();
   1511	if (ret_val != 0)
   1512		goto init_failure;
   1513
   1514	ret_val = netlbl_unlabel_defconf();
   1515	if (ret_val != 0)
   1516		goto init_failure;
   1517	printk(KERN_INFO "NetLabel:  unlabeled traffic allowed by default\n");
   1518
   1519	return 0;
   1520
   1521init_failure:
   1522	panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
   1523}
   1524
   1525subsys_initcall(netlbl_init);