root/net/netlabel/netlabel_mgmt.c

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

DEFINITIONS

This source file includes following definitions.
  1. netlbl_mgmt_add_common
  2. netlbl_mgmt_listentry
  3. netlbl_mgmt_add
  4. netlbl_mgmt_remove
  5. netlbl_mgmt_listall_cb
  6. netlbl_mgmt_listall
  7. netlbl_mgmt_adddef
  8. netlbl_mgmt_removedef
  9. netlbl_mgmt_listdef
  10. netlbl_mgmt_protocols_cb
  11. netlbl_mgmt_protocols
  12. netlbl_mgmt_version
  13. netlbl_mgmt_genl_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * NetLabel Management Support
   4  *
   5  * This file defines the management 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, 2008
  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/in.h>
  21 #include <linux/in6.h>
  22 #include <linux/slab.h>
  23 #include <net/sock.h>
  24 #include <net/netlink.h>
  25 #include <net/genetlink.h>
  26 #include <net/ip.h>
  27 #include <net/ipv6.h>
  28 #include <net/netlabel.h>
  29 #include <net/cipso_ipv4.h>
  30 #include <net/calipso.h>
  31 #include <linux/atomic.h>
  32 
  33 #include "netlabel_calipso.h"
  34 #include "netlabel_domainhash.h"
  35 #include "netlabel_user.h"
  36 #include "netlabel_mgmt.h"
  37 
  38 /* NetLabel configured protocol counter */
  39 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
  40 
  41 /* Argument struct for netlbl_domhsh_walk() */
  42 struct netlbl_domhsh_walk_arg {
  43         struct netlink_callback *nl_cb;
  44         struct sk_buff *skb;
  45         u32 seq;
  46 };
  47 
  48 /* NetLabel Generic NETLINK CIPSOv4 family */
  49 static struct genl_family netlbl_mgmt_gnl_family;
  50 
  51 /* NetLabel Netlink attribute policy */
  52 static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
  53         [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
  54         [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
  55         [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
  56         [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
  57         [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
  58         [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
  59 };
  60 
  61 /*
  62  * Helper Functions
  63  */
  64 
  65 /**
  66  * netlbl_mgmt_add - Handle an ADD message
  67  * @info: the Generic NETLINK info block
  68  * @audit_info: NetLabel audit information
  69  *
  70  * Description:
  71  * Helper function for the ADD and ADDDEF messages to add the domain mappings
  72  * from the message to the hash table.  See netlabel.h for a description of the
  73  * message format.  Returns zero on success, negative values on failure.
  74  *
  75  */
  76 static int netlbl_mgmt_add_common(struct genl_info *info,
  77                                   struct netlbl_audit *audit_info)
  78 {
  79         int ret_val = -EINVAL;
  80         struct netlbl_domaddr_map *addrmap = NULL;
  81         struct cipso_v4_doi *cipsov4 = NULL;
  82 #if IS_ENABLED(CONFIG_IPV6)
  83         struct calipso_doi *calipso = NULL;
  84 #endif
  85         u32 tmp_val;
  86         struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  87 
  88         if (!entry)
  89                 return -ENOMEM;
  90         entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
  91         if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
  92                 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
  93                 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
  94                 if (entry->domain == NULL) {
  95                         ret_val = -ENOMEM;
  96                         goto add_free_entry;
  97                 }
  98                 nla_strlcpy(entry->domain,
  99                             info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
 100         }
 101 
 102         /* NOTE: internally we allow/use a entry->def.type value of
 103          *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
 104          *       to pass that as a protocol value because we need to know the
 105          *       "real" protocol */
 106 
 107         switch (entry->def.type) {
 108         case NETLBL_NLTYPE_UNLABELED:
 109                 if (info->attrs[NLBL_MGMT_A_FAMILY])
 110                         entry->family =
 111                                 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
 112                 else
 113                         entry->family = AF_UNSPEC;
 114                 break;
 115         case NETLBL_NLTYPE_CIPSOV4:
 116                 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
 117                         goto add_free_domain;
 118 
 119                 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
 120                 cipsov4 = cipso_v4_doi_getdef(tmp_val);
 121                 if (cipsov4 == NULL)
 122                         goto add_free_domain;
 123                 entry->family = AF_INET;
 124                 entry->def.cipso = cipsov4;
 125                 break;
 126 #if IS_ENABLED(CONFIG_IPV6)
 127         case NETLBL_NLTYPE_CALIPSO:
 128                 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
 129                         goto add_free_domain;
 130 
 131                 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
 132                 calipso = calipso_doi_getdef(tmp_val);
 133                 if (calipso == NULL)
 134                         goto add_free_domain;
 135                 entry->family = AF_INET6;
 136                 entry->def.calipso = calipso;
 137                 break;
 138 #endif /* IPv6 */
 139         default:
 140                 goto add_free_domain;
 141         }
 142 
 143         if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
 144             (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
 145                 goto add_doi_put_def;
 146 
 147         if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
 148                 struct in_addr *addr;
 149                 struct in_addr *mask;
 150                 struct netlbl_domaddr4_map *map;
 151 
 152                 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
 153                 if (addrmap == NULL) {
 154                         ret_val = -ENOMEM;
 155                         goto add_doi_put_def;
 156                 }
 157                 INIT_LIST_HEAD(&addrmap->list4);
 158                 INIT_LIST_HEAD(&addrmap->list6);
 159 
 160                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
 161                     sizeof(struct in_addr)) {
 162                         ret_val = -EINVAL;
 163                         goto add_free_addrmap;
 164                 }
 165                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
 166                     sizeof(struct in_addr)) {
 167                         ret_val = -EINVAL;
 168                         goto add_free_addrmap;
 169                 }
 170                 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
 171                 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
 172 
 173                 map = kzalloc(sizeof(*map), GFP_KERNEL);
 174                 if (map == NULL) {
 175                         ret_val = -ENOMEM;
 176                         goto add_free_addrmap;
 177                 }
 178                 map->list.addr = addr->s_addr & mask->s_addr;
 179                 map->list.mask = mask->s_addr;
 180                 map->list.valid = 1;
 181                 map->def.type = entry->def.type;
 182                 if (cipsov4)
 183                         map->def.cipso = cipsov4;
 184 
 185                 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
 186                 if (ret_val != 0) {
 187                         kfree(map);
 188                         goto add_free_addrmap;
 189                 }
 190 
 191                 entry->family = AF_INET;
 192                 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
 193                 entry->def.addrsel = addrmap;
 194 #if IS_ENABLED(CONFIG_IPV6)
 195         } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
 196                 struct in6_addr *addr;
 197                 struct in6_addr *mask;
 198                 struct netlbl_domaddr6_map *map;
 199 
 200                 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
 201                 if (addrmap == NULL) {
 202                         ret_val = -ENOMEM;
 203                         goto add_doi_put_def;
 204                 }
 205                 INIT_LIST_HEAD(&addrmap->list4);
 206                 INIT_LIST_HEAD(&addrmap->list6);
 207 
 208                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
 209                     sizeof(struct in6_addr)) {
 210                         ret_val = -EINVAL;
 211                         goto add_free_addrmap;
 212                 }
 213                 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
 214                     sizeof(struct in6_addr)) {
 215                         ret_val = -EINVAL;
 216                         goto add_free_addrmap;
 217                 }
 218                 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
 219                 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
 220 
 221                 map = kzalloc(sizeof(*map), GFP_KERNEL);
 222                 if (map == NULL) {
 223                         ret_val = -ENOMEM;
 224                         goto add_free_addrmap;
 225                 }
 226                 map->list.addr = *addr;
 227                 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
 228                 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
 229                 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
 230                 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
 231                 map->list.mask = *mask;
 232                 map->list.valid = 1;
 233                 map->def.type = entry->def.type;
 234                 if (calipso)
 235                         map->def.calipso = calipso;
 236 
 237                 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
 238                 if (ret_val != 0) {
 239                         kfree(map);
 240                         goto add_free_addrmap;
 241                 }
 242 
 243                 entry->family = AF_INET6;
 244                 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
 245                 entry->def.addrsel = addrmap;
 246 #endif /* IPv6 */
 247         }
 248 
 249         ret_val = netlbl_domhsh_add(entry, audit_info);
 250         if (ret_val != 0)
 251                 goto add_free_addrmap;
 252 
 253         return 0;
 254 
 255 add_free_addrmap:
 256         kfree(addrmap);
 257 add_doi_put_def:
 258         cipso_v4_doi_putdef(cipsov4);
 259 #if IS_ENABLED(CONFIG_IPV6)
 260         calipso_doi_putdef(calipso);
 261 #endif
 262 add_free_domain:
 263         kfree(entry->domain);
 264 add_free_entry:
 265         kfree(entry);
 266         return ret_val;
 267 }
 268 
 269 /**
 270  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
 271  * @skb: the NETLINK buffer
 272  * @entry: the map entry
 273  *
 274  * Description:
 275  * This function is a helper function used by the LISTALL and LISTDEF command
 276  * handlers.  The caller is responsible for ensuring that the RCU read lock
 277  * is held.  Returns zero on success, negative values on failure.
 278  *
 279  */
 280 static int netlbl_mgmt_listentry(struct sk_buff *skb,
 281                                  struct netlbl_dom_map *entry)
 282 {
 283         int ret_val = 0;
 284         struct nlattr *nla_a;
 285         struct nlattr *nla_b;
 286         struct netlbl_af4list *iter4;
 287 #if IS_ENABLED(CONFIG_IPV6)
 288         struct netlbl_af6list *iter6;
 289 #endif
 290 
 291         if (entry->domain != NULL) {
 292                 ret_val = nla_put_string(skb,
 293                                          NLBL_MGMT_A_DOMAIN, entry->domain);
 294                 if (ret_val != 0)
 295                         return ret_val;
 296         }
 297 
 298         ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
 299         if (ret_val != 0)
 300                 return ret_val;
 301 
 302         switch (entry->def.type) {
 303         case NETLBL_NLTYPE_ADDRSELECT:
 304                 nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
 305                 if (nla_a == NULL)
 306                         return -ENOMEM;
 307 
 308                 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
 309                         struct netlbl_domaddr4_map *map4;
 310                         struct in_addr addr_struct;
 311 
 312                         nla_b = nla_nest_start_noflag(skb,
 313                                                       NLBL_MGMT_A_ADDRSELECTOR);
 314                         if (nla_b == NULL)
 315                                 return -ENOMEM;
 316 
 317                         addr_struct.s_addr = iter4->addr;
 318                         ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
 319                                                   addr_struct.s_addr);
 320                         if (ret_val != 0)
 321                                 return ret_val;
 322                         addr_struct.s_addr = iter4->mask;
 323                         ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
 324                                                   addr_struct.s_addr);
 325                         if (ret_val != 0)
 326                                 return ret_val;
 327                         map4 = netlbl_domhsh_addr4_entry(iter4);
 328                         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
 329                                               map4->def.type);
 330                         if (ret_val != 0)
 331                                 return ret_val;
 332                         switch (map4->def.type) {
 333                         case NETLBL_NLTYPE_CIPSOV4:
 334                                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
 335                                                       map4->def.cipso->doi);
 336                                 if (ret_val != 0)
 337                                         return ret_val;
 338                                 break;
 339                         }
 340 
 341                         nla_nest_end(skb, nla_b);
 342                 }
 343 #if IS_ENABLED(CONFIG_IPV6)
 344                 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
 345                         struct netlbl_domaddr6_map *map6;
 346 
 347                         nla_b = nla_nest_start_noflag(skb,
 348                                                       NLBL_MGMT_A_ADDRSELECTOR);
 349                         if (nla_b == NULL)
 350                                 return -ENOMEM;
 351 
 352                         ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
 353                                                    &iter6->addr);
 354                         if (ret_val != 0)
 355                                 return ret_val;
 356                         ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
 357                                                    &iter6->mask);
 358                         if (ret_val != 0)
 359                                 return ret_val;
 360                         map6 = netlbl_domhsh_addr6_entry(iter6);
 361                         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
 362                                               map6->def.type);
 363                         if (ret_val != 0)
 364                                 return ret_val;
 365 
 366                         switch (map6->def.type) {
 367                         case NETLBL_NLTYPE_CALIPSO:
 368                                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
 369                                                       map6->def.calipso->doi);
 370                                 if (ret_val != 0)
 371                                         return ret_val;
 372                                 break;
 373                         }
 374 
 375                         nla_nest_end(skb, nla_b);
 376                 }
 377 #endif /* IPv6 */
 378 
 379                 nla_nest_end(skb, nla_a);
 380                 break;
 381         case NETLBL_NLTYPE_UNLABELED:
 382                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
 383                                       entry->def.type);
 384                 break;
 385         case NETLBL_NLTYPE_CIPSOV4:
 386                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
 387                                       entry->def.type);
 388                 if (ret_val != 0)
 389                         return ret_val;
 390                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
 391                                       entry->def.cipso->doi);
 392                 break;
 393         case NETLBL_NLTYPE_CALIPSO:
 394                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
 395                                       entry->def.type);
 396                 if (ret_val != 0)
 397                         return ret_val;
 398                 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
 399                                       entry->def.calipso->doi);
 400                 break;
 401         }
 402 
 403         return ret_val;
 404 }
 405 
 406 /*
 407  * NetLabel Command Handlers
 408  */
 409 
 410 /**
 411  * netlbl_mgmt_add - Handle an ADD message
 412  * @skb: the NETLINK buffer
 413  * @info: the Generic NETLINK info block
 414  *
 415  * Description:
 416  * Process a user generated ADD message and add the domains from the message
 417  * to the hash table.  See netlabel.h for a description of the message format.
 418  * Returns zero on success, negative values on failure.
 419  *
 420  */
 421 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
 422 {
 423         struct netlbl_audit audit_info;
 424 
 425         if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
 426             (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
 427             (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
 428              info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
 429             (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
 430              info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
 431             ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
 432              (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
 433             ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
 434              (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
 435                 return -EINVAL;
 436 
 437         netlbl_netlink_auditinfo(skb, &audit_info);
 438 
 439         return netlbl_mgmt_add_common(info, &audit_info);
 440 }
 441 
 442 /**
 443  * netlbl_mgmt_remove - Handle a REMOVE message
 444  * @skb: the NETLINK buffer
 445  * @info: the Generic NETLINK info block
 446  *
 447  * Description:
 448  * Process a user generated REMOVE message and remove the specified domain
 449  * mappings.  Returns zero on success, negative values on failure.
 450  *
 451  */
 452 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
 453 {
 454         char *domain;
 455         struct netlbl_audit audit_info;
 456 
 457         if (!info->attrs[NLBL_MGMT_A_DOMAIN])
 458                 return -EINVAL;
 459 
 460         netlbl_netlink_auditinfo(skb, &audit_info);
 461 
 462         domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
 463         return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
 464 }
 465 
 466 /**
 467  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
 468  * @entry: the domain mapping hash table entry
 469  * @arg: the netlbl_domhsh_walk_arg structure
 470  *
 471  * Description:
 472  * This function is designed to be used as a callback to the
 473  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
 474  * message.  Returns the size of the message on success, negative values on
 475  * failure.
 476  *
 477  */
 478 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
 479 {
 480         int ret_val = -ENOMEM;
 481         struct netlbl_domhsh_walk_arg *cb_arg = arg;
 482         void *data;
 483 
 484         data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
 485                            cb_arg->seq, &netlbl_mgmt_gnl_family,
 486                            NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
 487         if (data == NULL)
 488                 goto listall_cb_failure;
 489 
 490         ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
 491         if (ret_val != 0)
 492                 goto listall_cb_failure;
 493 
 494         cb_arg->seq++;
 495         genlmsg_end(cb_arg->skb, data);
 496         return 0;
 497 
 498 listall_cb_failure:
 499         genlmsg_cancel(cb_arg->skb, data);
 500         return ret_val;
 501 }
 502 
 503 /**
 504  * netlbl_mgmt_listall - Handle a LISTALL message
 505  * @skb: the NETLINK buffer
 506  * @cb: the NETLINK callback
 507  *
 508  * Description:
 509  * Process a user generated LISTALL message and dumps the domain hash table in
 510  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
 511  * on success, negative values on failure.
 512  *
 513  */
 514 static int netlbl_mgmt_listall(struct sk_buff *skb,
 515                                struct netlink_callback *cb)
 516 {
 517         struct netlbl_domhsh_walk_arg cb_arg;
 518         u32 skip_bkt = cb->args[0];
 519         u32 skip_chain = cb->args[1];
 520 
 521         cb_arg.nl_cb = cb;
 522         cb_arg.skb = skb;
 523         cb_arg.seq = cb->nlh->nlmsg_seq;
 524 
 525         netlbl_domhsh_walk(&skip_bkt,
 526                            &skip_chain,
 527                            netlbl_mgmt_listall_cb,
 528                            &cb_arg);
 529 
 530         cb->args[0] = skip_bkt;
 531         cb->args[1] = skip_chain;
 532         return skb->len;
 533 }
 534 
 535 /**
 536  * netlbl_mgmt_adddef - Handle an ADDDEF message
 537  * @skb: the NETLINK buffer
 538  * @info: the Generic NETLINK info block
 539  *
 540  * Description:
 541  * Process a user generated ADDDEF message and respond accordingly.  Returns
 542  * zero on success, negative values on failure.
 543  *
 544  */
 545 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
 546 {
 547         struct netlbl_audit audit_info;
 548 
 549         if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
 550             (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
 551              info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
 552             (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
 553              info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
 554             ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
 555              (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
 556             ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
 557              (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
 558                 return -EINVAL;
 559 
 560         netlbl_netlink_auditinfo(skb, &audit_info);
 561 
 562         return netlbl_mgmt_add_common(info, &audit_info);
 563 }
 564 
 565 /**
 566  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
 567  * @skb: the NETLINK buffer
 568  * @info: the Generic NETLINK info block
 569  *
 570  * Description:
 571  * Process a user generated REMOVEDEF message and remove the default domain
 572  * mapping.  Returns zero on success, negative values on failure.
 573  *
 574  */
 575 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
 576 {
 577         struct netlbl_audit audit_info;
 578 
 579         netlbl_netlink_auditinfo(skb, &audit_info);
 580 
 581         return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
 582 }
 583 
 584 /**
 585  * netlbl_mgmt_listdef - Handle a LISTDEF message
 586  * @skb: the NETLINK buffer
 587  * @info: the Generic NETLINK info block
 588  *
 589  * Description:
 590  * Process a user generated LISTDEF message and dumps the default domain
 591  * mapping in a form suitable for use in a kernel generated LISTDEF message.
 592  * Returns zero on success, negative values on failure.
 593  *
 594  */
 595 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
 596 {
 597         int ret_val = -ENOMEM;
 598         struct sk_buff *ans_skb = NULL;
 599         void *data;
 600         struct netlbl_dom_map *entry;
 601         u16 family;
 602 
 603         if (info->attrs[NLBL_MGMT_A_FAMILY])
 604                 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
 605         else
 606                 family = AF_INET;
 607 
 608         ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 609         if (ans_skb == NULL)
 610                 return -ENOMEM;
 611         data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
 612                                  0, NLBL_MGMT_C_LISTDEF);
 613         if (data == NULL)
 614                 goto listdef_failure;
 615 
 616         rcu_read_lock();
 617         entry = netlbl_domhsh_getentry(NULL, family);
 618         if (entry == NULL) {
 619                 ret_val = -ENOENT;
 620                 goto listdef_failure_lock;
 621         }
 622         ret_val = netlbl_mgmt_listentry(ans_skb, entry);
 623         rcu_read_unlock();
 624         if (ret_val != 0)
 625                 goto listdef_failure;
 626 
 627         genlmsg_end(ans_skb, data);
 628         return genlmsg_reply(ans_skb, info);
 629 
 630 listdef_failure_lock:
 631         rcu_read_unlock();
 632 listdef_failure:
 633         kfree_skb(ans_skb);
 634         return ret_val;
 635 }
 636 
 637 /**
 638  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
 639  * @skb: the skb to write to
 640  * @cb: the NETLINK callback
 641  * @protocol: the NetLabel protocol to use in the message
 642  *
 643  * Description:
 644  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
 645  * answer a application's PROTOCOLS message.  Returns the size of the message
 646  * on success, negative values on failure.
 647  *
 648  */
 649 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
 650                                     struct netlink_callback *cb,
 651                                     u32 protocol)
 652 {
 653         int ret_val = -ENOMEM;
 654         void *data;
 655 
 656         data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
 657                            &netlbl_mgmt_gnl_family, NLM_F_MULTI,
 658                            NLBL_MGMT_C_PROTOCOLS);
 659         if (data == NULL)
 660                 goto protocols_cb_failure;
 661 
 662         ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
 663         if (ret_val != 0)
 664                 goto protocols_cb_failure;
 665 
 666         genlmsg_end(skb, data);
 667         return 0;
 668 
 669 protocols_cb_failure:
 670         genlmsg_cancel(skb, data);
 671         return ret_val;
 672 }
 673 
 674 /**
 675  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
 676  * @skb: the NETLINK buffer
 677  * @cb: the NETLINK callback
 678  *
 679  * Description:
 680  * Process a user generated PROTOCOLS message and respond accordingly.
 681  *
 682  */
 683 static int netlbl_mgmt_protocols(struct sk_buff *skb,
 684                                  struct netlink_callback *cb)
 685 {
 686         u32 protos_sent = cb->args[0];
 687 
 688         if (protos_sent == 0) {
 689                 if (netlbl_mgmt_protocols_cb(skb,
 690                                              cb,
 691                                              NETLBL_NLTYPE_UNLABELED) < 0)
 692                         goto protocols_return;
 693                 protos_sent++;
 694         }
 695         if (protos_sent == 1) {
 696                 if (netlbl_mgmt_protocols_cb(skb,
 697                                              cb,
 698                                              NETLBL_NLTYPE_CIPSOV4) < 0)
 699                         goto protocols_return;
 700                 protos_sent++;
 701         }
 702 #if IS_ENABLED(CONFIG_IPV6)
 703         if (protos_sent == 2) {
 704                 if (netlbl_mgmt_protocols_cb(skb,
 705                                              cb,
 706                                              NETLBL_NLTYPE_CALIPSO) < 0)
 707                         goto protocols_return;
 708                 protos_sent++;
 709         }
 710 #endif
 711 
 712 protocols_return:
 713         cb->args[0] = protos_sent;
 714         return skb->len;
 715 }
 716 
 717 /**
 718  * netlbl_mgmt_version - Handle a VERSION message
 719  * @skb: the NETLINK buffer
 720  * @info: the Generic NETLINK info block
 721  *
 722  * Description:
 723  * Process a user generated VERSION message and respond accordingly.  Returns
 724  * zero on success, negative values on failure.
 725  *
 726  */
 727 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
 728 {
 729         int ret_val = -ENOMEM;
 730         struct sk_buff *ans_skb = NULL;
 731         void *data;
 732 
 733         ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 734         if (ans_skb == NULL)
 735                 return -ENOMEM;
 736         data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
 737                                  0, NLBL_MGMT_C_VERSION);
 738         if (data == NULL)
 739                 goto version_failure;
 740 
 741         ret_val = nla_put_u32(ans_skb,
 742                               NLBL_MGMT_A_VERSION,
 743                               NETLBL_PROTO_VERSION);
 744         if (ret_val != 0)
 745                 goto version_failure;
 746 
 747         genlmsg_end(ans_skb, data);
 748         return genlmsg_reply(ans_skb, info);
 749 
 750 version_failure:
 751         kfree_skb(ans_skb);
 752         return ret_val;
 753 }
 754 
 755 
 756 /*
 757  * NetLabel Generic NETLINK Command Definitions
 758  */
 759 
 760 static const struct genl_ops netlbl_mgmt_genl_ops[] = {
 761         {
 762         .cmd = NLBL_MGMT_C_ADD,
 763         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 764         .flags = GENL_ADMIN_PERM,
 765         .doit = netlbl_mgmt_add,
 766         .dumpit = NULL,
 767         },
 768         {
 769         .cmd = NLBL_MGMT_C_REMOVE,
 770         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 771         .flags = GENL_ADMIN_PERM,
 772         .doit = netlbl_mgmt_remove,
 773         .dumpit = NULL,
 774         },
 775         {
 776         .cmd = NLBL_MGMT_C_LISTALL,
 777         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 778         .flags = 0,
 779         .doit = NULL,
 780         .dumpit = netlbl_mgmt_listall,
 781         },
 782         {
 783         .cmd = NLBL_MGMT_C_ADDDEF,
 784         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 785         .flags = GENL_ADMIN_PERM,
 786         .doit = netlbl_mgmt_adddef,
 787         .dumpit = NULL,
 788         },
 789         {
 790         .cmd = NLBL_MGMT_C_REMOVEDEF,
 791         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 792         .flags = GENL_ADMIN_PERM,
 793         .doit = netlbl_mgmt_removedef,
 794         .dumpit = NULL,
 795         },
 796         {
 797         .cmd = NLBL_MGMT_C_LISTDEF,
 798         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 799         .flags = 0,
 800         .doit = netlbl_mgmt_listdef,
 801         .dumpit = NULL,
 802         },
 803         {
 804         .cmd = NLBL_MGMT_C_PROTOCOLS,
 805         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 806         .flags = 0,
 807         .doit = NULL,
 808         .dumpit = netlbl_mgmt_protocols,
 809         },
 810         {
 811         .cmd = NLBL_MGMT_C_VERSION,
 812         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
 813         .flags = 0,
 814         .doit = netlbl_mgmt_version,
 815         .dumpit = NULL,
 816         },
 817 };
 818 
 819 static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
 820         .hdrsize = 0,
 821         .name = NETLBL_NLTYPE_MGMT_NAME,
 822         .version = NETLBL_PROTO_VERSION,
 823         .maxattr = NLBL_MGMT_A_MAX,
 824         .policy = netlbl_mgmt_genl_policy,
 825         .module = THIS_MODULE,
 826         .ops = netlbl_mgmt_genl_ops,
 827         .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
 828 };
 829 
 830 /*
 831  * NetLabel Generic NETLINK Protocol Functions
 832  */
 833 
 834 /**
 835  * netlbl_mgmt_genl_init - Register the NetLabel management component
 836  *
 837  * Description:
 838  * Register the NetLabel management component with the Generic NETLINK
 839  * mechanism.  Returns zero on success, negative values on failure.
 840  *
 841  */
 842 int __init netlbl_mgmt_genl_init(void)
 843 {
 844         return genl_register_family(&netlbl_mgmt_gnl_family);
 845 }

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