root/net/netlabel/netlabel_cipso_v4.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. netlbl_cipsov4_add_common
  2. netlbl_cipsov4_add_std
  3. netlbl_cipsov4_add_pass
  4. netlbl_cipsov4_add_local
  5. netlbl_cipsov4_add
  6. netlbl_cipsov4_list
  7. netlbl_cipsov4_listall_cb
  8. netlbl_cipsov4_listall
  9. netlbl_cipsov4_remove_cb
  10. netlbl_cipsov4_remove
  11. netlbl_cipsov4_genl_init

   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() */
  35 struct 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() */
  42 struct netlbl_domhsh_walk_arg {
  43         struct netlbl_audit *audit_info;
  44         u32 doi;
  45 };
  46 
  47 /* NetLabel Generic NETLINK CIPSOv4 family */
  48 static struct genl_family netlbl_cipsov4_gnl_family;
  49 /* NetLabel Netlink attribute policy */
  50 static 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  */
  79 static 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  */
 121 static 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                 ret_val = -ENOMEM;
 148                 goto add_std_failure;
 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);
 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);
 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);
 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);
 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 
 310 add_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  */
 326 static 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 
 349 add_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  */
 365 static 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 
 388 add_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  */
 403 static 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(skb, &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  */
 448 static 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 
 465 list_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         rcu_read_unlock();
 579 
 580         genlmsg_end(ans_skb, data);
 581         return genlmsg_reply(ans_skb, info);
 582 
 583 list_retry:
 584         /* XXX - this limit is a guesstimate */
 585         if (nlsze_mult < 4) {
 586                 rcu_read_unlock();
 587                 kfree_skb(ans_skb);
 588                 nlsze_mult *= 2;
 589                 goto list_start;
 590         }
 591 list_failure_lock:
 592         rcu_read_unlock();
 593 list_failure:
 594         kfree_skb(ans_skb);
 595         return ret_val;
 596 }
 597 
 598 /**
 599  * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
 600  * @doi_def: the CIPSOv4 DOI definition
 601  * @arg: the netlbl_cipsov4_doiwalk_arg structure
 602  *
 603  * Description:
 604  * This function is designed to be used as a callback to the
 605  * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
 606  * message.  Returns the size of the message on success, negative values on
 607  * failure.
 608  *
 609  */
 610 static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
 611 {
 612         int ret_val = -ENOMEM;
 613         struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
 614         void *data;
 615 
 616         data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
 617                            cb_arg->seq, &netlbl_cipsov4_gnl_family,
 618                            NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
 619         if (data == NULL)
 620                 goto listall_cb_failure;
 621 
 622         ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
 623         if (ret_val != 0)
 624                 goto listall_cb_failure;
 625         ret_val = nla_put_u32(cb_arg->skb,
 626                               NLBL_CIPSOV4_A_MTYPE,
 627                               doi_def->type);
 628         if (ret_val != 0)
 629                 goto listall_cb_failure;
 630 
 631         genlmsg_end(cb_arg->skb, data);
 632         return 0;
 633 
 634 listall_cb_failure:
 635         genlmsg_cancel(cb_arg->skb, data);
 636         return ret_val;
 637 }
 638 
 639 /**
 640  * netlbl_cipsov4_listall - Handle a LISTALL message
 641  * @skb: the NETLINK buffer
 642  * @cb: the NETLINK callback
 643  *
 644  * Description:
 645  * Process a user generated LISTALL message and respond accordingly.  Returns
 646  * zero on success and negative values on error.
 647  *
 648  */
 649 static int netlbl_cipsov4_listall(struct sk_buff *skb,
 650                                   struct netlink_callback *cb)
 651 {
 652         struct netlbl_cipsov4_doiwalk_arg cb_arg;
 653         u32 doi_skip = cb->args[0];
 654 
 655         cb_arg.nl_cb = cb;
 656         cb_arg.skb = skb;
 657         cb_arg.seq = cb->nlh->nlmsg_seq;
 658 
 659         cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
 660 
 661         cb->args[0] = doi_skip;
 662         return skb->len;
 663 }
 664 
 665 /**
 666  * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
 667  * @entry: LSM domain mapping entry
 668  * @arg: the netlbl_domhsh_walk_arg structure
 669  *
 670  * Description:
 671  * This function is intended for use by netlbl_cipsov4_remove() as the callback
 672  * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
 673  * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
 674  * success, negative values on failure.
 675  *
 676  */
 677 static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
 678 {
 679         struct netlbl_domhsh_walk_arg *cb_arg = arg;
 680 
 681         if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
 682             entry->def.cipso->doi == cb_arg->doi)
 683                 return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
 684 
 685         return 0;
 686 }
 687 
 688 /**
 689  * netlbl_cipsov4_remove - Handle a REMOVE message
 690  * @skb: the NETLINK buffer
 691  * @info: the Generic NETLINK info block
 692  *
 693  * Description:
 694  * Process a user generated REMOVE message and respond accordingly.  Returns
 695  * zero on success, negative values on failure.
 696  *
 697  */
 698 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
 699 {
 700         int ret_val = -EINVAL;
 701         struct netlbl_domhsh_walk_arg cb_arg;
 702         struct netlbl_audit audit_info;
 703         u32 skip_bkt = 0;
 704         u32 skip_chain = 0;
 705 
 706         if (!info->attrs[NLBL_CIPSOV4_A_DOI])
 707                 return -EINVAL;
 708 
 709         netlbl_netlink_auditinfo(skb, &audit_info);
 710         cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
 711         cb_arg.audit_info = &audit_info;
 712         ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
 713                                      netlbl_cipsov4_remove_cb, &cb_arg);
 714         if (ret_val == 0 || ret_val == -ENOENT) {
 715                 ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
 716                 if (ret_val == 0)
 717                         atomic_dec(&netlabel_mgmt_protocount);
 718         }
 719 
 720         return ret_val;
 721 }
 722 
 723 /*
 724  * NetLabel Generic NETLINK Command Definitions
 725  */
 726 
 727 static const struct genl_ops netlbl_cipsov4_ops[] = {
 728         {
 729         .cmd = NLBL_CIPSOV4_C_ADD,
 730         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 731         .flags = GENL_ADMIN_PERM,
 732         .doit = netlbl_cipsov4_add,
 733         .dumpit = NULL,
 734         },
 735         {
 736         .cmd = NLBL_CIPSOV4_C_REMOVE,
 737         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 738         .flags = GENL_ADMIN_PERM,
 739         .doit = netlbl_cipsov4_remove,
 740         .dumpit = NULL,
 741         },
 742         {
 743         .cmd = NLBL_CIPSOV4_C_LIST,
 744         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 745         .flags = 0,
 746         .doit = netlbl_cipsov4_list,
 747         .dumpit = NULL,
 748         },
 749         {
 750         .cmd = NLBL_CIPSOV4_C_LISTALL,
 751         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 752         .flags = 0,
 753         .doit = NULL,
 754         .dumpit = netlbl_cipsov4_listall,
 755         },
 756 };
 757 
 758 static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
 759         .hdrsize = 0,
 760         .name = NETLBL_NLTYPE_CIPSOV4_NAME,
 761         .version = NETLBL_PROTO_VERSION,
 762         .maxattr = NLBL_CIPSOV4_A_MAX,
 763         .policy = netlbl_cipsov4_genl_policy,
 764         .module = THIS_MODULE,
 765         .ops = netlbl_cipsov4_ops,
 766         .n_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
 767 };
 768 
 769 /*
 770  * NetLabel Generic NETLINK Protocol Functions
 771  */
 772 
 773 /**
 774  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
 775  *
 776  * Description:
 777  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
 778  * mechanism.  Returns zero on success, negative values on failure.
 779  *
 780  */
 781 int __init netlbl_cipsov4_genl_init(void)
 782 {
 783         return genl_register_family(&netlbl_cipsov4_gnl_family);
 784 }

/* [<][>][^][v][top][bottom][index][help] */