linux/net/netlabel/netlabel_unlabeled.c
<<
>>
Prefs
   1/*
   2 * NetLabel Unlabeled Support
   3 *
   4 * This file defines functions for dealing with unlabeled packets for the
   5 * NetLabel system.  The NetLabel system manages static and dynamic label
   6 * mappings for network protocols such as CIPSO and RIPSO.
   7 *
   8 * Author: Paul Moore <paul.moore@hp.com>
   9 *
  10 */
  11
  12/*
  13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008
  14 *
  15 * This program is free software;  you can redistribute it and/or modify
  16 * it under the terms of the GNU General Public License as published by
  17 * the Free Software Foundation; either version 2 of the License, or
  18 * (at your option) any later version.
  19 *
  20 * This program is distributed in the hope that it will be useful,
  21 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
  22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  23 * the GNU General Public License for more details.
  24 *
  25 * You should have received a copy of the GNU General Public License
  26 * along with this program;  if not, write to the Free Software
  27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28 *
  29 */
  30
  31#include <linux/types.h>
  32#include <linux/rcupdate.h>
  33#include <linux/list.h>
  34#include <linux/spinlock.h>
  35#include <linux/socket.h>
  36#include <linux/string.h>
  37#include <linux/skbuff.h>
  38#include <linux/audit.h>
  39#include <linux/in.h>
  40#include <linux/in6.h>
  41#include <linux/ip.h>
  42#include <linux/ipv6.h>
  43#include <linux/notifier.h>
  44#include <linux/netdevice.h>
  45#include <linux/security.h>
  46#include <net/sock.h>
  47#include <net/netlink.h>
  48#include <net/genetlink.h>
  49#include <net/ip.h>
  50#include <net/ipv6.h>
  51#include <net/net_namespace.h>
  52#include <net/netlabel.h>
  53#include <asm/bug.h>
  54#include <asm/atomic.h>
  55
  56#include "netlabel_user.h"
  57#include "netlabel_addrlist.h"
  58#include "netlabel_domainhash.h"
  59#include "netlabel_unlabeled.h"
  60#include "netlabel_mgmt.h"
  61
  62/* NOTE: at present we always use init's network namespace since we don't
  63 *       presently support different namespaces even though the majority of
  64 *       the functions in this file are "namespace safe" */
  65
  66/* The unlabeled connection hash table which we use to map network interfaces
  67 * and addresses of unlabeled packets to a user specified secid value for the
  68 * LSM.  The hash table is used to lookup the network interface entry
  69 * (struct netlbl_unlhsh_iface) and then the interface entry is used to
  70 * lookup an IP address match from an ordered list.  If a network interface
  71 * match can not be found in the hash table then the default entry
  72 * (netlbl_unlhsh_def) is used.  The IP address entry list
  73 * (struct netlbl_unlhsh_addr) is ordered such that the entries with a
  74 * larger netmask come first.
  75 */
  76struct netlbl_unlhsh_tbl {
  77        struct list_head *tbl;
  78        u32 size;
  79};
  80#define netlbl_unlhsh_addr4_entry(iter) \
  81        container_of(iter, struct netlbl_unlhsh_addr4, list)
  82struct netlbl_unlhsh_addr4 {
  83        u32 secid;
  84
  85        struct netlbl_af4list list;
  86        struct rcu_head rcu;
  87};
  88#define netlbl_unlhsh_addr6_entry(iter) \
  89        container_of(iter, struct netlbl_unlhsh_addr6, list)
  90struct netlbl_unlhsh_addr6 {
  91        u32 secid;
  92
  93        struct netlbl_af6list list;
  94        struct rcu_head rcu;
  95};
  96struct netlbl_unlhsh_iface {
  97        int ifindex;
  98        struct list_head addr4_list;
  99        struct list_head addr6_list;
 100
 101        u32 valid;
 102        struct list_head list;
 103        struct rcu_head rcu;
 104};
 105
 106/* Argument struct for netlbl_unlhsh_walk() */
 107struct netlbl_unlhsh_walk_arg {
 108        struct netlink_callback *nl_cb;
 109        struct sk_buff *skb;
 110        u32 seq;
 111};
 112
 113/* Unlabeled connection hash table */
 114/* updates should be so rare that having one spinlock for the entire
 115 * hash table should be okay */
 116static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
 117static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;
 118static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;
 119
 120/* Accept unlabeled packets flag */
 121static u8 netlabel_unlabel_acceptflg = 0;
 122
 123/* NetLabel Generic NETLINK unlabeled family */
 124static struct genl_family netlbl_unlabel_gnl_family = {
 125        .id = GENL_ID_GENERATE,
 126        .hdrsize = 0,
 127        .name = NETLBL_NLTYPE_UNLABELED_NAME,
 128        .version = NETLBL_PROTO_VERSION,
 129        .maxattr = NLBL_UNLABEL_A_MAX,
 130};
 131
 132/* NetLabel Netlink attribute policy */
 133static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
 134        [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
 135        [NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,
 136                                      .len = sizeof(struct in6_addr) },
 137        [NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,
 138                                      .len = sizeof(struct in6_addr) },
 139        [NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,
 140                                      .len = sizeof(struct in_addr) },
 141        [NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,
 142                                      .len = sizeof(struct in_addr) },
 143        [NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,
 144                                   .len = IFNAMSIZ - 1 },
 145        [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
 146};
 147
 148/*
 149 * Unlabeled Connection Hash Table Functions
 150 */
 151
 152/**
 153 * netlbl_unlhsh_free_addr4 - Frees an IPv4 address entry from the hash table
 154 * @entry: the entry's RCU field
 155 *
 156 * Description:
 157 * This function is designed to be used as a callback to the call_rcu()
 158 * function so that memory allocated to a hash table address entry can be
 159 * released safely.
 160 *
 161 */
 162static void netlbl_unlhsh_free_addr4(struct rcu_head *entry)
 163{
 164        struct netlbl_unlhsh_addr4 *ptr;
 165
 166        ptr = container_of(entry, struct netlbl_unlhsh_addr4, rcu);
 167        kfree(ptr);
 168}
 169
 170#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 171/**
 172 * netlbl_unlhsh_free_addr6 - Frees an IPv6 address entry from the hash table
 173 * @entry: the entry's RCU field
 174 *
 175 * Description:
 176 * This function is designed to be used as a callback to the call_rcu()
 177 * function so that memory allocated to a hash table address entry can be
 178 * released safely.
 179 *
 180 */
 181static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
 182{
 183        struct netlbl_unlhsh_addr6 *ptr;
 184
 185        ptr = container_of(entry, struct netlbl_unlhsh_addr6, rcu);
 186        kfree(ptr);
 187}
 188#endif /* IPv6 */
 189
 190/**
 191 * netlbl_unlhsh_free_iface - Frees an interface entry from the hash table
 192 * @entry: the entry's RCU field
 193 *
 194 * Description:
 195 * This function is designed to be used as a callback to the call_rcu()
 196 * function so that memory allocated to a hash table interface entry can be
 197 * released safely.  It is important to note that this function does not free
 198 * the IPv4 and IPv6 address lists contained as part of an interface entry.  It
 199 * is up to the rest of the code to make sure an interface entry is only freed
 200 * once it's address lists are empty.
 201 *
 202 */
 203static void netlbl_unlhsh_free_iface(struct rcu_head *entry)
 204{
 205        struct netlbl_unlhsh_iface *iface;
 206        struct netlbl_af4list *iter4;
 207        struct netlbl_af4list *tmp4;
 208#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 209        struct netlbl_af6list *iter6;
 210        struct netlbl_af6list *tmp6;
 211#endif /* IPv6 */
 212
 213        iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);
 214
 215        /* no need for locks here since we are the only one with access to this
 216         * structure */
 217
 218        netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {
 219                netlbl_af4list_remove_entry(iter4);
 220                kfree(netlbl_unlhsh_addr4_entry(iter4));
 221        }
 222#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 223        netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {
 224                netlbl_af6list_remove_entry(iter6);
 225                kfree(netlbl_unlhsh_addr6_entry(iter6));
 226        }
 227#endif /* IPv6 */
 228        kfree(iface);
 229}
 230
 231/**
 232 * netlbl_unlhsh_hash - Hashing function for the hash table
 233 * @ifindex: the network interface/device to hash
 234 *
 235 * Description:
 236 * This is the hashing function for the unlabeled hash table, it returns the
 237 * bucket number for the given device/interface.  The caller is responsible for
 238 * calling the rcu_read_[un]lock() functions.
 239 *
 240 */
 241static u32 netlbl_unlhsh_hash(int ifindex)
 242{
 243        /* this is taken _almost_ directly from
 244         * security/selinux/netif.c:sel_netif_hasfn() as they do pretty much
 245         * the same thing */
 246        return ifindex & (rcu_dereference(netlbl_unlhsh)->size - 1);
 247}
 248
 249/**
 250 * netlbl_unlhsh_search_iface - Search for a matching interface entry
 251 * @ifindex: the network interface
 252 *
 253 * Description:
 254 * Searches the unlabeled connection hash table and returns a pointer to the
 255 * interface entry which matches @ifindex, otherwise NULL is returned.  The
 256 * caller is responsible for calling the rcu_read_[un]lock() functions.
 257 *
 258 */
 259static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)
 260{
 261        u32 bkt;
 262        struct list_head *bkt_list;
 263        struct netlbl_unlhsh_iface *iter;
 264
 265        bkt = netlbl_unlhsh_hash(ifindex);
 266        bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt];
 267        list_for_each_entry_rcu(iter, bkt_list, list)
 268                if (iter->valid && iter->ifindex == ifindex)
 269                        return iter;
 270
 271        return NULL;
 272}
 273
 274/**
 275 * netlbl_unlhsh_search_iface_def - Search for a matching interface entry
 276 * @ifindex: the network interface
 277 *
 278 * Description:
 279 * Searches the unlabeled connection hash table and returns a pointer to the
 280 * interface entry which matches @ifindex.  If an exact match can not be found
 281 * and there is a valid default entry, the default entry is returned, otherwise
 282 * NULL is returned.  The caller is responsible for calling the
 283 * rcu_read_[un]lock() functions.
 284 *
 285 */
 286static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface_def(int ifindex)
 287{
 288        struct netlbl_unlhsh_iface *entry;
 289
 290        entry = netlbl_unlhsh_search_iface(ifindex);
 291        if (entry != NULL)
 292                return entry;
 293
 294        entry = rcu_dereference(netlbl_unlhsh_def);
 295        if (entry != NULL && entry->valid)
 296                return entry;
 297
 298        return NULL;
 299}
 300
 301/**
 302 * netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table
 303 * @iface: the associated interface entry
 304 * @addr: IPv4 address in network byte order
 305 * @mask: IPv4 address mask in network byte order
 306 * @secid: LSM secid value for entry
 307 *
 308 * Description:
 309 * Add a new address entry into the unlabeled connection hash table using the
 310 * interface entry specified by @iface.  On success zero is returned, otherwise
 311 * a negative value is returned.  The caller is responsible for calling the
 312 * rcu_read_[un]lock() functions.
 313 *
 314 */
 315static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
 316                                   const struct in_addr *addr,
 317                                   const struct in_addr *mask,
 318                                   u32 secid)
 319{
 320        int ret_val;
 321        struct netlbl_unlhsh_addr4 *entry;
 322
 323        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 324        if (entry == NULL)
 325                return -ENOMEM;
 326
 327        entry->list.addr = addr->s_addr & mask->s_addr;
 328        entry->list.mask = mask->s_addr;
 329        entry->list.valid = 1;
 330        INIT_RCU_HEAD(&entry->rcu);
 331        entry->secid = secid;
 332
 333        spin_lock(&netlbl_unlhsh_lock);
 334        ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);
 335        spin_unlock(&netlbl_unlhsh_lock);
 336
 337        if (ret_val != 0)
 338                kfree(entry);
 339        return ret_val;
 340}
 341
 342#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 343/**
 344 * netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table
 345 * @iface: the associated interface entry
 346 * @addr: IPv6 address in network byte order
 347 * @mask: IPv6 address mask in network byte order
 348 * @secid: LSM secid value for entry
 349 *
 350 * Description:
 351 * Add a new address entry into the unlabeled connection hash table using the
 352 * interface entry specified by @iface.  On success zero is returned, otherwise
 353 * a negative value is returned.  The caller is responsible for calling the
 354 * rcu_read_[un]lock() functions.
 355 *
 356 */
 357static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
 358                                   const struct in6_addr *addr,
 359                                   const struct in6_addr *mask,
 360                                   u32 secid)
 361{
 362        int ret_val;
 363        struct netlbl_unlhsh_addr6 *entry;
 364
 365        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 366        if (entry == NULL)
 367                return -ENOMEM;
 368
 369        ipv6_addr_copy(&entry->list.addr, addr);
 370        entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
 371        entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
 372        entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
 373        entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
 374        ipv6_addr_copy(&entry->list.mask, mask);
 375        entry->list.valid = 1;
 376        INIT_RCU_HEAD(&entry->rcu);
 377        entry->secid = secid;
 378
 379        spin_lock(&netlbl_unlhsh_lock);
 380        ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);
 381        spin_unlock(&netlbl_unlhsh_lock);
 382
 383        if (ret_val != 0)
 384                kfree(entry);
 385        return 0;
 386}
 387#endif /* IPv6 */
 388
 389/**
 390 * netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table
 391 * @ifindex: network interface
 392 *
 393 * Description:
 394 * Add a new, empty, interface entry into the unlabeled connection hash table.
 395 * On success a pointer to the new interface entry is returned, on failure NULL
 396 * is returned.  The caller is responsible for calling the rcu_read_[un]lock()
 397 * functions.
 398 *
 399 */
 400static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
 401{
 402        u32 bkt;
 403        struct netlbl_unlhsh_iface *iface;
 404
 405        iface = kzalloc(sizeof(*iface), GFP_ATOMIC);
 406        if (iface == NULL)
 407                return NULL;
 408
 409        iface->ifindex = ifindex;
 410        INIT_LIST_HEAD(&iface->addr4_list);
 411        INIT_LIST_HEAD(&iface->addr6_list);
 412        iface->valid = 1;
 413        INIT_RCU_HEAD(&iface->rcu);
 414
 415        spin_lock(&netlbl_unlhsh_lock);
 416        if (ifindex > 0) {
 417                bkt = netlbl_unlhsh_hash(ifindex);
 418                if (netlbl_unlhsh_search_iface(ifindex) != NULL)
 419                        goto add_iface_failure;
 420                list_add_tail_rcu(&iface->list,
 421                                  &rcu_dereference(netlbl_unlhsh)->tbl[bkt]);
 422        } else {
 423                INIT_LIST_HEAD(&iface->list);
 424                if (rcu_dereference(netlbl_unlhsh_def) != NULL)
 425                        goto add_iface_failure;
 426                rcu_assign_pointer(netlbl_unlhsh_def, iface);
 427        }
 428        spin_unlock(&netlbl_unlhsh_lock);
 429
 430        return iface;
 431
 432add_iface_failure:
 433        spin_unlock(&netlbl_unlhsh_lock);
 434        kfree(iface);
 435        return NULL;
 436}
 437
 438/**
 439 * netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table
 440 * @net: network namespace
 441 * @dev_name: interface name
 442 * @addr: IP address in network byte order
 443 * @mask: address mask in network byte order
 444 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
 445 * @secid: LSM secid value for the entry
 446 * @audit_info: NetLabel audit information
 447 *
 448 * Description:
 449 * Adds a new entry to the unlabeled connection hash table.  Returns zero on
 450 * success, negative values on failure.
 451 *
 452 */
 453int netlbl_unlhsh_add(struct net *net,
 454                      const char *dev_name,
 455                      const void *addr,
 456                      const void *mask,
 457                      u32 addr_len,
 458                      u32 secid,
 459                      struct netlbl_audit *audit_info)
 460{
 461        int ret_val;
 462        int ifindex;
 463        struct net_device *dev;
 464        struct netlbl_unlhsh_iface *iface;
 465        struct audit_buffer *audit_buf = NULL;
 466        char *secctx = NULL;
 467        u32 secctx_len;
 468
 469        if (addr_len != sizeof(struct in_addr) &&
 470            addr_len != sizeof(struct in6_addr))
 471                return -EINVAL;
 472
 473        rcu_read_lock();
 474        if (dev_name != NULL) {
 475                dev = dev_get_by_name(net, dev_name);
 476                if (dev == NULL) {
 477                        ret_val = -ENODEV;
 478                        goto unlhsh_add_return;
 479                }
 480                ifindex = dev->ifindex;
 481                dev_put(dev);
 482                iface = netlbl_unlhsh_search_iface(ifindex);
 483        } else {
 484                ifindex = 0;
 485                iface = rcu_dereference(netlbl_unlhsh_def);
 486        }
 487        if (iface == NULL) {
 488                iface = netlbl_unlhsh_add_iface(ifindex);
 489                if (iface == NULL) {
 490                        ret_val = -ENOMEM;
 491                        goto unlhsh_add_return;
 492                }
 493        }
 494        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
 495                                              audit_info);
 496        switch (addr_len) {
 497        case sizeof(struct in_addr): {
 498                struct in_addr *addr4, *mask4;
 499
 500                addr4 = (struct in_addr *)addr;
 501                mask4 = (struct in_addr *)mask;
 502                ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
 503                if (audit_buf != NULL)
 504                        netlbl_af4list_audit_addr(audit_buf, 1,
 505                                                  dev_name,
 506                                                  addr4->s_addr,
 507                                                  mask4->s_addr);
 508                break;
 509        }
 510#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 511        case sizeof(struct in6_addr): {
 512                struct in6_addr *addr6, *mask6;
 513
 514                addr6 = (struct in6_addr *)addr;
 515                mask6 = (struct in6_addr *)mask;
 516                ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
 517                if (audit_buf != NULL)
 518                        netlbl_af6list_audit_addr(audit_buf, 1,
 519                                                  dev_name,
 520                                                  addr6, mask6);
 521                break;
 522        }
 523#endif /* IPv6 */
 524        default:
 525                ret_val = -EINVAL;
 526        }
 527        if (ret_val == 0)
 528                atomic_inc(&netlabel_mgmt_protocount);
 529
 530unlhsh_add_return:
 531        rcu_read_unlock();
 532        if (audit_buf != NULL) {
 533                if (security_secid_to_secctx(secid,
 534                                             &secctx,
 535                                             &secctx_len) == 0) {
 536                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
 537                        security_release_secctx(secctx, secctx_len);
 538                }
 539                audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
 540                audit_log_end(audit_buf);
 541        }
 542        return ret_val;
 543}
 544
 545/**
 546 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
 547 * @net: network namespace
 548 * @iface: interface entry
 549 * @addr: IP address
 550 * @mask: IP address mask
 551 * @audit_info: NetLabel audit information
 552 *
 553 * Description:
 554 * Remove an IP address entry from the unlabeled connection hash table.
 555 * Returns zero on success, negative values on failure.  The caller is
 556 * responsible for calling the rcu_read_[un]lock() functions.
 557 *
 558 */
 559static int netlbl_unlhsh_remove_addr4(struct net *net,
 560                                      struct netlbl_unlhsh_iface *iface,
 561                                      const struct in_addr *addr,
 562                                      const struct in_addr *mask,
 563                                      struct netlbl_audit *audit_info)
 564{
 565        struct netlbl_af4list *list_entry;
 566        struct netlbl_unlhsh_addr4 *entry;
 567        struct audit_buffer *audit_buf;
 568        struct net_device *dev;
 569        char *secctx;
 570        u32 secctx_len;
 571
 572        spin_lock(&netlbl_unlhsh_lock);
 573        list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
 574                                           &iface->addr4_list);
 575        spin_unlock(&netlbl_unlhsh_lock);
 576        if (list_entry != NULL)
 577                entry = netlbl_unlhsh_addr4_entry(list_entry);
 578        else
 579                entry = NULL;
 580
 581        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 582                                              audit_info);
 583        if (audit_buf != NULL) {
 584                dev = dev_get_by_index(net, iface->ifindex);
 585                netlbl_af4list_audit_addr(audit_buf, 1,
 586                                          (dev != NULL ? dev->name : NULL),
 587                                          addr->s_addr, mask->s_addr);
 588                if (dev != NULL)
 589                        dev_put(dev);
 590                if (entry != NULL &&
 591                    security_secid_to_secctx(entry->secid,
 592                                             &secctx, &secctx_len) == 0) {
 593                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
 594                        security_release_secctx(secctx, secctx_len);
 595                }
 596                audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
 597                audit_log_end(audit_buf);
 598        }
 599
 600        if (entry == NULL)
 601                return -ENOENT;
 602
 603        call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
 604        return 0;
 605}
 606
 607#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 608/**
 609 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
 610 * @net: network namespace
 611 * @iface: interface entry
 612 * @addr: IP address
 613 * @mask: IP address mask
 614 * @audit_info: NetLabel audit information
 615 *
 616 * Description:
 617 * Remove an IP address entry from the unlabeled connection hash table.
 618 * Returns zero on success, negative values on failure.  The caller is
 619 * responsible for calling the rcu_read_[un]lock() functions.
 620 *
 621 */
 622static int netlbl_unlhsh_remove_addr6(struct net *net,
 623                                      struct netlbl_unlhsh_iface *iface,
 624                                      const struct in6_addr *addr,
 625                                      const struct in6_addr *mask,
 626                                      struct netlbl_audit *audit_info)
 627{
 628        struct netlbl_af6list *list_entry;
 629        struct netlbl_unlhsh_addr6 *entry;
 630        struct audit_buffer *audit_buf;
 631        struct net_device *dev;
 632        char *secctx;
 633        u32 secctx_len;
 634
 635        spin_lock(&netlbl_unlhsh_lock);
 636        list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);
 637        spin_unlock(&netlbl_unlhsh_lock);
 638        if (list_entry != NULL)
 639                entry = netlbl_unlhsh_addr6_entry(list_entry);
 640        else
 641                entry = NULL;
 642
 643        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
 644                                              audit_info);
 645        if (audit_buf != NULL) {
 646                dev = dev_get_by_index(net, iface->ifindex);
 647                netlbl_af6list_audit_addr(audit_buf, 1,
 648                                          (dev != NULL ? dev->name : NULL),
 649                                          addr, mask);
 650                if (dev != NULL)
 651                        dev_put(dev);
 652                if (entry != NULL &&
 653                    security_secid_to_secctx(entry->secid,
 654                                             &secctx, &secctx_len) == 0) {
 655                        audit_log_format(audit_buf, " sec_obj=%s", secctx);
 656                        security_release_secctx(secctx, secctx_len);
 657                }
 658                audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);
 659                audit_log_end(audit_buf);
 660        }
 661
 662        if (entry == NULL)
 663                return -ENOENT;
 664
 665        call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
 666        return 0;
 667}
 668#endif /* IPv6 */
 669
 670/**
 671 * netlbl_unlhsh_condremove_iface - Remove an interface entry
 672 * @iface: the interface entry
 673 *
 674 * Description:
 675 * Remove an interface entry from the unlabeled connection hash table if it is
 676 * empty.  An interface entry is considered to be empty if there are no
 677 * address entries assigned to it.
 678 *
 679 */
 680static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 681{
 682        struct netlbl_af4list *iter4;
 683#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 684        struct netlbl_af6list *iter6;
 685#endif /* IPv6 */
 686
 687        spin_lock(&netlbl_unlhsh_lock);
 688        netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)
 689                goto unlhsh_condremove_failure;
 690#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 691        netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)
 692                goto unlhsh_condremove_failure;
 693#endif /* IPv6 */
 694        iface->valid = 0;
 695        if (iface->ifindex > 0)
 696                list_del_rcu(&iface->list);
 697        else
 698                rcu_assign_pointer(netlbl_unlhsh_def, NULL);
 699        spin_unlock(&netlbl_unlhsh_lock);
 700
 701        call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
 702        return;
 703
 704unlhsh_condremove_failure:
 705        spin_unlock(&netlbl_unlhsh_lock);
 706        return;
 707}
 708
 709/**
 710 * netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table
 711 * @net: network namespace
 712 * @dev_name: interface name
 713 * @addr: IP address in network byte order
 714 * @mask: address mask in network byte order
 715 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
 716 * @audit_info: NetLabel audit information
 717 *
 718 * Description:
 719 * Removes and existing entry from the unlabeled connection hash table.
 720 * Returns zero on success, negative values on failure.
 721 *
 722 */
 723int netlbl_unlhsh_remove(struct net *net,
 724                         const char *dev_name,
 725                         const void *addr,
 726                         const void *mask,
 727                         u32 addr_len,
 728                         struct netlbl_audit *audit_info)
 729{
 730        int ret_val;
 731        struct net_device *dev;
 732        struct netlbl_unlhsh_iface *iface;
 733
 734        if (addr_len != sizeof(struct in_addr) &&
 735            addr_len != sizeof(struct in6_addr))
 736                return -EINVAL;
 737
 738        rcu_read_lock();
 739        if (dev_name != NULL) {
 740                dev = dev_get_by_name(net, dev_name);
 741                if (dev == NULL) {
 742                        ret_val = -ENODEV;
 743                        goto unlhsh_remove_return;
 744                }
 745                iface = netlbl_unlhsh_search_iface(dev->ifindex);
 746                dev_put(dev);
 747        } else
 748                iface = rcu_dereference(netlbl_unlhsh_def);
 749        if (iface == NULL) {
 750                ret_val = -ENOENT;
 751                goto unlhsh_remove_return;
 752        }
 753        switch (addr_len) {
 754        case sizeof(struct in_addr):
 755                ret_val = netlbl_unlhsh_remove_addr4(net,
 756                                                     iface, addr, mask,
 757                                                     audit_info);
 758                break;
 759#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 760        case sizeof(struct in6_addr):
 761                ret_val = netlbl_unlhsh_remove_addr6(net,
 762                                                     iface, addr, mask,
 763                                                     audit_info);
 764                break;
 765#endif /* IPv6 */
 766        default:
 767                ret_val = -EINVAL;
 768        }
 769        if (ret_val == 0) {
 770                netlbl_unlhsh_condremove_iface(iface);
 771                atomic_dec(&netlabel_mgmt_protocount);
 772        }
 773
 774unlhsh_remove_return:
 775        rcu_read_unlock();
 776        return ret_val;
 777}
 778
 779/*
 780 * General Helper Functions
 781 */
 782
 783/**
 784 * netlbl_unlhsh_netdev_handler - Network device notification handler
 785 * @this: notifier block
 786 * @event: the event
 787 * @ptr: the network device (cast to void)
 788 *
 789 * Description:
 790 * Handle network device events, although at present all we care about is a
 791 * network device going away.  In the case of a device going away we clear any
 792 * related entries from the unlabeled connection hash table.
 793 *
 794 */
 795static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
 796                                        unsigned long event,
 797                                        void *ptr)
 798{
 799        struct net_device *dev = ptr;
 800        struct netlbl_unlhsh_iface *iface = NULL;
 801
 802        if (!net_eq(dev_net(dev), &init_net))
 803                return NOTIFY_DONE;
 804
 805        /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
 806        if (event == NETDEV_DOWN) {
 807                spin_lock(&netlbl_unlhsh_lock);
 808                iface = netlbl_unlhsh_search_iface(dev->ifindex);
 809                if (iface != NULL && iface->valid) {
 810                        iface->valid = 0;
 811                        list_del_rcu(&iface->list);
 812                } else
 813                        iface = NULL;
 814                spin_unlock(&netlbl_unlhsh_lock);
 815        }
 816
 817        if (iface != NULL)
 818                call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);
 819
 820        return NOTIFY_DONE;
 821}
 822
 823/**
 824 * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
 825 * @value: desired value
 826 * @audit_info: NetLabel audit information
 827 *
 828 * Description:
 829 * Set the value of the unlabeled accept flag to @value.
 830 *
 831 */
 832static void netlbl_unlabel_acceptflg_set(u8 value,
 833                                         struct netlbl_audit *audit_info)
 834{
 835        struct audit_buffer *audit_buf;
 836        u8 old_val;
 837
 838        old_val = netlabel_unlabel_acceptflg;
 839        netlabel_unlabel_acceptflg = value;
 840        audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
 841                                              audit_info);
 842        if (audit_buf != NULL) {
 843                audit_log_format(audit_buf,
 844                                 " unlbl_accept=%u old=%u", value, old_val);
 845                audit_log_end(audit_buf);
 846        }
 847}
 848
 849/**
 850 * netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information
 851 * @info: the Generic NETLINK info block
 852 * @addr: the IP address
 853 * @mask: the IP address mask
 854 * @len: the address length
 855 *
 856 * Description:
 857 * Examine the Generic NETLINK message and extract the IP address information.
 858 * Returns zero on success, negative values on failure.
 859 *
 860 */
 861static int netlbl_unlabel_addrinfo_get(struct genl_info *info,
 862                                       void **addr,
 863                                       void **mask,
 864                                       u32 *len)
 865{
 866        u32 addr_len;
 867
 868        if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR]) {
 869                addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
 870                if (addr_len != sizeof(struct in_addr) &&
 871                    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))
 872                        return -EINVAL;
 873                *len = addr_len;
 874                *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);
 875                *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);
 876                return 0;
 877        } else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {
 878                addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
 879                if (addr_len != sizeof(struct in6_addr) &&
 880                    addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))
 881                        return -EINVAL;
 882                *len = addr_len;
 883                *addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);
 884                *mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);
 885                return 0;
 886        }
 887
 888        return -EINVAL;
 889}
 890
 891/*
 892 * NetLabel Command Handlers
 893 */
 894
 895/**
 896 * netlbl_unlabel_accept - Handle an ACCEPT message
 897 * @skb: the NETLINK buffer
 898 * @info: the Generic NETLINK info block
 899 *
 900 * Description:
 901 * Process a user generated ACCEPT message and set the accept flag accordingly.
 902 * Returns zero on success, negative values on failure.
 903 *
 904 */
 905static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
 906{
 907        u8 value;
 908        struct netlbl_audit audit_info;
 909
 910        if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
 911                value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
 912                if (value == 1 || value == 0) {
 913                        netlbl_netlink_auditinfo(skb, &audit_info);
 914                        netlbl_unlabel_acceptflg_set(value, &audit_info);
 915                        return 0;
 916                }
 917        }
 918
 919        return -EINVAL;
 920}
 921
 922/**
 923 * netlbl_unlabel_list - Handle a LIST message
 924 * @skb: the NETLINK buffer
 925 * @info: the Generic NETLINK info block
 926 *
 927 * Description:
 928 * Process a user generated LIST message and respond with the current status.
 929 * Returns zero on success, negative values on failure.
 930 *
 931 */
 932static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
 933{
 934        int ret_val = -EINVAL;
 935        struct sk_buff *ans_skb;
 936        void *data;
 937
 938        ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 939        if (ans_skb == NULL)
 940                goto list_failure;
 941        data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,
 942                                 0, NLBL_UNLABEL_C_LIST);
 943        if (data == NULL) {
 944                ret_val = -ENOMEM;
 945                goto list_failure;
 946        }
 947
 948        ret_val = nla_put_u8(ans_skb,
 949                             NLBL_UNLABEL_A_ACPTFLG,
 950                             netlabel_unlabel_acceptflg);
 951        if (ret_val != 0)
 952                goto list_failure;
 953
 954        genlmsg_end(ans_skb, data);
 955        return genlmsg_reply(ans_skb, info);
 956
 957list_failure:
 958        kfree_skb(ans_skb);
 959        return ret_val;
 960}
 961
 962/**
 963 * netlbl_unlabel_staticadd - Handle a STATICADD message
 964 * @skb: the NETLINK buffer
 965 * @info: the Generic NETLINK info block
 966 *
 967 * Description:
 968 * Process a user generated STATICADD message and add a new unlabeled
 969 * connection entry to the hash table.  Returns zero on success, negative
 970 * values on failure.
 971 *
 972 */
 973static int netlbl_unlabel_staticadd(struct sk_buff *skb,
 974                                    struct genl_info *info)
 975{
 976        int ret_val;
 977        char *dev_name;
 978        void *addr;
 979        void *mask;
 980        u32 addr_len;
 981        u32 secid;
 982        struct netlbl_audit audit_info;
 983
 984        /* Don't allow users to add both IPv4 and IPv6 addresses for a
 985         * single entry.  However, allow users to create two entries, one each
 986         * for IPv4 and IPv4, with the same LSM security context which should
 987         * achieve the same result. */
 988        if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
 989            !info->attrs[NLBL_UNLABEL_A_IFACE] ||
 990            !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
 991               !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
 992              (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
 993               !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
 994                return -EINVAL;
 995
 996        netlbl_netlink_auditinfo(skb, &audit_info);
 997
 998        ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
 999        if (ret_val != 0)
1000                return ret_val;
1001        dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1002        ret_val = security_secctx_to_secid(
1003                                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1004                                  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1005                                  &secid);
1006        if (ret_val != 0)
1007                return ret_val;
1008
1009        return netlbl_unlhsh_add(&init_net,
1010                                 dev_name, addr, mask, addr_len, secid,
1011                                 &audit_info);
1012}
1013
1014/**
1015 * netlbl_unlabel_staticadddef - Handle a STATICADDDEF message
1016 * @skb: the NETLINK buffer
1017 * @info: the Generic NETLINK info block
1018 *
1019 * Description:
1020 * Process a user generated STATICADDDEF message and add a new default
1021 * unlabeled connection entry.  Returns zero on success, negative values on
1022 * failure.
1023 *
1024 */
1025static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
1026                                       struct genl_info *info)
1027{
1028        int ret_val;
1029        void *addr;
1030        void *mask;
1031        u32 addr_len;
1032        u32 secid;
1033        struct netlbl_audit audit_info;
1034
1035        /* Don't allow users to add both IPv4 and IPv6 addresses for a
1036         * single entry.  However, allow users to create two entries, one each
1037         * for IPv4 and IPv6, with the same LSM security context which should
1038         * achieve the same result. */
1039        if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||
1040            !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1041               !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1042              (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1043               !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1044                return -EINVAL;
1045
1046        netlbl_netlink_auditinfo(skb, &audit_info);
1047
1048        ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1049        if (ret_val != 0)
1050                return ret_val;
1051        ret_val = security_secctx_to_secid(
1052                                  nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1053                                  nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),
1054                                  &secid);
1055        if (ret_val != 0)
1056                return ret_val;
1057
1058        return netlbl_unlhsh_add(&init_net,
1059                                 NULL, addr, mask, addr_len, secid,
1060                                 &audit_info);
1061}
1062
1063/**
1064 * netlbl_unlabel_staticremove - Handle a STATICREMOVE message
1065 * @skb: the NETLINK buffer
1066 * @info: the Generic NETLINK info block
1067 *
1068 * Description:
1069 * Process a user generated STATICREMOVE message and remove the specified
1070 * unlabeled connection entry.  Returns zero on success, negative values on
1071 * failure.
1072 *
1073 */
1074static int netlbl_unlabel_staticremove(struct sk_buff *skb,
1075                                       struct genl_info *info)
1076{
1077        int ret_val;
1078        char *dev_name;
1079        void *addr;
1080        void *mask;
1081        u32 addr_len;
1082        struct netlbl_audit audit_info;
1083
1084        /* See the note in netlbl_unlabel_staticadd() about not allowing both
1085         * IPv4 and IPv6 in the same entry. */
1086        if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||
1087            !((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1088               !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1089              (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1090               !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1091                return -EINVAL;
1092
1093        netlbl_netlink_auditinfo(skb, &audit_info);
1094
1095        ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1096        if (ret_val != 0)
1097                return ret_val;
1098        dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);
1099
1100        return netlbl_unlhsh_remove(&init_net,
1101                                    dev_name, addr, mask, addr_len,
1102                                    &audit_info);
1103}
1104
1105/**
1106 * netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message
1107 * @skb: the NETLINK buffer
1108 * @info: the Generic NETLINK info block
1109 *
1110 * Description:
1111 * Process a user generated STATICREMOVEDEF message and remove the default
1112 * unlabeled connection entry.  Returns zero on success, negative values on
1113 * failure.
1114 *
1115 */
1116static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
1117                                          struct genl_info *info)
1118{
1119        int ret_val;
1120        void *addr;
1121        void *mask;
1122        u32 addr_len;
1123        struct netlbl_audit audit_info;
1124
1125        /* See the note in netlbl_unlabel_staticadd() about not allowing both
1126         * IPv4 and IPv6 in the same entry. */
1127        if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||
1128               !info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^
1129              (!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||
1130               !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
1131                return -EINVAL;
1132
1133        netlbl_netlink_auditinfo(skb, &audit_info);
1134
1135        ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
1136        if (ret_val != 0)
1137                return ret_val;
1138
1139        return netlbl_unlhsh_remove(&init_net,
1140                                    NULL, addr, mask, addr_len,
1141                                    &audit_info);
1142}
1143
1144
1145/**
1146 * netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]
1147 * @cmd: command/message
1148 * @iface: the interface entry
1149 * @addr4: the IPv4 address entry
1150 * @addr6: the IPv6 address entry
1151 * @arg: the netlbl_unlhsh_walk_arg structure
1152 *
1153 * Description:
1154 * This function is designed to be used to generate a response for a
1155 * STATICLIST or STATICLISTDEF message.  When called either @addr4 or @addr6
1156 * can be specified, not both, the other unspecified entry should be set to
1157 * NULL by the caller.  Returns the size of the message on success, negative
1158 * values on failure.
1159 *
1160 */
1161static int netlbl_unlabel_staticlist_gen(u32 cmd,
1162                                       const struct netlbl_unlhsh_iface *iface,
1163                                       const struct netlbl_unlhsh_addr4 *addr4,
1164                                       const struct netlbl_unlhsh_addr6 *addr6,
1165                                       void *arg)
1166{
1167        int ret_val = -ENOMEM;
1168        struct netlbl_unlhsh_walk_arg *cb_arg = arg;
1169        struct net_device *dev;
1170        void *data;
1171        u32 secid;
1172        char *secctx;
1173        u32 secctx_len;
1174
1175        data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
1176                           cb_arg->seq, &netlbl_unlabel_gnl_family,
1177                           NLM_F_MULTI, cmd);
1178        if (data == NULL)
1179                goto list_cb_failure;
1180
1181        if (iface->ifindex > 0) {
1182                dev = dev_get_by_index(&init_net, iface->ifindex);
1183                if (!dev) {
1184                        ret_val = -ENODEV;
1185                        goto list_cb_failure;
1186                }
1187                ret_val = nla_put_string(cb_arg->skb,
1188                                         NLBL_UNLABEL_A_IFACE, dev->name);
1189                dev_put(dev);
1190                if (ret_val != 0)
1191                        goto list_cb_failure;
1192        }
1193
1194        if (addr4) {
1195                struct in_addr addr_struct;
1196
1197                addr_struct.s_addr = addr4->list.addr;
1198                ret_val = nla_put(cb_arg->skb,
1199                                  NLBL_UNLABEL_A_IPV4ADDR,
1200                                  sizeof(struct in_addr),
1201                                  &addr_struct);
1202                if (ret_val != 0)
1203                        goto list_cb_failure;
1204
1205                addr_struct.s_addr = addr4->list.mask;
1206                ret_val = nla_put(cb_arg->skb,
1207                                  NLBL_UNLABEL_A_IPV4MASK,
1208                                  sizeof(struct in_addr),
1209                                  &addr_struct);
1210                if (ret_val != 0)
1211                        goto list_cb_failure;
1212
1213                secid = addr4->secid;
1214        } else {
1215                ret_val = nla_put(cb_arg->skb,
1216                                  NLBL_UNLABEL_A_IPV6ADDR,
1217                                  sizeof(struct in6_addr),
1218                                  &addr6->list.addr);
1219                if (ret_val != 0)
1220                        goto list_cb_failure;
1221
1222                ret_val = nla_put(cb_arg->skb,
1223                                  NLBL_UNLABEL_A_IPV6MASK,
1224                                  sizeof(struct in6_addr),
1225                                  &addr6->list.mask);
1226                if (ret_val != 0)
1227                        goto list_cb_failure;
1228
1229                secid = addr6->secid;
1230        }
1231
1232        ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);
1233        if (ret_val != 0)
1234                goto list_cb_failure;
1235        ret_val = nla_put(cb_arg->skb,
1236                          NLBL_UNLABEL_A_SECCTX,
1237                          secctx_len,
1238                          secctx);
1239        security_release_secctx(secctx, secctx_len);
1240        if (ret_val != 0)
1241                goto list_cb_failure;
1242
1243        cb_arg->seq++;
1244        return genlmsg_end(cb_arg->skb, data);
1245
1246list_cb_failure:
1247        genlmsg_cancel(cb_arg->skb, data);
1248        return ret_val;
1249}
1250
1251/**
1252 * netlbl_unlabel_staticlist - Handle a STATICLIST message
1253 * @skb: the NETLINK buffer
1254 * @cb: the NETLINK callback
1255 *
1256 * Description:
1257 * Process a user generated STATICLIST message and dump the unlabeled
1258 * connection hash table in a form suitable for use in a kernel generated
1259 * STATICLIST message.  Returns the length of @skb.
1260 *
1261 */
1262static int netlbl_unlabel_staticlist(struct sk_buff *skb,
1263                                     struct netlink_callback *cb)
1264{
1265        struct netlbl_unlhsh_walk_arg cb_arg;
1266        u32 skip_bkt = cb->args[0];
1267        u32 skip_chain = cb->args[1];
1268        u32 skip_addr4 = cb->args[2];
1269        u32 skip_addr6 = cb->args[3];
1270        u32 iter_bkt;
1271        u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;
1272        struct netlbl_unlhsh_iface *iface;
1273        struct list_head *iter_list;
1274        struct netlbl_af4list *addr4;
1275#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1276        struct netlbl_af6list *addr6;
1277#endif
1278
1279        cb_arg.nl_cb = cb;
1280        cb_arg.skb = skb;
1281        cb_arg.seq = cb->nlh->nlmsg_seq;
1282
1283        rcu_read_lock();
1284        for (iter_bkt = skip_bkt;
1285             iter_bkt < rcu_dereference(netlbl_unlhsh)->size;
1286             iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {
1287                iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];
1288                list_for_each_entry_rcu(iface, iter_list, list) {
1289                        if (!iface->valid ||
1290                            iter_chain++ < skip_chain)
1291                                continue;
1292                        netlbl_af4list_foreach_rcu(addr4,
1293                                                   &iface->addr4_list) {
1294                                if (iter_addr4++ < skip_addr4)
1295                                        continue;
1296                                if (netlbl_unlabel_staticlist_gen(
1297                                              NLBL_UNLABEL_C_STATICLIST,
1298                                              iface,
1299                                              netlbl_unlhsh_addr4_entry(addr4),
1300                                              NULL,
1301                                              &cb_arg) < 0) {
1302                                        iter_addr4--;
1303                                        iter_chain--;
1304                                        goto unlabel_staticlist_return;
1305                                }
1306                        }
1307#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1308                        netlbl_af6list_foreach_rcu(addr6,
1309                                                   &iface->addr6_list) {
1310                                if (iter_addr6++ < skip_addr6)
1311                                        continue;
1312                                if (netlbl_unlabel_staticlist_gen(
1313                                              NLBL_UNLABEL_C_STATICLIST,
1314                                              iface,
1315                                              NULL,
1316                                              netlbl_unlhsh_addr6_entry(addr6),
1317                                              &cb_arg) < 0) {
1318                                        iter_addr6--;
1319                                        iter_chain--;
1320                                        goto unlabel_staticlist_return;
1321                                }
1322                        }
1323#endif /* IPv6 */
1324                }
1325        }
1326
1327unlabel_staticlist_return:
1328        rcu_read_unlock();
1329        cb->args[0] = skip_bkt;
1330        cb->args[1] = skip_chain;
1331        cb->args[2] = skip_addr4;
1332        cb->args[3] = skip_addr6;
1333        return skb->len;
1334}
1335
1336/**
1337 * netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message
1338 * @skb: the NETLINK buffer
1339 * @cb: the NETLINK callback
1340 *
1341 * Description:
1342 * Process a user generated STATICLISTDEF message and dump the default
1343 * unlabeled connection entry in a form suitable for use in a kernel generated
1344 * STATICLISTDEF message.  Returns the length of @skb.
1345 *
1346 */
1347static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
1348                                        struct netlink_callback *cb)
1349{
1350        struct netlbl_unlhsh_walk_arg cb_arg;
1351        struct netlbl_unlhsh_iface *iface;
1352        u32 skip_addr4 = cb->args[0];
1353        u32 skip_addr6 = cb->args[1];
1354        u32 iter_addr4 = 0;
1355        struct netlbl_af4list *addr4;
1356#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1357        u32 iter_addr6 = 0;
1358        struct netlbl_af6list *addr6;
1359#endif
1360
1361        cb_arg.nl_cb = cb;
1362        cb_arg.skb = skb;
1363        cb_arg.seq = cb->nlh->nlmsg_seq;
1364
1365        rcu_read_lock();
1366        iface = rcu_dereference(netlbl_unlhsh_def);
1367        if (iface == NULL || !iface->valid)
1368                goto unlabel_staticlistdef_return;
1369
1370        netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {
1371                if (iter_addr4++ < skip_addr4)
1372                        continue;
1373                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1374                                              iface,
1375                                              netlbl_unlhsh_addr4_entry(addr4),
1376                                              NULL,
1377                                              &cb_arg) < 0) {
1378                        iter_addr4--;
1379                        goto unlabel_staticlistdef_return;
1380                }
1381        }
1382#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1383        netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {
1384                if (iter_addr6++ < skip_addr6)
1385                        continue;
1386                if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,
1387                                              iface,
1388                                              NULL,
1389                                              netlbl_unlhsh_addr6_entry(addr6),
1390                                              &cb_arg) < 0) {
1391                        iter_addr6--;
1392                        goto unlabel_staticlistdef_return;
1393                }
1394        }
1395#endif /* IPv6 */
1396
1397unlabel_staticlistdef_return:
1398        rcu_read_unlock();
1399        cb->args[0] = skip_addr4;
1400        cb->args[1] = skip_addr6;
1401        return skb->len;
1402}
1403
1404/*
1405 * NetLabel Generic NETLINK Command Definitions
1406 */
1407
1408static struct genl_ops netlbl_unlabel_genl_ops[] = {
1409        {
1410        .cmd = NLBL_UNLABEL_C_STATICADD,
1411        .flags = GENL_ADMIN_PERM,
1412        .policy = netlbl_unlabel_genl_policy,
1413        .doit = netlbl_unlabel_staticadd,
1414        .dumpit = NULL,
1415        },
1416        {
1417        .cmd = NLBL_UNLABEL_C_STATICREMOVE,
1418        .flags = GENL_ADMIN_PERM,
1419        .policy = netlbl_unlabel_genl_policy,
1420        .doit = netlbl_unlabel_staticremove,
1421        .dumpit = NULL,
1422        },
1423        {
1424        .cmd = NLBL_UNLABEL_C_STATICLIST,
1425        .flags = 0,
1426        .policy = netlbl_unlabel_genl_policy,
1427        .doit = NULL,
1428        .dumpit = netlbl_unlabel_staticlist,
1429        },
1430        {
1431        .cmd = NLBL_UNLABEL_C_STATICADDDEF,
1432        .flags = GENL_ADMIN_PERM,
1433        .policy = netlbl_unlabel_genl_policy,
1434        .doit = netlbl_unlabel_staticadddef,
1435        .dumpit = NULL,
1436        },
1437        {
1438        .cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,
1439        .flags = GENL_ADMIN_PERM,
1440        .policy = netlbl_unlabel_genl_policy,
1441        .doit = netlbl_unlabel_staticremovedef,
1442        .dumpit = NULL,
1443        },
1444        {
1445        .cmd = NLBL_UNLABEL_C_STATICLISTDEF,
1446        .flags = 0,
1447        .policy = netlbl_unlabel_genl_policy,
1448        .doit = NULL,
1449        .dumpit = netlbl_unlabel_staticlistdef,
1450        },
1451        {
1452        .cmd = NLBL_UNLABEL_C_ACCEPT,
1453        .flags = GENL_ADMIN_PERM,
1454        .policy = netlbl_unlabel_genl_policy,
1455        .doit = netlbl_unlabel_accept,
1456        .dumpit = NULL,
1457        },
1458        {
1459        .cmd = NLBL_UNLABEL_C_LIST,
1460        .flags = 0,
1461        .policy = netlbl_unlabel_genl_policy,
1462        .doit = netlbl_unlabel_list,
1463        .dumpit = NULL,
1464        },
1465};
1466
1467/*
1468 * NetLabel Generic NETLINK Protocol Functions
1469 */
1470
1471/**
1472 * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
1473 *
1474 * Description:
1475 * Register the unlabeled packet NetLabel component with the Generic NETLINK
1476 * mechanism.  Returns zero on success, negative values on failure.
1477 *
1478 */
1479int __init netlbl_unlabel_genl_init(void)
1480{
1481        return genl_register_family_with_ops(&netlbl_unlabel_gnl_family,
1482                netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops));
1483}
1484
1485/*
1486 * NetLabel KAPI Hooks
1487 */
1488
1489static struct notifier_block netlbl_unlhsh_netdev_notifier = {
1490        .notifier_call = netlbl_unlhsh_netdev_handler,
1491};
1492
1493/**
1494 * netlbl_unlabel_init - Initialize the unlabeled connection hash table
1495 * @size: the number of bits to use for the hash buckets
1496 *
1497 * Description:
1498 * Initializes the unlabeled connection hash table and registers a network
1499 * device notification handler.  This function should only be called by the
1500 * NetLabel subsystem itself during initialization.  Returns zero on success,
1501 * non-zero values on error.
1502 *
1503 */
1504int __init netlbl_unlabel_init(u32 size)
1505{
1506        u32 iter;
1507        struct netlbl_unlhsh_tbl *hsh_tbl;
1508
1509        if (size == 0)
1510                return -EINVAL;
1511
1512        hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
1513        if (hsh_tbl == NULL)
1514                return -ENOMEM;
1515        hsh_tbl->size = 1 << size;
1516        hsh_tbl->tbl = kcalloc(hsh_tbl->size,
1517                               sizeof(struct list_head),
1518                               GFP_KERNEL);
1519        if (hsh_tbl->tbl == NULL) {
1520                kfree(hsh_tbl);
1521                return -ENOMEM;
1522        }
1523        for (iter = 0; iter < hsh_tbl->size; iter++)
1524                INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
1525
1526        rcu_read_lock();
1527        spin_lock(&netlbl_unlhsh_lock);
1528        rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
1529        spin_unlock(&netlbl_unlhsh_lock);
1530        rcu_read_unlock();
1531
1532        register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
1533
1534        return 0;
1535}
1536
1537/**
1538 * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
1539 * @skb: the packet
1540 * @family: protocol family
1541 * @secattr: the security attributes
1542 *
1543 * Description:
1544 * Determine the security attributes, if any, for an unlabled packet and return
1545 * them in @secattr.  Returns zero on success and negative values on failure.
1546 *
1547 */
1548int netlbl_unlabel_getattr(const struct sk_buff *skb,
1549                           u16 family,
1550                           struct netlbl_lsm_secattr *secattr)
1551{
1552        struct netlbl_unlhsh_iface *iface;
1553
1554        rcu_read_lock();
1555        iface = netlbl_unlhsh_search_iface_def(skb->iif);
1556        if (iface == NULL)
1557                goto unlabel_getattr_nolabel;
1558        switch (family) {
1559        case PF_INET: {
1560                struct iphdr *hdr4;
1561                struct netlbl_af4list *addr4;
1562
1563                hdr4 = ip_hdr(skb);
1564                addr4 = netlbl_af4list_search(hdr4->saddr,
1565                                              &iface->addr4_list);
1566                if (addr4 == NULL)
1567                        goto unlabel_getattr_nolabel;
1568                secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;
1569                break;
1570        }
1571#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
1572        case PF_INET6: {
1573                struct ipv6hdr *hdr6;
1574                struct netlbl_af6list *addr6;
1575
1576                hdr6 = ipv6_hdr(skb);
1577                addr6 = netlbl_af6list_search(&hdr6->saddr,
1578                                              &iface->addr6_list);
1579                if (addr6 == NULL)
1580                        goto unlabel_getattr_nolabel;
1581                secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;
1582                break;
1583        }
1584#endif /* IPv6 */
1585        default:
1586                goto unlabel_getattr_nolabel;
1587        }
1588        rcu_read_unlock();
1589
1590        secattr->flags |= NETLBL_SECATTR_SECID;
1591        secattr->type = NETLBL_NLTYPE_UNLABELED;
1592        return 0;
1593
1594unlabel_getattr_nolabel:
1595        rcu_read_unlock();
1596        if (netlabel_unlabel_acceptflg == 0)
1597                return -ENOMSG;
1598        secattr->type = NETLBL_NLTYPE_UNLABELED;
1599        return 0;
1600}
1601
1602/**
1603 * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
1604 *
1605 * Description:
1606 * Set the default NetLabel configuration to allow incoming unlabeled packets
1607 * and to send unlabeled network traffic by default.
1608 *
1609 */
1610int __init netlbl_unlabel_defconf(void)
1611{
1612        int ret_val;
1613        struct netlbl_dom_map *entry;
1614        struct netlbl_audit audit_info;
1615
1616        /* Only the kernel is allowed to call this function and the only time
1617         * it is called is at bootup before the audit subsystem is reporting
1618         * messages so don't worry to much about these values. */
1619        security_task_getsecid(current, &audit_info.secid);
1620        audit_info.loginuid = 0;
1621        audit_info.sessionid = 0;
1622
1623        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1624        if (entry == NULL)
1625                return -ENOMEM;
1626        entry->type = NETLBL_NLTYPE_UNLABELED;
1627        ret_val = netlbl_domhsh_add_default(entry, &audit_info);
1628        if (ret_val != 0)
1629                return ret_val;
1630
1631        netlbl_unlabel_acceptflg_set(1, &audit_info);
1632
1633        return 0;
1634}
1635