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_cipso_v4.c (21614B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NetLabel CIPSO/IPv4 Support
      4 *
      5 * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
      6 * NetLabel system manages static and dynamic label mappings for network
      7 * protocols such 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
     14 */
     15
     16#include <linux/types.h>
     17#include <linux/socket.h>
     18#include <linux/string.h>
     19#include <linux/skbuff.h>
     20#include <linux/audit.h>
     21#include <linux/slab.h>
     22#include <net/sock.h>
     23#include <net/netlink.h>
     24#include <net/genetlink.h>
     25#include <net/netlabel.h>
     26#include <net/cipso_ipv4.h>
     27#include <linux/atomic.h>
     28
     29#include "netlabel_user.h"
     30#include "netlabel_cipso_v4.h"
     31#include "netlabel_mgmt.h"
     32#include "netlabel_domainhash.h"
     33
     34/* Argument struct for cipso_v4_doi_walk() */
     35struct netlbl_cipsov4_doiwalk_arg {
     36	struct netlink_callback *nl_cb;
     37	struct sk_buff *skb;
     38	u32 seq;
     39};
     40
     41/* Argument struct for netlbl_domhsh_walk() */
     42struct netlbl_domhsh_walk_arg {
     43	struct netlbl_audit *audit_info;
     44	u32 doi;
     45};
     46
     47/* NetLabel Generic NETLINK CIPSOv4 family */
     48static struct genl_family netlbl_cipsov4_gnl_family;
     49/* NetLabel Netlink attribute policy */
     50static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
     51	[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
     52	[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
     53	[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
     54	[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
     55	[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
     56	[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
     57	[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
     58	[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
     59	[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
     60	[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
     61	[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
     62	[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
     63};
     64
     65/*
     66 * Helper Functions
     67 */
     68
     69/**
     70 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
     71 * @info: the Generic NETLINK info block
     72 * @doi_def: the CIPSO V4 DOI definition
     73 *
     74 * Description:
     75 * Parse the common sections of a ADD message and fill in the related values
     76 * in @doi_def.  Returns zero on success, negative values on failure.
     77 *
     78 */
     79static int netlbl_cipsov4_add_common(struct genl_info *info,
     80				     struct cipso_v4_doi *doi_def)
     81{
     82	struct nlattr *nla;
     83	int nla_rem;
     84	u32 iter = 0;
     85
     86	doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
     87
     88	if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_TAGLST],
     89					   NLBL_CIPSOV4_A_MAX,
     90					   netlbl_cipsov4_genl_policy,
     91					   NULL) != 0)
     92		return -EINVAL;
     93
     94	nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
     95		if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
     96			if (iter >= CIPSO_V4_TAG_MAXCNT)
     97				return -EINVAL;
     98			doi_def->tags[iter++] = nla_get_u8(nla);
     99		}
    100	while (iter < CIPSO_V4_TAG_MAXCNT)
    101		doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
    102
    103	return 0;
    104}
    105
    106/*
    107 * NetLabel Command Handlers
    108 */
    109
    110/**
    111 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
    112 * @info: the Generic NETLINK info block
    113 * @audit_info: NetLabel audit information
    114 *
    115 * Description:
    116 * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
    117 * message and add it to the CIPSO V4 engine.  Return zero on success and
    118 * non-zero on error.
    119 *
    120 */
    121static int netlbl_cipsov4_add_std(struct genl_info *info,
    122				  struct netlbl_audit *audit_info)
    123{
    124	int ret_val = -EINVAL;
    125	struct cipso_v4_doi *doi_def = NULL;
    126	struct nlattr *nla_a;
    127	struct nlattr *nla_b;
    128	int nla_a_rem;
    129	int nla_b_rem;
    130	u32 iter;
    131
    132	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
    133	    !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
    134		return -EINVAL;
    135
    136	if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
    137					   NLBL_CIPSOV4_A_MAX,
    138					   netlbl_cipsov4_genl_policy,
    139					   NULL) != 0)
    140		return -EINVAL;
    141
    142	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
    143	if (doi_def == NULL)
    144		return -ENOMEM;
    145	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
    146	if (doi_def->map.std == NULL) {
    147		kfree(doi_def);
    148		return -ENOMEM;
    149	}
    150	doi_def->type = CIPSO_V4_MAP_TRANS;
    151
    152	ret_val = netlbl_cipsov4_add_common(info, doi_def);
    153	if (ret_val != 0)
    154		goto add_std_failure;
    155	ret_val = -EINVAL;
    156
    157	nla_for_each_nested(nla_a,
    158			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
    159			    nla_a_rem)
    160		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
    161			if (nla_validate_nested_deprecated(nla_a,
    162							   NLBL_CIPSOV4_A_MAX,
    163							   netlbl_cipsov4_genl_policy,
    164							   NULL) != 0)
    165				goto add_std_failure;
    166			nla_for_each_nested(nla_b, nla_a, nla_b_rem)
    167				switch (nla_type(nla_b)) {
    168				case NLBL_CIPSOV4_A_MLSLVLLOC:
    169					if (nla_get_u32(nla_b) >
    170					    CIPSO_V4_MAX_LOC_LVLS)
    171						goto add_std_failure;
    172					if (nla_get_u32(nla_b) >=
    173					    doi_def->map.std->lvl.local_size)
    174					     doi_def->map.std->lvl.local_size =
    175						     nla_get_u32(nla_b) + 1;
    176					break;
    177				case NLBL_CIPSOV4_A_MLSLVLREM:
    178					if (nla_get_u32(nla_b) >
    179					    CIPSO_V4_MAX_REM_LVLS)
    180						goto add_std_failure;
    181					if (nla_get_u32(nla_b) >=
    182					    doi_def->map.std->lvl.cipso_size)
    183					     doi_def->map.std->lvl.cipso_size =
    184						     nla_get_u32(nla_b) + 1;
    185					break;
    186				}
    187		}
    188	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
    189					      sizeof(u32),
    190					      GFP_KERNEL | __GFP_NOWARN);
    191	if (doi_def->map.std->lvl.local == NULL) {
    192		ret_val = -ENOMEM;
    193		goto add_std_failure;
    194	}
    195	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
    196					      sizeof(u32),
    197					      GFP_KERNEL | __GFP_NOWARN);
    198	if (doi_def->map.std->lvl.cipso == NULL) {
    199		ret_val = -ENOMEM;
    200		goto add_std_failure;
    201	}
    202	for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
    203		doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
    204	for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
    205		doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
    206	nla_for_each_nested(nla_a,
    207			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
    208			    nla_a_rem)
    209		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
    210			struct nlattr *lvl_loc;
    211			struct nlattr *lvl_rem;
    212
    213			lvl_loc = nla_find_nested(nla_a,
    214						  NLBL_CIPSOV4_A_MLSLVLLOC);
    215			lvl_rem = nla_find_nested(nla_a,
    216						  NLBL_CIPSOV4_A_MLSLVLREM);
    217			if (lvl_loc == NULL || lvl_rem == NULL)
    218				goto add_std_failure;
    219			doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
    220				nla_get_u32(lvl_rem);
    221			doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
    222				nla_get_u32(lvl_loc);
    223		}
    224
    225	if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
    226		if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
    227						   NLBL_CIPSOV4_A_MAX,
    228						   netlbl_cipsov4_genl_policy,
    229						   NULL) != 0)
    230			goto add_std_failure;
    231
    232		nla_for_each_nested(nla_a,
    233				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
    234				    nla_a_rem)
    235			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
    236				if (nla_validate_nested_deprecated(nla_a,
    237								   NLBL_CIPSOV4_A_MAX,
    238								   netlbl_cipsov4_genl_policy,
    239								   NULL) != 0)
    240					goto add_std_failure;
    241				nla_for_each_nested(nla_b, nla_a, nla_b_rem)
    242					switch (nla_type(nla_b)) {
    243					case NLBL_CIPSOV4_A_MLSCATLOC:
    244						if (nla_get_u32(nla_b) >
    245						    CIPSO_V4_MAX_LOC_CATS)
    246							goto add_std_failure;
    247						if (nla_get_u32(nla_b) >=
    248					      doi_def->map.std->cat.local_size)
    249					     doi_def->map.std->cat.local_size =
    250						     nla_get_u32(nla_b) + 1;
    251						break;
    252					case NLBL_CIPSOV4_A_MLSCATREM:
    253						if (nla_get_u32(nla_b) >
    254						    CIPSO_V4_MAX_REM_CATS)
    255							goto add_std_failure;
    256						if (nla_get_u32(nla_b) >=
    257					      doi_def->map.std->cat.cipso_size)
    258					     doi_def->map.std->cat.cipso_size =
    259						     nla_get_u32(nla_b) + 1;
    260						break;
    261					}
    262			}
    263		doi_def->map.std->cat.local = kcalloc(
    264					      doi_def->map.std->cat.local_size,
    265					      sizeof(u32),
    266					      GFP_KERNEL | __GFP_NOWARN);
    267		if (doi_def->map.std->cat.local == NULL) {
    268			ret_val = -ENOMEM;
    269			goto add_std_failure;
    270		}
    271		doi_def->map.std->cat.cipso = kcalloc(
    272					      doi_def->map.std->cat.cipso_size,
    273					      sizeof(u32),
    274					      GFP_KERNEL | __GFP_NOWARN);
    275		if (doi_def->map.std->cat.cipso == NULL) {
    276			ret_val = -ENOMEM;
    277			goto add_std_failure;
    278		}
    279		for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
    280			doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
    281		for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
    282			doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
    283		nla_for_each_nested(nla_a,
    284				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
    285				    nla_a_rem)
    286			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
    287				struct nlattr *cat_loc;
    288				struct nlattr *cat_rem;
    289
    290				cat_loc = nla_find_nested(nla_a,
    291						     NLBL_CIPSOV4_A_MLSCATLOC);
    292				cat_rem = nla_find_nested(nla_a,
    293						     NLBL_CIPSOV4_A_MLSCATREM);
    294				if (cat_loc == NULL || cat_rem == NULL)
    295					goto add_std_failure;
    296				doi_def->map.std->cat.local[
    297							nla_get_u32(cat_loc)] =
    298					nla_get_u32(cat_rem);
    299				doi_def->map.std->cat.cipso[
    300							nla_get_u32(cat_rem)] =
    301					nla_get_u32(cat_loc);
    302			}
    303	}
    304
    305	ret_val = cipso_v4_doi_add(doi_def, audit_info);
    306	if (ret_val != 0)
    307		goto add_std_failure;
    308	return 0;
    309
    310add_std_failure:
    311	cipso_v4_doi_free(doi_def);
    312	return ret_val;
    313}
    314
    315/**
    316 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
    317 * @info: the Generic NETLINK info block
    318 * @audit_info: NetLabel audit information
    319 *
    320 * Description:
    321 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
    322 * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
    323 * error.
    324 *
    325 */
    326static int netlbl_cipsov4_add_pass(struct genl_info *info,
    327				   struct netlbl_audit *audit_info)
    328{
    329	int ret_val;
    330	struct cipso_v4_doi *doi_def = NULL;
    331
    332	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
    333		return -EINVAL;
    334
    335	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
    336	if (doi_def == NULL)
    337		return -ENOMEM;
    338	doi_def->type = CIPSO_V4_MAP_PASS;
    339
    340	ret_val = netlbl_cipsov4_add_common(info, doi_def);
    341	if (ret_val != 0)
    342		goto add_pass_failure;
    343
    344	ret_val = cipso_v4_doi_add(doi_def, audit_info);
    345	if (ret_val != 0)
    346		goto add_pass_failure;
    347	return 0;
    348
    349add_pass_failure:
    350	cipso_v4_doi_free(doi_def);
    351	return ret_val;
    352}
    353
    354/**
    355 * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
    356 * @info: the Generic NETLINK info block
    357 * @audit_info: NetLabel audit information
    358 *
    359 * Description:
    360 * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
    361 * message and add it to the CIPSO V4 engine.  Return zero on success and
    362 * non-zero on error.
    363 *
    364 */
    365static int netlbl_cipsov4_add_local(struct genl_info *info,
    366				    struct netlbl_audit *audit_info)
    367{
    368	int ret_val;
    369	struct cipso_v4_doi *doi_def = NULL;
    370
    371	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
    372		return -EINVAL;
    373
    374	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
    375	if (doi_def == NULL)
    376		return -ENOMEM;
    377	doi_def->type = CIPSO_V4_MAP_LOCAL;
    378
    379	ret_val = netlbl_cipsov4_add_common(info, doi_def);
    380	if (ret_val != 0)
    381		goto add_local_failure;
    382
    383	ret_val = cipso_v4_doi_add(doi_def, audit_info);
    384	if (ret_val != 0)
    385		goto add_local_failure;
    386	return 0;
    387
    388add_local_failure:
    389	cipso_v4_doi_free(doi_def);
    390	return ret_val;
    391}
    392
    393/**
    394 * netlbl_cipsov4_add - Handle an ADD message
    395 * @skb: the NETLINK buffer
    396 * @info: the Generic NETLINK info block
    397 *
    398 * Description:
    399 * Create a new DOI definition based on the given ADD message and add it to the
    400 * CIPSO V4 engine.  Returns zero on success, negative values on failure.
    401 *
    402 */
    403static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
    404
    405{
    406	int ret_val = -EINVAL;
    407	struct netlbl_audit audit_info;
    408
    409	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
    410	    !info->attrs[NLBL_CIPSOV4_A_MTYPE])
    411		return -EINVAL;
    412
    413	netlbl_netlink_auditinfo(&audit_info);
    414	switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
    415	case CIPSO_V4_MAP_TRANS:
    416		ret_val = netlbl_cipsov4_add_std(info, &audit_info);
    417		break;
    418	case CIPSO_V4_MAP_PASS:
    419		ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
    420		break;
    421	case CIPSO_V4_MAP_LOCAL:
    422		ret_val = netlbl_cipsov4_add_local(info, &audit_info);
    423		break;
    424	}
    425	if (ret_val == 0)
    426		atomic_inc(&netlabel_mgmt_protocount);
    427
    428	return ret_val;
    429}
    430
    431/**
    432 * netlbl_cipsov4_list - Handle a LIST message
    433 * @skb: the NETLINK buffer
    434 * @info: the Generic NETLINK info block
    435 *
    436 * Description:
    437 * Process a user generated LIST message and respond accordingly.  While the
    438 * response message generated by the kernel is straightforward, determining
    439 * before hand the size of the buffer to allocate is not (we have to generate
    440 * the message to know the size).  In order to keep this function sane what we
    441 * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
    442 * that size, if we fail then we restart with a larger buffer and try again.
    443 * We continue in this manner until we hit a limit of failed attempts then we
    444 * give up and just send an error message.  Returns zero on success and
    445 * negative values on error.
    446 *
    447 */
    448static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
    449{
    450	int ret_val;
    451	struct sk_buff *ans_skb = NULL;
    452	u32 nlsze_mult = 1;
    453	void *data;
    454	u32 doi;
    455	struct nlattr *nla_a;
    456	struct nlattr *nla_b;
    457	struct cipso_v4_doi *doi_def;
    458	u32 iter;
    459
    460	if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
    461		ret_val = -EINVAL;
    462		goto list_failure;
    463	}
    464
    465list_start:
    466	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
    467	if (ans_skb == NULL) {
    468		ret_val = -ENOMEM;
    469		goto list_failure;
    470	}
    471	data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
    472				 0, NLBL_CIPSOV4_C_LIST);
    473	if (data == NULL) {
    474		ret_val = -ENOMEM;
    475		goto list_failure;
    476	}
    477
    478	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
    479
    480	rcu_read_lock();
    481	doi_def = cipso_v4_doi_getdef(doi);
    482	if (doi_def == NULL) {
    483		ret_val = -EINVAL;
    484		goto list_failure_lock;
    485	}
    486
    487	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
    488	if (ret_val != 0)
    489		goto list_failure_lock;
    490
    491	nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
    492	if (nla_a == NULL) {
    493		ret_val = -ENOMEM;
    494		goto list_failure_lock;
    495	}
    496	for (iter = 0;
    497	     iter < CIPSO_V4_TAG_MAXCNT &&
    498	       doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
    499	     iter++) {
    500		ret_val = nla_put_u8(ans_skb,
    501				     NLBL_CIPSOV4_A_TAG,
    502				     doi_def->tags[iter]);
    503		if (ret_val != 0)
    504			goto list_failure_lock;
    505	}
    506	nla_nest_end(ans_skb, nla_a);
    507
    508	switch (doi_def->type) {
    509	case CIPSO_V4_MAP_TRANS:
    510		nla_a = nla_nest_start_noflag(ans_skb,
    511					      NLBL_CIPSOV4_A_MLSLVLLST);
    512		if (nla_a == NULL) {
    513			ret_val = -ENOMEM;
    514			goto list_failure_lock;
    515		}
    516		for (iter = 0;
    517		     iter < doi_def->map.std->lvl.local_size;
    518		     iter++) {
    519			if (doi_def->map.std->lvl.local[iter] ==
    520			    CIPSO_V4_INV_LVL)
    521				continue;
    522
    523			nla_b = nla_nest_start_noflag(ans_skb,
    524						      NLBL_CIPSOV4_A_MLSLVL);
    525			if (nla_b == NULL) {
    526				ret_val = -ENOMEM;
    527				goto list_retry;
    528			}
    529			ret_val = nla_put_u32(ans_skb,
    530					      NLBL_CIPSOV4_A_MLSLVLLOC,
    531					      iter);
    532			if (ret_val != 0)
    533				goto list_retry;
    534			ret_val = nla_put_u32(ans_skb,
    535					    NLBL_CIPSOV4_A_MLSLVLREM,
    536					    doi_def->map.std->lvl.local[iter]);
    537			if (ret_val != 0)
    538				goto list_retry;
    539			nla_nest_end(ans_skb, nla_b);
    540		}
    541		nla_nest_end(ans_skb, nla_a);
    542
    543		nla_a = nla_nest_start_noflag(ans_skb,
    544					      NLBL_CIPSOV4_A_MLSCATLST);
    545		if (nla_a == NULL) {
    546			ret_val = -ENOMEM;
    547			goto list_retry;
    548		}
    549		for (iter = 0;
    550		     iter < doi_def->map.std->cat.local_size;
    551		     iter++) {
    552			if (doi_def->map.std->cat.local[iter] ==
    553			    CIPSO_V4_INV_CAT)
    554				continue;
    555
    556			nla_b = nla_nest_start_noflag(ans_skb,
    557						      NLBL_CIPSOV4_A_MLSCAT);
    558			if (nla_b == NULL) {
    559				ret_val = -ENOMEM;
    560				goto list_retry;
    561			}
    562			ret_val = nla_put_u32(ans_skb,
    563					      NLBL_CIPSOV4_A_MLSCATLOC,
    564					      iter);
    565			if (ret_val != 0)
    566				goto list_retry;
    567			ret_val = nla_put_u32(ans_skb,
    568					    NLBL_CIPSOV4_A_MLSCATREM,
    569					    doi_def->map.std->cat.local[iter]);
    570			if (ret_val != 0)
    571				goto list_retry;
    572			nla_nest_end(ans_skb, nla_b);
    573		}
    574		nla_nest_end(ans_skb, nla_a);
    575
    576		break;
    577	}
    578	cipso_v4_doi_putdef(doi_def);
    579	rcu_read_unlock();
    580
    581	genlmsg_end(ans_skb, data);
    582	return genlmsg_reply(ans_skb, info);
    583
    584list_retry:
    585	/* XXX - this limit is a guesstimate */
    586	if (nlsze_mult < 4) {
    587		cipso_v4_doi_putdef(doi_def);
    588		rcu_read_unlock();
    589		kfree_skb(ans_skb);
    590		nlsze_mult *= 2;
    591		goto list_start;
    592	}
    593list_failure_lock:
    594	cipso_v4_doi_putdef(doi_def);
    595	rcu_read_unlock();
    596list_failure:
    597	kfree_skb(ans_skb);
    598	return ret_val;
    599}
    600
    601/**
    602 * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
    603 * @doi_def: the CIPSOv4 DOI definition
    604 * @arg: the netlbl_cipsov4_doiwalk_arg structure
    605 *
    606 * Description:
    607 * This function is designed to be used as a callback to the
    608 * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
    609 * message.  Returns the size of the message on success, negative values on
    610 * failure.
    611 *
    612 */
    613static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
    614{
    615	int ret_val = -ENOMEM;
    616	struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
    617	void *data;
    618
    619	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
    620			   cb_arg->seq, &netlbl_cipsov4_gnl_family,
    621			   NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
    622	if (data == NULL)
    623		goto listall_cb_failure;
    624
    625	ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
    626	if (ret_val != 0)
    627		goto listall_cb_failure;
    628	ret_val = nla_put_u32(cb_arg->skb,
    629			      NLBL_CIPSOV4_A_MTYPE,
    630			      doi_def->type);
    631	if (ret_val != 0)
    632		goto listall_cb_failure;
    633
    634	genlmsg_end(cb_arg->skb, data);
    635	return 0;
    636
    637listall_cb_failure:
    638	genlmsg_cancel(cb_arg->skb, data);
    639	return ret_val;
    640}
    641
    642/**
    643 * netlbl_cipsov4_listall - Handle a LISTALL message
    644 * @skb: the NETLINK buffer
    645 * @cb: the NETLINK callback
    646 *
    647 * Description:
    648 * Process a user generated LISTALL message and respond accordingly.  Returns
    649 * zero on success and negative values on error.
    650 *
    651 */
    652static int netlbl_cipsov4_listall(struct sk_buff *skb,
    653				  struct netlink_callback *cb)
    654{
    655	struct netlbl_cipsov4_doiwalk_arg cb_arg;
    656	u32 doi_skip = cb->args[0];
    657
    658	cb_arg.nl_cb = cb;
    659	cb_arg.skb = skb;
    660	cb_arg.seq = cb->nlh->nlmsg_seq;
    661
    662	cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
    663
    664	cb->args[0] = doi_skip;
    665	return skb->len;
    666}
    667
    668/**
    669 * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
    670 * @entry: LSM domain mapping entry
    671 * @arg: the netlbl_domhsh_walk_arg structure
    672 *
    673 * Description:
    674 * This function is intended for use by netlbl_cipsov4_remove() as the callback
    675 * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
    676 * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
    677 * success, negative values on failure.
    678 *
    679 */
    680static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
    681{
    682	struct netlbl_domhsh_walk_arg *cb_arg = arg;
    683
    684	if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
    685	    entry->def.cipso->doi == cb_arg->doi)
    686		return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
    687
    688	return 0;
    689}
    690
    691/**
    692 * netlbl_cipsov4_remove - Handle a REMOVE message
    693 * @skb: the NETLINK buffer
    694 * @info: the Generic NETLINK info block
    695 *
    696 * Description:
    697 * Process a user generated REMOVE message and respond accordingly.  Returns
    698 * zero on success, negative values on failure.
    699 *
    700 */
    701static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
    702{
    703	int ret_val = -EINVAL;
    704	struct netlbl_domhsh_walk_arg cb_arg;
    705	struct netlbl_audit audit_info;
    706	u32 skip_bkt = 0;
    707	u32 skip_chain = 0;
    708
    709	if (!info->attrs[NLBL_CIPSOV4_A_DOI])
    710		return -EINVAL;
    711
    712	netlbl_netlink_auditinfo(&audit_info);
    713	cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
    714	cb_arg.audit_info = &audit_info;
    715	ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
    716				     netlbl_cipsov4_remove_cb, &cb_arg);
    717	if (ret_val == 0 || ret_val == -ENOENT) {
    718		ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
    719		if (ret_val == 0)
    720			atomic_dec(&netlabel_mgmt_protocount);
    721	}
    722
    723	return ret_val;
    724}
    725
    726/*
    727 * NetLabel Generic NETLINK Command Definitions
    728 */
    729
    730static const struct genl_small_ops netlbl_cipsov4_ops[] = {
    731	{
    732	.cmd = NLBL_CIPSOV4_C_ADD,
    733	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
    734	.flags = GENL_ADMIN_PERM,
    735	.doit = netlbl_cipsov4_add,
    736	.dumpit = NULL,
    737	},
    738	{
    739	.cmd = NLBL_CIPSOV4_C_REMOVE,
    740	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
    741	.flags = GENL_ADMIN_PERM,
    742	.doit = netlbl_cipsov4_remove,
    743	.dumpit = NULL,
    744	},
    745	{
    746	.cmd = NLBL_CIPSOV4_C_LIST,
    747	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
    748	.flags = 0,
    749	.doit = netlbl_cipsov4_list,
    750	.dumpit = NULL,
    751	},
    752	{
    753	.cmd = NLBL_CIPSOV4_C_LISTALL,
    754	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
    755	.flags = 0,
    756	.doit = NULL,
    757	.dumpit = netlbl_cipsov4_listall,
    758	},
    759};
    760
    761static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
    762	.hdrsize = 0,
    763	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
    764	.version = NETLBL_PROTO_VERSION,
    765	.maxattr = NLBL_CIPSOV4_A_MAX,
    766	.policy = netlbl_cipsov4_genl_policy,
    767	.module = THIS_MODULE,
    768	.small_ops = netlbl_cipsov4_ops,
    769	.n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
    770};
    771
    772/*
    773 * NetLabel Generic NETLINK Protocol Functions
    774 */
    775
    776/**
    777 * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
    778 *
    779 * Description:
    780 * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
    781 * mechanism.  Returns zero on success, negative values on failure.
    782 *
    783 */
    784int __init netlbl_cipsov4_genl_init(void)
    785{
    786	return genl_register_family(&netlbl_cipsov4_gnl_family);
    787}