linux/net/ipv4/cipso_ipv4.c
<<
>>
Prefs
   1/*
   2 * CIPSO - Commercial IP Security Option
   3 *
   4 * This is an implementation of the CIPSO 2.2 protocol as specified in
   5 * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
   6 * FIPS-188.  While CIPSO never became a full IETF RFC standard many vendors
   7 * have chosen to adopt the protocol and over the years it has become a
   8 * de-facto standard for labeled networking.
   9 *
  10 * The CIPSO draft specification can be found in the kernel's Documentation
  11 * directory as well as the following URL:
  12 *   http://tools.ietf.org/id/draft-ietf-cipso-ipsecurity-01.txt
  13 * The FIPS-188 specification can be found at the following URL:
  14 *   http://www.itl.nist.gov/fipspubs/fip188.htm
  15 *
  16 * Author: Paul Moore <paul.moore@hp.com>
  17 *
  18 */
  19
  20/*
  21 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
  22 *
  23 * This program is free software;  you can redistribute it and/or modify
  24 * it under the terms of the GNU General Public License as published by
  25 * the Free Software Foundation; either version 2 of the License, or
  26 * (at your option) any later version.
  27 *
  28 * This program is distributed in the hope that it will be useful,
  29 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
  30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  31 * the GNU General Public License for more details.
  32 *
  33 * You should have received a copy of the GNU General Public License
  34 * along with this program;  if not, write to the Free Software
  35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  36 *
  37 */
  38
  39#include <linux/init.h>
  40#include <linux/types.h>
  41#include <linux/rcupdate.h>
  42#include <linux/list.h>
  43#include <linux/spinlock.h>
  44#include <linux/string.h>
  45#include <linux/jhash.h>
  46#include <linux/audit.h>
  47#include <linux/slab.h>
  48#include <net/ip.h>
  49#include <net/icmp.h>
  50#include <net/tcp.h>
  51#include <net/netlabel.h>
  52#include <net/cipso_ipv4.h>
  53#include <linux/atomic.h>
  54#include <asm/bug.h>
  55#include <asm/unaligned.h>
  56
  57/* List of available DOI definitions */
  58/* XXX - This currently assumes a minimal number of different DOIs in use,
  59 * if in practice there are a lot of different DOIs this list should
  60 * probably be turned into a hash table or something similar so we
  61 * can do quick lookups. */
  62static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
  63static LIST_HEAD(cipso_v4_doi_list);
  64
  65/* Label mapping cache */
  66int cipso_v4_cache_enabled = 1;
  67int cipso_v4_cache_bucketsize = 10;
  68#define CIPSO_V4_CACHE_BUCKETBITS     7
  69#define CIPSO_V4_CACHE_BUCKETS        (1 << CIPSO_V4_CACHE_BUCKETBITS)
  70#define CIPSO_V4_CACHE_REORDERLIMIT   10
  71struct cipso_v4_map_cache_bkt {
  72        spinlock_t lock;
  73        u32 size;
  74        struct list_head list;
  75};
  76struct cipso_v4_map_cache_entry {
  77        u32 hash;
  78        unsigned char *key;
  79        size_t key_len;
  80
  81        struct netlbl_lsm_cache *lsm_data;
  82
  83        u32 activity;
  84        struct list_head list;
  85};
  86static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
  87
  88/* Restricted bitmap (tag #1) flags */
  89int cipso_v4_rbm_optfmt = 0;
  90int cipso_v4_rbm_strictvalid = 1;
  91
  92/*
  93 * Protocol Constants
  94 */
  95
  96/* Maximum size of the CIPSO IP option, derived from the fact that the maximum
  97 * IPv4 header size is 60 bytes and the base IPv4 header is 20 bytes long. */
  98#define CIPSO_V4_OPT_LEN_MAX          40
  99
 100/* Length of the base CIPSO option, this includes the option type (1 byte), the
 101 * option length (1 byte), and the DOI (4 bytes). */
 102#define CIPSO_V4_HDR_LEN              6
 103
 104/* Base length of the restrictive category bitmap tag (tag #1). */
 105#define CIPSO_V4_TAG_RBM_BLEN         4
 106
 107/* Base length of the enumerated category tag (tag #2). */
 108#define CIPSO_V4_TAG_ENUM_BLEN        4
 109
 110/* Base length of the ranged categories bitmap tag (tag #5). */
 111#define CIPSO_V4_TAG_RNG_BLEN         4
 112/* The maximum number of category ranges permitted in the ranged category tag
 113 * (tag #5).  You may note that the IETF draft states that the maximum number
 114 * of category ranges is 7, but if the low end of the last category range is
 115 * zero then it is possible to fit 8 category ranges because the zero should
 116 * be omitted. */
 117#define CIPSO_V4_TAG_RNG_CAT_MAX      8
 118
 119/* Base length of the local tag (non-standard tag).
 120 *  Tag definition (may change between kernel versions)
 121 *
 122 * 0          8          16         24         32
 123 * +----------+----------+----------+----------+
 124 * | 10000000 | 00000110 | 32-bit secid value  |
 125 * +----------+----------+----------+----------+
 126 * | in (host byte order)|
 127 * +----------+----------+
 128 *
 129 */
 130#define CIPSO_V4_TAG_LOC_BLEN         6
 131
 132/*
 133 * Helper Functions
 134 */
 135
 136/**
 137 * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
 138 * @bitmap: the bitmap
 139 * @bitmap_len: length in bits
 140 * @offset: starting offset
 141 * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
 142 *
 143 * Description:
 144 * Starting at @offset, walk the bitmap from left to right until either the
 145 * desired bit is found or we reach the end.  Return the bit offset, -1 if
 146 * not found, or -2 if error.
 147 */
 148static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
 149                                u32 bitmap_len,
 150                                u32 offset,
 151                                u8 state)
 152{
 153        u32 bit_spot;
 154        u32 byte_offset;
 155        unsigned char bitmask;
 156        unsigned char byte;
 157
 158        /* gcc always rounds to zero when doing integer division */
 159        byte_offset = offset / 8;
 160        byte = bitmap[byte_offset];
 161        bit_spot = offset;
 162        bitmask = 0x80 >> (offset % 8);
 163
 164        while (bit_spot < bitmap_len) {
 165                if ((state && (byte & bitmask) == bitmask) ||
 166                    (state == 0 && (byte & bitmask) == 0))
 167                        return bit_spot;
 168
 169                bit_spot++;
 170                bitmask >>= 1;
 171                if (bitmask == 0) {
 172                        byte = bitmap[++byte_offset];
 173                        bitmask = 0x80;
 174                }
 175        }
 176
 177        return -1;
 178}
 179
 180/**
 181 * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
 182 * @bitmap: the bitmap
 183 * @bit: the bit
 184 * @state: if non-zero, set the bit (1) else clear the bit (0)
 185 *
 186 * Description:
 187 * Set a single bit in the bitmask.  Returns zero on success, negative values
 188 * on error.
 189 */
 190static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
 191                                   u32 bit,
 192                                   u8 state)
 193{
 194        u32 byte_spot;
 195        u8 bitmask;
 196
 197        /* gcc always rounds to zero when doing integer division */
 198        byte_spot = bit / 8;
 199        bitmask = 0x80 >> (bit % 8);
 200        if (state)
 201                bitmap[byte_spot] |= bitmask;
 202        else
 203                bitmap[byte_spot] &= ~bitmask;
 204}
 205
 206/**
 207 * cipso_v4_cache_entry_free - Frees a cache entry
 208 * @entry: the entry to free
 209 *
 210 * Description:
 211 * This function frees the memory associated with a cache entry including the
 212 * LSM cache data if there are no longer any users, i.e. reference count == 0.
 213 *
 214 */
 215static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
 216{
 217        if (entry->lsm_data)
 218                netlbl_secattr_cache_free(entry->lsm_data);
 219        kfree(entry->key);
 220        kfree(entry);
 221}
 222
 223/**
 224 * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
 225 * @key: the hash key
 226 * @key_len: the length of the key in bytes
 227 *
 228 * Description:
 229 * The CIPSO tag hashing function.  Returns a 32-bit hash value.
 230 *
 231 */
 232static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len)
 233{
 234        return jhash(key, key_len, 0);
 235}
 236
 237/*
 238 * Label Mapping Cache Functions
 239 */
 240
 241/**
 242 * cipso_v4_cache_init - Initialize the CIPSO cache
 243 *
 244 * Description:
 245 * Initializes the CIPSO label mapping cache, this function should be called
 246 * before any of the other functions defined in this file.  Returns zero on
 247 * success, negative values on error.
 248 *
 249 */
 250static int cipso_v4_cache_init(void)
 251{
 252        u32 iter;
 253
 254        cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,
 255                                 sizeof(struct cipso_v4_map_cache_bkt),
 256                                 GFP_KERNEL);
 257        if (cipso_v4_cache == NULL)
 258                return -ENOMEM;
 259
 260        for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
 261                spin_lock_init(&cipso_v4_cache[iter].lock);
 262                cipso_v4_cache[iter].size = 0;
 263                INIT_LIST_HEAD(&cipso_v4_cache[iter].list);
 264        }
 265
 266        return 0;
 267}
 268
 269/**
 270 * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
 271 *
 272 * Description:
 273 * Invalidates and frees any entries in the CIPSO cache.  Returns zero on
 274 * success and negative values on failure.
 275 *
 276 */
 277void cipso_v4_cache_invalidate(void)
 278{
 279        struct cipso_v4_map_cache_entry *entry, *tmp_entry;
 280        u32 iter;
 281
 282        for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
 283                spin_lock_bh(&cipso_v4_cache[iter].lock);
 284                list_for_each_entry_safe(entry,
 285                                         tmp_entry,
 286                                         &cipso_v4_cache[iter].list, list) {
 287                        list_del(&entry->list);
 288                        cipso_v4_cache_entry_free(entry);
 289                }
 290                cipso_v4_cache[iter].size = 0;
 291                spin_unlock_bh(&cipso_v4_cache[iter].lock);
 292        }
 293}
 294
 295/**
 296 * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
 297 * @key: the buffer to check
 298 * @key_len: buffer length in bytes
 299 * @secattr: the security attribute struct to use
 300 *
 301 * Description:
 302 * This function checks the cache to see if a label mapping already exists for
 303 * the given key.  If there is a match then the cache is adjusted and the
 304 * @secattr struct is populated with the correct LSM security attributes.  The
 305 * cache is adjusted in the following manner if the entry is not already the
 306 * first in the cache bucket:
 307 *
 308 *  1. The cache entry's activity counter is incremented
 309 *  2. The previous (higher ranking) entry's activity counter is decremented
 310 *  3. If the difference between the two activity counters is geater than
 311 *     CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
 312 *
 313 * Returns zero on success, -ENOENT for a cache miss, and other negative values
 314 * on error.
 315 *
 316 */
 317static int cipso_v4_cache_check(const unsigned char *key,
 318                                u32 key_len,
 319                                struct netlbl_lsm_secattr *secattr)
 320{
 321        u32 bkt;
 322        struct cipso_v4_map_cache_entry *entry;
 323        struct cipso_v4_map_cache_entry *prev_entry = NULL;
 324        u32 hash;
 325
 326        if (!cipso_v4_cache_enabled)
 327                return -ENOENT;
 328
 329        hash = cipso_v4_map_cache_hash(key, key_len);
 330        bkt = hash & (CIPSO_V4_CACHE_BUCKETS - 1);
 331        spin_lock_bh(&cipso_v4_cache[bkt].lock);
 332        list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
 333                if (entry->hash == hash &&
 334                    entry->key_len == key_len &&
 335                    memcmp(entry->key, key, key_len) == 0) {
 336                        entry->activity += 1;
 337                        atomic_inc(&entry->lsm_data->refcount);
 338                        secattr->cache = entry->lsm_data;
 339                        secattr->flags |= NETLBL_SECATTR_CACHE;
 340                        secattr->type = NETLBL_NLTYPE_CIPSOV4;
 341                        if (prev_entry == NULL) {
 342                                spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 343                                return 0;
 344                        }
 345
 346                        if (prev_entry->activity > 0)
 347                                prev_entry->activity -= 1;
 348                        if (entry->activity > prev_entry->activity &&
 349                            entry->activity - prev_entry->activity >
 350                            CIPSO_V4_CACHE_REORDERLIMIT) {
 351                                __list_del(entry->list.prev, entry->list.next);
 352                                __list_add(&entry->list,
 353                                           prev_entry->list.prev,
 354                                           &prev_entry->list);
 355                        }
 356
 357                        spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 358                        return 0;
 359                }
 360                prev_entry = entry;
 361        }
 362        spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 363
 364        return -ENOENT;
 365}
 366
 367/**
 368 * cipso_v4_cache_add - Add an entry to the CIPSO cache
 369 * @skb: the packet
 370 * @secattr: the packet's security attributes
 371 *
 372 * Description:
 373 * Add a new entry into the CIPSO label mapping cache.  Add the new entry to
 374 * head of the cache bucket's list, if the cache bucket is out of room remove
 375 * the last entry in the list first.  It is important to note that there is
 376 * currently no checking for duplicate keys.  Returns zero on success,
 377 * negative values on failure.
 378 *
 379 */
 380int cipso_v4_cache_add(const struct sk_buff *skb,
 381                       const struct netlbl_lsm_secattr *secattr)
 382{
 383        int ret_val = -EPERM;
 384        u32 bkt;
 385        struct cipso_v4_map_cache_entry *entry = NULL;
 386        struct cipso_v4_map_cache_entry *old_entry = NULL;
 387        unsigned char *cipso_ptr;
 388        u32 cipso_ptr_len;
 389
 390        if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
 391                return 0;
 392
 393        cipso_ptr = CIPSO_V4_OPTPTR(skb);
 394        cipso_ptr_len = cipso_ptr[1];
 395
 396        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 397        if (entry == NULL)
 398                return -ENOMEM;
 399        entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC);
 400        if (entry->key == NULL) {
 401                ret_val = -ENOMEM;
 402                goto cache_add_failure;
 403        }
 404        entry->key_len = cipso_ptr_len;
 405        entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
 406        atomic_inc(&secattr->cache->refcount);
 407        entry->lsm_data = secattr->cache;
 408
 409        bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
 410        spin_lock_bh(&cipso_v4_cache[bkt].lock);
 411        if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
 412                list_add(&entry->list, &cipso_v4_cache[bkt].list);
 413                cipso_v4_cache[bkt].size += 1;
 414        } else {
 415                old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
 416                                       struct cipso_v4_map_cache_entry, list);
 417                list_del(&old_entry->list);
 418                list_add(&entry->list, &cipso_v4_cache[bkt].list);
 419                cipso_v4_cache_entry_free(old_entry);
 420        }
 421        spin_unlock_bh(&cipso_v4_cache[bkt].lock);
 422
 423        return 0;
 424
 425cache_add_failure:
 426        if (entry)
 427                cipso_v4_cache_entry_free(entry);
 428        return ret_val;
 429}
 430
 431/*
 432 * DOI List Functions
 433 */
 434
 435/**
 436 * cipso_v4_doi_search - Searches for a DOI definition
 437 * @doi: the DOI to search for
 438 *
 439 * Description:
 440 * Search the DOI definition list for a DOI definition with a DOI value that
 441 * matches @doi.  The caller is responsible for calling rcu_read_[un]lock().
 442 * Returns a pointer to the DOI definition on success and NULL on failure.
 443 */
 444static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
 445{
 446        struct cipso_v4_doi *iter;
 447
 448        list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
 449                if (iter->doi == doi && atomic_read(&iter->refcount))
 450                        return iter;
 451        return NULL;
 452}
 453
 454/**
 455 * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
 456 * @doi_def: the DOI structure
 457 * @audit_info: NetLabel audit information
 458 *
 459 * Description:
 460 * The caller defines a new DOI for use by the CIPSO engine and calls this
 461 * function to add it to the list of acceptable domains.  The caller must
 462 * ensure that the mapping table specified in @doi_def->map meets all of the
 463 * requirements of the mapping type (see cipso_ipv4.h for details).  Returns
 464 * zero on success and non-zero on failure.
 465 *
 466 */
 467int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
 468                     struct netlbl_audit *audit_info)
 469{
 470        int ret_val = -EINVAL;
 471        u32 iter;
 472        u32 doi;
 473        u32 doi_type;
 474        struct audit_buffer *audit_buf;
 475
 476        doi = doi_def->doi;
 477        doi_type = doi_def->type;
 478
 479        if (doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
 480                goto doi_add_return;
 481        for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
 482                switch (doi_def->tags[iter]) {
 483                case CIPSO_V4_TAG_RBITMAP:
 484                        break;
 485                case CIPSO_V4_TAG_RANGE:
 486                case CIPSO_V4_TAG_ENUM:
 487                        if (doi_def->type != CIPSO_V4_MAP_PASS)
 488                                goto doi_add_return;
 489                        break;
 490                case CIPSO_V4_TAG_LOCAL:
 491                        if (doi_def->type != CIPSO_V4_MAP_LOCAL)
 492                                goto doi_add_return;
 493                        break;
 494                case CIPSO_V4_TAG_INVALID:
 495                        if (iter == 0)
 496                                goto doi_add_return;
 497                        break;
 498                default:
 499                        goto doi_add_return;
 500                }
 501        }
 502
 503        atomic_set(&doi_def->refcount, 1);
 504
 505        spin_lock(&cipso_v4_doi_list_lock);
 506        if (cipso_v4_doi_search(doi_def->doi) != NULL) {
 507                spin_unlock(&cipso_v4_doi_list_lock);
 508                ret_val = -EEXIST;
 509                goto doi_add_return;
 510        }
 511        list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
 512        spin_unlock(&cipso_v4_doi_list_lock);
 513        ret_val = 0;
 514
 515doi_add_return:
 516        audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info);
 517        if (audit_buf != NULL) {
 518                const char *type_str;
 519                switch (doi_type) {
 520                case CIPSO_V4_MAP_TRANS:
 521                        type_str = "trans";
 522                        break;
 523                case CIPSO_V4_MAP_PASS:
 524                        type_str = "pass";
 525                        break;
 526                case CIPSO_V4_MAP_LOCAL:
 527                        type_str = "local";
 528                        break;
 529                default:
 530                        type_str = "(unknown)";
 531                }
 532                audit_log_format(audit_buf,
 533                                 " cipso_doi=%u cipso_type=%s res=%u",
 534                                 doi, type_str, ret_val == 0 ? 1 : 0);
 535                audit_log_end(audit_buf);
 536        }
 537
 538        return ret_val;
 539}
 540
 541/**
 542 * cipso_v4_doi_free - Frees a DOI definition
 543 * @entry: the entry's RCU field
 544 *
 545 * Description:
 546 * This function frees all of the memory associated with a DOI definition.
 547 *
 548 */
 549void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
 550{
 551        if (doi_def == NULL)
 552                return;
 553
 554        switch (doi_def->type) {
 555        case CIPSO_V4_MAP_TRANS:
 556                kfree(doi_def->map.std->lvl.cipso);
 557                kfree(doi_def->map.std->lvl.local);
 558                kfree(doi_def->map.std->cat.cipso);
 559                kfree(doi_def->map.std->cat.local);
 560                break;
 561        }
 562        kfree(doi_def);
 563}
 564
 565/**
 566 * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
 567 * @entry: the entry's RCU field
 568 *
 569 * Description:
 570 * This function is designed to be used as a callback to the call_rcu()
 571 * function so that the memory allocated to the DOI definition can be released
 572 * safely.
 573 *
 574 */
 575static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
 576{
 577        struct cipso_v4_doi *doi_def;
 578
 579        doi_def = container_of(entry, struct cipso_v4_doi, rcu);
 580        cipso_v4_doi_free(doi_def);
 581}
 582
 583/**
 584 * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
 585 * @doi: the DOI value
 586 * @audit_secid: the LSM secid to use in the audit message
 587 *
 588 * Description:
 589 * Removes a DOI definition from the CIPSO engine.  The NetLabel routines will
 590 * be called to release their own LSM domain mappings as well as our own
 591 * domain list.  Returns zero on success and negative values on failure.
 592 *
 593 */
 594int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
 595{
 596        int ret_val;
 597        struct cipso_v4_doi *doi_def;
 598        struct audit_buffer *audit_buf;
 599
 600        spin_lock(&cipso_v4_doi_list_lock);
 601        doi_def = cipso_v4_doi_search(doi);
 602        if (doi_def == NULL) {
 603                spin_unlock(&cipso_v4_doi_list_lock);
 604                ret_val = -ENOENT;
 605                goto doi_remove_return;
 606        }
 607        if (!atomic_dec_and_test(&doi_def->refcount)) {
 608                spin_unlock(&cipso_v4_doi_list_lock);
 609                ret_val = -EBUSY;
 610                goto doi_remove_return;
 611        }
 612        list_del_rcu(&doi_def->list);
 613        spin_unlock(&cipso_v4_doi_list_lock);
 614
 615        cipso_v4_cache_invalidate();
 616        call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
 617        ret_val = 0;
 618
 619doi_remove_return:
 620        audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info);
 621        if (audit_buf != NULL) {
 622                audit_log_format(audit_buf,
 623                                 " cipso_doi=%u res=%u",
 624                                 doi, ret_val == 0 ? 1 : 0);
 625                audit_log_end(audit_buf);
 626        }
 627
 628        return ret_val;
 629}
 630
 631/**
 632 * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition
 633 * @doi: the DOI value
 634 *
 635 * Description:
 636 * Searches for a valid DOI definition and if one is found it is returned to
 637 * the caller.  Otherwise NULL is returned.  The caller must ensure that
 638 * rcu_read_lock() is held while accessing the returned definition and the DOI
 639 * definition reference count is decremented when the caller is done.
 640 *
 641 */
 642struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
 643{
 644        struct cipso_v4_doi *doi_def;
 645
 646        rcu_read_lock();
 647        doi_def = cipso_v4_doi_search(doi);
 648        if (doi_def == NULL)
 649                goto doi_getdef_return;
 650        if (!atomic_inc_not_zero(&doi_def->refcount))
 651                doi_def = NULL;
 652
 653doi_getdef_return:
 654        rcu_read_unlock();
 655        return doi_def;
 656}
 657
 658/**
 659 * cipso_v4_doi_putdef - Releases a reference for the given DOI definition
 660 * @doi_def: the DOI definition
 661 *
 662 * Description:
 663 * Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
 664 *
 665 */
 666void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def)
 667{
 668        if (doi_def == NULL)
 669                return;
 670
 671        if (!atomic_dec_and_test(&doi_def->refcount))
 672                return;
 673        spin_lock(&cipso_v4_doi_list_lock);
 674        list_del_rcu(&doi_def->list);
 675        spin_unlock(&cipso_v4_doi_list_lock);
 676
 677        cipso_v4_cache_invalidate();
 678        call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
 679}
 680
 681/**
 682 * cipso_v4_doi_walk - Iterate through the DOI definitions
 683 * @skip_cnt: skip past this number of DOI definitions, updated
 684 * @callback: callback for each DOI definition
 685 * @cb_arg: argument for the callback function
 686 *
 687 * Description:
 688 * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
 689 * For each entry call @callback, if @callback returns a negative value stop
 690 * 'walking' through the list and return.  Updates the value in @skip_cnt upon
 691 * return.  Returns zero on success, negative values on failure.
 692 *
 693 */
 694int cipso_v4_doi_walk(u32 *skip_cnt,
 695                     int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
 696                     void *cb_arg)
 697{
 698        int ret_val = -ENOENT;
 699        u32 doi_cnt = 0;
 700        struct cipso_v4_doi *iter_doi;
 701
 702        rcu_read_lock();
 703        list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
 704                if (atomic_read(&iter_doi->refcount) > 0) {
 705                        if (doi_cnt++ < *skip_cnt)
 706                                continue;
 707                        ret_val = callback(iter_doi, cb_arg);
 708                        if (ret_val < 0) {
 709                                doi_cnt--;
 710                                goto doi_walk_return;
 711                        }
 712                }
 713
 714doi_walk_return:
 715        rcu_read_unlock();
 716        *skip_cnt = doi_cnt;
 717        return ret_val;
 718}
 719
 720/*
 721 * Label Mapping Functions
 722 */
 723
 724/**
 725 * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
 726 * @doi_def: the DOI definition
 727 * @level: the level to check
 728 *
 729 * Description:
 730 * Checks the given level against the given DOI definition and returns a
 731 * negative value if the level does not have a valid mapping and a zero value
 732 * if the level is defined by the DOI.
 733 *
 734 */
 735static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
 736{
 737        switch (doi_def->type) {
 738        case CIPSO_V4_MAP_PASS:
 739                return 0;
 740        case CIPSO_V4_MAP_TRANS:
 741                if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
 742                        return 0;
 743                break;
 744        }
 745
 746        return -EFAULT;
 747}
 748
 749/**
 750 * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
 751 * @doi_def: the DOI definition
 752 * @host_lvl: the host MLS level
 753 * @net_lvl: the network/CIPSO MLS level
 754 *
 755 * Description:
 756 * Perform a label mapping to translate a local MLS level to the correct
 757 * CIPSO level using the given DOI definition.  Returns zero on success,
 758 * negative values otherwise.
 759 *
 760 */
 761static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
 762                                 u32 host_lvl,
 763                                 u32 *net_lvl)
 764{
 765        switch (doi_def->type) {
 766        case CIPSO_V4_MAP_PASS:
 767                *net_lvl = host_lvl;
 768                return 0;
 769        case CIPSO_V4_MAP_TRANS:
 770                if (host_lvl < doi_def->map.std->lvl.local_size &&
 771                    doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) {
 772                        *net_lvl = doi_def->map.std->lvl.local[host_lvl];
 773                        return 0;
 774                }
 775                return -EPERM;
 776        }
 777
 778        return -EINVAL;
 779}
 780
 781/**
 782 * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
 783 * @doi_def: the DOI definition
 784 * @net_lvl: the network/CIPSO MLS level
 785 * @host_lvl: the host MLS level
 786 *
 787 * Description:
 788 * Perform a label mapping to translate a CIPSO level to the correct local MLS
 789 * level using the given DOI definition.  Returns zero on success, negative
 790 * values otherwise.
 791 *
 792 */
 793static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
 794                                 u32 net_lvl,
 795                                 u32 *host_lvl)
 796{
 797        struct cipso_v4_std_map_tbl *map_tbl;
 798
 799        switch (doi_def->type) {
 800        case CIPSO_V4_MAP_PASS:
 801                *host_lvl = net_lvl;
 802                return 0;
 803        case CIPSO_V4_MAP_TRANS:
 804                map_tbl = doi_def->map.std;
 805                if (net_lvl < map_tbl->lvl.cipso_size &&
 806                    map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
 807                        *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
 808                        return 0;
 809                }
 810                return -EPERM;
 811        }
 812
 813        return -EINVAL;
 814}
 815
 816/**
 817 * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
 818 * @doi_def: the DOI definition
 819 * @bitmap: category bitmap
 820 * @bitmap_len: bitmap length in bytes
 821 *
 822 * Description:
 823 * Checks the given category bitmap against the given DOI definition and
 824 * returns a negative value if any of the categories in the bitmap do not have
 825 * a valid mapping and a zero value if all of the categories are valid.
 826 *
 827 */
 828static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
 829                                      const unsigned char *bitmap,
 830                                      u32 bitmap_len)
 831{
 832        int cat = -1;
 833        u32 bitmap_len_bits = bitmap_len * 8;
 834        u32 cipso_cat_size;
 835        u32 *cipso_array;
 836
 837        switch (doi_def->type) {
 838        case CIPSO_V4_MAP_PASS:
 839                return 0;
 840        case CIPSO_V4_MAP_TRANS:
 841                cipso_cat_size = doi_def->map.std->cat.cipso_size;
 842                cipso_array = doi_def->map.std->cat.cipso;
 843                for (;;) {
 844                        cat = cipso_v4_bitmap_walk(bitmap,
 845                                                   bitmap_len_bits,
 846                                                   cat + 1,
 847                                                   1);
 848                        if (cat < 0)
 849                                break;
 850                        if (cat >= cipso_cat_size ||
 851                            cipso_array[cat] >= CIPSO_V4_INV_CAT)
 852                                return -EFAULT;
 853                }
 854
 855                if (cat == -1)
 856                        return 0;
 857                break;
 858        }
 859
 860        return -EFAULT;
 861}
 862
 863/**
 864 * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
 865 * @doi_def: the DOI definition
 866 * @secattr: the security attributes
 867 * @net_cat: the zero'd out category bitmap in network/CIPSO format
 868 * @net_cat_len: the length of the CIPSO bitmap in bytes
 869 *
 870 * Description:
 871 * Perform a label mapping to translate a local MLS category bitmap to the
 872 * correct CIPSO bitmap using the given DOI definition.  Returns the minimum
 873 * size in bytes of the network bitmap on success, negative values otherwise.
 874 *
 875 */
 876static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
 877                                     const struct netlbl_lsm_secattr *secattr,
 878                                     unsigned char *net_cat,
 879                                     u32 net_cat_len)
 880{
 881        int host_spot = -1;
 882        u32 net_spot = CIPSO_V4_INV_CAT;
 883        u32 net_spot_max = 0;
 884        u32 net_clen_bits = net_cat_len * 8;
 885        u32 host_cat_size = 0;
 886        u32 *host_cat_array = NULL;
 887
 888        if (doi_def->type == CIPSO_V4_MAP_TRANS) {
 889                host_cat_size = doi_def->map.std->cat.local_size;
 890                host_cat_array = doi_def->map.std->cat.local;
 891        }
 892
 893        for (;;) {
 894                host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
 895                                                       host_spot + 1);
 896                if (host_spot < 0)
 897                        break;
 898
 899                switch (doi_def->type) {
 900                case CIPSO_V4_MAP_PASS:
 901                        net_spot = host_spot;
 902                        break;
 903                case CIPSO_V4_MAP_TRANS:
 904                        if (host_spot >= host_cat_size)
 905                                return -EPERM;
 906                        net_spot = host_cat_array[host_spot];
 907                        if (net_spot >= CIPSO_V4_INV_CAT)
 908                                return -EPERM;
 909                        break;
 910                }
 911                if (net_spot >= net_clen_bits)
 912                        return -ENOSPC;
 913                cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
 914
 915                if (net_spot > net_spot_max)
 916                        net_spot_max = net_spot;
 917        }
 918
 919        if (++net_spot_max % 8)
 920                return net_spot_max / 8 + 1;
 921        return net_spot_max / 8;
 922}
 923
 924/**
 925 * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
 926 * @doi_def: the DOI definition
 927 * @net_cat: the category bitmap in network/CIPSO format
 928 * @net_cat_len: the length of the CIPSO bitmap in bytes
 929 * @secattr: the security attributes
 930 *
 931 * Description:
 932 * Perform a label mapping to translate a CIPSO bitmap to the correct local
 933 * MLS category bitmap using the given DOI definition.  Returns zero on
 934 * success, negative values on failure.
 935 *
 936 */
 937static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
 938                                     const unsigned char *net_cat,
 939                                     u32 net_cat_len,
 940                                     struct netlbl_lsm_secattr *secattr)
 941{
 942        int ret_val;
 943        int net_spot = -1;
 944        u32 host_spot = CIPSO_V4_INV_CAT;
 945        u32 net_clen_bits = net_cat_len * 8;
 946        u32 net_cat_size = 0;
 947        u32 *net_cat_array = NULL;
 948
 949        if (doi_def->type == CIPSO_V4_MAP_TRANS) {
 950                net_cat_size = doi_def->map.std->cat.cipso_size;
 951                net_cat_array = doi_def->map.std->cat.cipso;
 952        }
 953
 954        for (;;) {
 955                net_spot = cipso_v4_bitmap_walk(net_cat,
 956                                                net_clen_bits,
 957                                                net_spot + 1,
 958                                                1);
 959                if (net_spot < 0) {
 960                        if (net_spot == -2)
 961                                return -EFAULT;
 962                        return 0;
 963                }
 964
 965                switch (doi_def->type) {
 966                case CIPSO_V4_MAP_PASS:
 967                        host_spot = net_spot;
 968                        break;
 969                case CIPSO_V4_MAP_TRANS:
 970                        if (net_spot >= net_cat_size)
 971                                return -EPERM;
 972                        host_spot = net_cat_array[net_spot];
 973                        if (host_spot >= CIPSO_V4_INV_CAT)
 974                                return -EPERM;
 975                        break;
 976                }
 977                ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
 978                                                       host_spot,
 979                                                       GFP_ATOMIC);
 980                if (ret_val != 0)
 981                        return ret_val;
 982        }
 983
 984        return -EINVAL;
 985}
 986
 987/**
 988 * cipso_v4_map_cat_enum_valid - Checks to see if the categories are valid
 989 * @doi_def: the DOI definition
 990 * @enumcat: category list
 991 * @enumcat_len: length of the category list in bytes
 992 *
 993 * Description:
 994 * Checks the given categories against the given DOI definition and returns a
 995 * negative value if any of the categories do not have a valid mapping and a
 996 * zero value if all of the categories are valid.
 997 *
 998 */
 999static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def,
1000                                       const unsigned char *enumcat,
1001                                       u32 enumcat_len)
1002{
1003        u16 cat;
1004        int cat_prev = -1;
1005        u32 iter;
1006
1007        if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01)
1008                return -EFAULT;
1009
1010        for (iter = 0; iter < enumcat_len; iter += 2) {
1011                cat = get_unaligned_be16(&enumcat[iter]);
1012                if (cat <= cat_prev)
1013                        return -EFAULT;
1014                cat_prev = cat;
1015        }
1016
1017        return 0;
1018}
1019
1020/**
1021 * cipso_v4_map_cat_enum_hton - Perform a category mapping from host to network
1022 * @doi_def: the DOI definition
1023 * @secattr: the security attributes
1024 * @net_cat: the zero'd out category list in network/CIPSO format
1025 * @net_cat_len: the length of the CIPSO category list in bytes
1026 *
1027 * Description:
1028 * Perform a label mapping to translate a local MLS category bitmap to the
1029 * correct CIPSO category list using the given DOI definition.   Returns the
1030 * size in bytes of the network category bitmap on success, negative values
1031 * otherwise.
1032 *
1033 */
1034static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
1035                                      const struct netlbl_lsm_secattr *secattr,
1036                                      unsigned char *net_cat,
1037                                      u32 net_cat_len)
1038{
1039        int cat = -1;
1040        u32 cat_iter = 0;
1041
1042        for (;;) {
1043                cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
1044                                                 cat + 1);
1045                if (cat < 0)
1046                        break;
1047                if ((cat_iter + 2) > net_cat_len)
1048                        return -ENOSPC;
1049
1050                *((__be16 *)&net_cat[cat_iter]) = htons(cat);
1051                cat_iter += 2;
1052        }
1053
1054        return cat_iter;
1055}
1056
1057/**
1058 * cipso_v4_map_cat_enum_ntoh - Perform a category mapping from network to host
1059 * @doi_def: the DOI definition
1060 * @net_cat: the category list in network/CIPSO format
1061 * @net_cat_len: the length of the CIPSO bitmap in bytes
1062 * @secattr: the security attributes
1063 *
1064 * Description:
1065 * Perform a label mapping to translate a CIPSO category list to the correct
1066 * local MLS category bitmap using the given DOI definition.  Returns zero on
1067 * success, negative values on failure.
1068 *
1069 */
1070static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
1071                                      const unsigned char *net_cat,
1072                                      u32 net_cat_len,
1073                                      struct netlbl_lsm_secattr *secattr)
1074{
1075        int ret_val;
1076        u32 iter;
1077
1078        for (iter = 0; iter < net_cat_len; iter += 2) {
1079                ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
1080                                get_unaligned_be16(&net_cat[iter]),
1081                                GFP_ATOMIC);
1082                if (ret_val != 0)
1083                        return ret_val;
1084        }
1085
1086        return 0;
1087}
1088
1089/**
1090 * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid
1091 * @doi_def: the DOI definition
1092 * @rngcat: category list
1093 * @rngcat_len: length of the category list in bytes
1094 *
1095 * Description:
1096 * Checks the given categories against the given DOI definition and returns a
1097 * negative value if any of the categories do not have a valid mapping and a
1098 * zero value if all of the categories are valid.
1099 *
1100 */
1101static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def,
1102                                      const unsigned char *rngcat,
1103                                      u32 rngcat_len)
1104{
1105        u16 cat_high;
1106        u16 cat_low;
1107        u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1;
1108        u32 iter;
1109
1110        if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01)
1111                return -EFAULT;
1112
1113        for (iter = 0; iter < rngcat_len; iter += 4) {
1114                cat_high = get_unaligned_be16(&rngcat[iter]);
1115                if ((iter + 4) <= rngcat_len)
1116                        cat_low = get_unaligned_be16(&rngcat[iter + 2]);
1117                else
1118                        cat_low = 0;
1119
1120                if (cat_high > cat_prev)
1121                        return -EFAULT;
1122
1123                cat_prev = cat_low;
1124        }
1125
1126        return 0;
1127}
1128
1129/**
1130 * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network
1131 * @doi_def: the DOI definition
1132 * @secattr: the security attributes
1133 * @net_cat: the zero'd out category list in network/CIPSO format
1134 * @net_cat_len: the length of the CIPSO category list in bytes
1135 *
1136 * Description:
1137 * Perform a label mapping to translate a local MLS category bitmap to the
1138 * correct CIPSO category list using the given DOI definition.   Returns the
1139 * size in bytes of the network category bitmap on success, negative values
1140 * otherwise.
1141 *
1142 */
1143static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
1144                                     const struct netlbl_lsm_secattr *secattr,
1145                                     unsigned char *net_cat,
1146                                     u32 net_cat_len)
1147{
1148        int iter = -1;
1149        u16 array[CIPSO_V4_TAG_RNG_CAT_MAX * 2];
1150        u32 array_cnt = 0;
1151        u32 cat_size = 0;
1152
1153        /* make sure we don't overflow the 'array[]' variable */
1154        if (net_cat_len >
1155            (CIPSO_V4_OPT_LEN_MAX - CIPSO_V4_HDR_LEN - CIPSO_V4_TAG_RNG_BLEN))
1156                return -ENOSPC;
1157
1158        for (;;) {
1159                iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
1160                                                  iter + 1);
1161                if (iter < 0)
1162                        break;
1163                cat_size += (iter == 0 ? 0 : sizeof(u16));
1164                if (cat_size > net_cat_len)
1165                        return -ENOSPC;
1166                array[array_cnt++] = iter;
1167
1168                iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat,
1169                                                      iter);
1170                if (iter < 0)
1171                        return -EFAULT;
1172                cat_size += sizeof(u16);
1173                if (cat_size > net_cat_len)
1174                        return -ENOSPC;
1175                array[array_cnt++] = iter;
1176        }
1177
1178        for (iter = 0; array_cnt > 0;) {
1179                *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]);
1180                iter += 2;
1181                array_cnt--;
1182                if (array[array_cnt] != 0) {
1183                        *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]);
1184                        iter += 2;
1185                }
1186        }
1187
1188        return cat_size;
1189}
1190
1191/**
1192 * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host
1193 * @doi_def: the DOI definition
1194 * @net_cat: the category list in network/CIPSO format
1195 * @net_cat_len: the length of the CIPSO bitmap in bytes
1196 * @secattr: the security attributes
1197 *
1198 * Description:
1199 * Perform a label mapping to translate a CIPSO category list to the correct
1200 * local MLS category bitmap using the given DOI definition.  Returns zero on
1201 * success, negative values on failure.
1202 *
1203 */
1204static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
1205                                     const unsigned char *net_cat,
1206                                     u32 net_cat_len,
1207                                     struct netlbl_lsm_secattr *secattr)
1208{
1209        int ret_val;
1210        u32 net_iter;
1211        u16 cat_low;
1212        u16 cat_high;
1213
1214        for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
1215                cat_high = get_unaligned_be16(&net_cat[net_iter]);
1216                if ((net_iter + 4) <= net_cat_len)
1217                        cat_low = get_unaligned_be16(&net_cat[net_iter + 2]);
1218                else
1219                        cat_low = 0;
1220
1221                ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat,
1222                                                       cat_low,
1223                                                       cat_high,
1224                                                       GFP_ATOMIC);
1225                if (ret_val != 0)
1226                        return ret_val;
1227        }
1228
1229        return 0;
1230}
1231
1232/*
1233 * Protocol Handling Functions
1234 */
1235
1236/**
1237 * cipso_v4_gentag_hdr - Generate a CIPSO option header
1238 * @doi_def: the DOI definition
1239 * @len: the total tag length in bytes, not including this header
1240 * @buf: the CIPSO option buffer
1241 *
1242 * Description:
1243 * Write a CIPSO header into the beginning of @buffer.
1244 *
1245 */
1246static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
1247                                unsigned char *buf,
1248                                u32 len)
1249{
1250        buf[0] = IPOPT_CIPSO;
1251        buf[1] = CIPSO_V4_HDR_LEN + len;
1252        *(__be32 *)&buf[2] = htonl(doi_def->doi);
1253}
1254
1255/**
1256 * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
1257 * @doi_def: the DOI definition
1258 * @secattr: the security attributes
1259 * @buffer: the option buffer
1260 * @buffer_len: length of buffer in bytes
1261 *
1262 * Description:
1263 * Generate a CIPSO option using the restricted bitmap tag, tag type #1.  The
1264 * actual buffer length may be larger than the indicated size due to
1265 * translation between host and network category bitmaps.  Returns the size of
1266 * the tag on success, negative values on failure.
1267 *
1268 */
1269static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
1270                               const struct netlbl_lsm_secattr *secattr,
1271                               unsigned char *buffer,
1272                               u32 buffer_len)
1273{
1274        int ret_val;
1275        u32 tag_len;
1276        u32 level;
1277
1278        if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
1279                return -EPERM;
1280
1281        ret_val = cipso_v4_map_lvl_hton(doi_def,
1282                                        secattr->attr.mls.lvl,
1283                                        &level);
1284        if (ret_val != 0)
1285                return ret_val;
1286
1287        if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1288                ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
1289                                                    secattr,
1290                                                    &buffer[4],
1291                                                    buffer_len - 4);
1292                if (ret_val < 0)
1293                        return ret_val;
1294
1295                /* This will send packets using the "optimized" format when
1296                 * possible as specified in  section 3.4.2.6 of the
1297                 * CIPSO draft. */
1298                if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
1299                        tag_len = 14;
1300                else
1301                        tag_len = 4 + ret_val;
1302        } else
1303                tag_len = 4;
1304
1305        buffer[0] = CIPSO_V4_TAG_RBITMAP;
1306        buffer[1] = tag_len;
1307        buffer[3] = level;
1308
1309        return tag_len;
1310}
1311
1312/**
1313 * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
1314 * @doi_def: the DOI definition
1315 * @tag: the CIPSO tag
1316 * @secattr: the security attributes
1317 *
1318 * Description:
1319 * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
1320 * attributes in @secattr.  Return zero on success, negatives values on
1321 * failure.
1322 *
1323 */
1324static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1325                                 const unsigned char *tag,
1326                                 struct netlbl_lsm_secattr *secattr)
1327{
1328        int ret_val;
1329        u8 tag_len = tag[1];
1330        u32 level;
1331
1332        ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1333        if (ret_val != 0)
1334                return ret_val;
1335        secattr->attr.mls.lvl = level;
1336        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1337
1338        if (tag_len > 4) {
1339                secattr->attr.mls.cat =
1340                                       netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1341                if (secattr->attr.mls.cat == NULL)
1342                        return -ENOMEM;
1343
1344                ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
1345                                                    &tag[4],
1346                                                    tag_len - 4,
1347                                                    secattr);
1348                if (ret_val != 0) {
1349                        netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1350                        return ret_val;
1351                }
1352
1353                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1354        }
1355
1356        return 0;
1357}
1358
1359/**
1360 * cipso_v4_gentag_enum - Generate a CIPSO enumerated tag (type #2)
1361 * @doi_def: the DOI definition
1362 * @secattr: the security attributes
1363 * @buffer: the option buffer
1364 * @buffer_len: length of buffer in bytes
1365 *
1366 * Description:
1367 * Generate a CIPSO option using the enumerated tag, tag type #2.  Returns the
1368 * size of the tag on success, negative values on failure.
1369 *
1370 */
1371static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
1372                                const struct netlbl_lsm_secattr *secattr,
1373                                unsigned char *buffer,
1374                                u32 buffer_len)
1375{
1376        int ret_val;
1377        u32 tag_len;
1378        u32 level;
1379
1380        if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1381                return -EPERM;
1382
1383        ret_val = cipso_v4_map_lvl_hton(doi_def,
1384                                        secattr->attr.mls.lvl,
1385                                        &level);
1386        if (ret_val != 0)
1387                return ret_val;
1388
1389        if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1390                ret_val = cipso_v4_map_cat_enum_hton(doi_def,
1391                                                     secattr,
1392                                                     &buffer[4],
1393                                                     buffer_len - 4);
1394                if (ret_val < 0)
1395                        return ret_val;
1396
1397                tag_len = 4 + ret_val;
1398        } else
1399                tag_len = 4;
1400
1401        buffer[0] = CIPSO_V4_TAG_ENUM;
1402        buffer[1] = tag_len;
1403        buffer[3] = level;
1404
1405        return tag_len;
1406}
1407
1408/**
1409 * cipso_v4_parsetag_enum - Parse a CIPSO enumerated tag
1410 * @doi_def: the DOI definition
1411 * @tag: the CIPSO tag
1412 * @secattr: the security attributes
1413 *
1414 * Description:
1415 * Parse a CIPSO enumerated tag (tag type #2) and return the security
1416 * attributes in @secattr.  Return zero on success, negatives values on
1417 * failure.
1418 *
1419 */
1420static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
1421                                  const unsigned char *tag,
1422                                  struct netlbl_lsm_secattr *secattr)
1423{
1424        int ret_val;
1425        u8 tag_len = tag[1];
1426        u32 level;
1427
1428        ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1429        if (ret_val != 0)
1430                return ret_val;
1431        secattr->attr.mls.lvl = level;
1432        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1433
1434        if (tag_len > 4) {
1435                secattr->attr.mls.cat =
1436                                       netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1437                if (secattr->attr.mls.cat == NULL)
1438                        return -ENOMEM;
1439
1440                ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
1441                                                     &tag[4],
1442                                                     tag_len - 4,
1443                                                     secattr);
1444                if (ret_val != 0) {
1445                        netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1446                        return ret_val;
1447                }
1448
1449                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1450        }
1451
1452        return 0;
1453}
1454
1455/**
1456 * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5)
1457 * @doi_def: the DOI definition
1458 * @secattr: the security attributes
1459 * @buffer: the option buffer
1460 * @buffer_len: length of buffer in bytes
1461 *
1462 * Description:
1463 * Generate a CIPSO option using the ranged tag, tag type #5.  Returns the
1464 * size of the tag on success, negative values on failure.
1465 *
1466 */
1467static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
1468                               const struct netlbl_lsm_secattr *secattr,
1469                               unsigned char *buffer,
1470                               u32 buffer_len)
1471{
1472        int ret_val;
1473        u32 tag_len;
1474        u32 level;
1475
1476        if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
1477                return -EPERM;
1478
1479        ret_val = cipso_v4_map_lvl_hton(doi_def,
1480                                        secattr->attr.mls.lvl,
1481                                        &level);
1482        if (ret_val != 0)
1483                return ret_val;
1484
1485        if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
1486                ret_val = cipso_v4_map_cat_rng_hton(doi_def,
1487                                                    secattr,
1488                                                    &buffer[4],
1489                                                    buffer_len - 4);
1490                if (ret_val < 0)
1491                        return ret_val;
1492
1493                tag_len = 4 + ret_val;
1494        } else
1495                tag_len = 4;
1496
1497        buffer[0] = CIPSO_V4_TAG_RANGE;
1498        buffer[1] = tag_len;
1499        buffer[3] = level;
1500
1501        return tag_len;
1502}
1503
1504/**
1505 * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag
1506 * @doi_def: the DOI definition
1507 * @tag: the CIPSO tag
1508 * @secattr: the security attributes
1509 *
1510 * Description:
1511 * Parse a CIPSO ranged tag (tag type #5) and return the security attributes
1512 * in @secattr.  Return zero on success, negatives values on failure.
1513 *
1514 */
1515static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1516                                 const unsigned char *tag,
1517                                 struct netlbl_lsm_secattr *secattr)
1518{
1519        int ret_val;
1520        u8 tag_len = tag[1];
1521        u32 level;
1522
1523        ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1524        if (ret_val != 0)
1525                return ret_val;
1526        secattr->attr.mls.lvl = level;
1527        secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1528
1529        if (tag_len > 4) {
1530                secattr->attr.mls.cat =
1531                                       netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1532                if (secattr->attr.mls.cat == NULL)
1533                        return -ENOMEM;
1534
1535                ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
1536                                                    &tag[4],
1537                                                    tag_len - 4,
1538                                                    secattr);
1539                if (ret_val != 0) {
1540                        netlbl_secattr_catmap_free(secattr->attr.mls.cat);
1541                        return ret_val;
1542                }
1543
1544                secattr->flags |= NETLBL_SECATTR_MLS_CAT;
1545        }
1546
1547        return 0;
1548}
1549
1550/**
1551 * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
1552 * @doi_def: the DOI definition
1553 * @secattr: the security attributes
1554 * @buffer: the option buffer
1555 * @buffer_len: length of buffer in bytes
1556 *
1557 * Description:
1558 * Generate a CIPSO option using the local tag.  Returns the size of the tag
1559 * on success, negative values on failure.
1560 *
1561 */
1562static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def,
1563                               const struct netlbl_lsm_secattr *secattr,
1564                               unsigned char *buffer,
1565                               u32 buffer_len)
1566{
1567        if (!(secattr->flags & NETLBL_SECATTR_SECID))
1568                return -EPERM;
1569
1570        buffer[0] = CIPSO_V4_TAG_LOCAL;
1571        buffer[1] = CIPSO_V4_TAG_LOC_BLEN;
1572        *(u32 *)&buffer[2] = secattr->attr.secid;
1573
1574        return CIPSO_V4_TAG_LOC_BLEN;
1575}
1576
1577/**
1578 * cipso_v4_parsetag_loc - Parse a CIPSO local tag
1579 * @doi_def: the DOI definition
1580 * @tag: the CIPSO tag
1581 * @secattr: the security attributes
1582 *
1583 * Description:
1584 * Parse a CIPSO local tag and return the security attributes in @secattr.
1585 * Return zero on success, negatives values on failure.
1586 *
1587 */
1588static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def,
1589                                 const unsigned char *tag,
1590                                 struct netlbl_lsm_secattr *secattr)
1591{
1592        secattr->attr.secid = *(u32 *)&tag[2];
1593        secattr->flags |= NETLBL_SECATTR_SECID;
1594
1595        return 0;
1596}
1597
1598/**
1599 * cipso_v4_validate - Validate a CIPSO option
1600 * @option: the start of the option, on error it is set to point to the error
1601 *
1602 * Description:
1603 * This routine is called to validate a CIPSO option, it checks all of the
1604 * fields to ensure that they are at least valid, see the draft snippet below
1605 * for details.  If the option is valid then a zero value is returned and
1606 * the value of @option is unchanged.  If the option is invalid then a
1607 * non-zero value is returned and @option is adjusted to point to the
1608 * offending portion of the option.  From the IETF draft ...
1609 *
1610 *  "If any field within the CIPSO options, such as the DOI identifier, is not
1611 *   recognized the IP datagram is discarded and an ICMP 'parameter problem'
1612 *   (type 12) is generated and returned.  The ICMP code field is set to 'bad
1613 *   parameter' (code 0) and the pointer is set to the start of the CIPSO field
1614 *   that is unrecognized."
1615 *
1616 */
1617int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
1618{
1619        unsigned char *opt = *option;
1620        unsigned char *tag;
1621        unsigned char opt_iter;
1622        unsigned char err_offset = 0;
1623        u8 opt_len;
1624        u8 tag_len;
1625        struct cipso_v4_doi *doi_def = NULL;
1626        u32 tag_iter;
1627
1628        /* caller already checks for length values that are too large */
1629        opt_len = opt[1];
1630        if (opt_len < 8) {
1631                err_offset = 1;
1632                goto validate_return;
1633        }
1634
1635        rcu_read_lock();
1636        doi_def = cipso_v4_doi_search(get_unaligned_be32(&opt[2]));
1637        if (doi_def == NULL) {
1638                err_offset = 2;
1639                goto validate_return_locked;
1640        }
1641
1642        opt_iter = CIPSO_V4_HDR_LEN;
1643        tag = opt + opt_iter;
1644        while (opt_iter < opt_len) {
1645                for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
1646                        if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
1647                            ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
1648                                err_offset = opt_iter;
1649                                goto validate_return_locked;
1650                        }
1651
1652                tag_len = tag[1];
1653                if (tag_len > (opt_len - opt_iter)) {
1654                        err_offset = opt_iter + 1;
1655                        goto validate_return_locked;
1656                }
1657
1658                switch (tag[0]) {
1659                case CIPSO_V4_TAG_RBITMAP:
1660                        if (tag_len < CIPSO_V4_TAG_RBM_BLEN) {
1661                                err_offset = opt_iter + 1;
1662                                goto validate_return_locked;
1663                        }
1664
1665                        /* We are already going to do all the verification
1666                         * necessary at the socket layer so from our point of
1667                         * view it is safe to turn these checks off (and less
1668                         * work), however, the CIPSO draft says we should do
1669                         * all the CIPSO validations here but it doesn't
1670                         * really specify _exactly_ what we need to validate
1671                         * ... so, just make it a sysctl tunable. */
1672                        if (cipso_v4_rbm_strictvalid) {
1673                                if (cipso_v4_map_lvl_valid(doi_def,
1674                                                           tag[3]) < 0) {
1675                                        err_offset = opt_iter + 3;
1676                                        goto validate_return_locked;
1677                                }
1678                                if (tag_len > CIPSO_V4_TAG_RBM_BLEN &&
1679                                    cipso_v4_map_cat_rbm_valid(doi_def,
1680                                                            &tag[4],
1681                                                            tag_len - 4) < 0) {
1682                                        err_offset = opt_iter + 4;
1683                                        goto validate_return_locked;
1684                                }
1685                        }
1686                        break;
1687                case CIPSO_V4_TAG_ENUM:
1688                        if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) {
1689                                err_offset = opt_iter + 1;
1690                                goto validate_return_locked;
1691                        }
1692
1693                        if (cipso_v4_map_lvl_valid(doi_def,
1694                                                   tag[3]) < 0) {
1695                                err_offset = opt_iter + 3;
1696                                goto validate_return_locked;
1697                        }
1698                        if (tag_len > CIPSO_V4_TAG_ENUM_BLEN &&
1699                            cipso_v4_map_cat_enum_valid(doi_def,
1700                                                        &tag[4],
1701                                                        tag_len - 4) < 0) {
1702                                err_offset = opt_iter + 4;
1703                                goto validate_return_locked;
1704                        }
1705                        break;
1706                case CIPSO_V4_TAG_RANGE:
1707                        if (tag_len < CIPSO_V4_TAG_RNG_BLEN) {
1708                                err_offset = opt_iter + 1;
1709                                goto validate_return_locked;
1710                        }
1711
1712                        if (cipso_v4_map_lvl_valid(doi_def,
1713                                                   tag[3]) < 0) {
1714                                err_offset = opt_iter + 3;
1715                                goto validate_return_locked;
1716                        }
1717                        if (tag_len > CIPSO_V4_TAG_RNG_BLEN &&
1718                            cipso_v4_map_cat_rng_valid(doi_def,
1719                                                       &tag[4],
1720                                                       tag_len - 4) < 0) {
1721                                err_offset = opt_iter + 4;
1722                                goto validate_return_locked;
1723                        }
1724                        break;
1725                case CIPSO_V4_TAG_LOCAL:
1726                        /* This is a non-standard tag that we only allow for
1727                         * local connections, so if the incoming interface is
1728                         * not the loopback device drop the packet. Further,
1729                         * there is no legitimate reason for setting this from
1730                         * userspace so reject it if skb is NULL. */
1731                        if (skb == NULL || !(skb->dev->flags & IFF_LOOPBACK)) {
1732                                err_offset = opt_iter;
1733                                goto validate_return_locked;
1734                        }
1735                        if (tag_len != CIPSO_V4_TAG_LOC_BLEN) {
1736                                err_offset = opt_iter + 1;
1737                                goto validate_return_locked;
1738                        }
1739                        break;
1740                default:
1741                        err_offset = opt_iter;
1742                        goto validate_return_locked;
1743                }
1744
1745                tag += tag_len;
1746                opt_iter += tag_len;
1747        }
1748
1749validate_return_locked:
1750        rcu_read_unlock();
1751validate_return:
1752        *option = opt + err_offset;
1753        return err_offset;
1754}
1755
1756/**
1757 * cipso_v4_error - Send the correct response for a bad packet
1758 * @skb: the packet
1759 * @error: the error code
1760 * @gateway: CIPSO gateway flag
1761 *
1762 * Description:
1763 * Based on the error code given in @error, send an ICMP error message back to
1764 * the originating host.  From the IETF draft ...
1765 *
1766 *  "If the contents of the CIPSO [option] are valid but the security label is
1767 *   outside of the configured host or port label range, the datagram is
1768 *   discarded and an ICMP 'destination unreachable' (type 3) is generated and
1769 *   returned.  The code field of the ICMP is set to 'communication with
1770 *   destination network administratively prohibited' (code 9) or to
1771 *   'communication with destination host administratively prohibited'
1772 *   (code 10).  The value of the code is dependent on whether the originator
1773 *   of the ICMP message is acting as a CIPSO host or a CIPSO gateway.  The
1774 *   recipient of the ICMP message MUST be able to handle either value.  The
1775 *   same procedure is performed if a CIPSO [option] can not be added to an
1776 *   IP packet because it is too large to fit in the IP options area."
1777 *
1778 *  "If the error is triggered by receipt of an ICMP message, the message is
1779 *   discarded and no response is permitted (consistent with general ICMP
1780 *   processing rules)."
1781 *
1782 */
1783void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1784{
1785        if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
1786                return;
1787
1788        if (gateway)
1789                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
1790        else
1791                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
1792}
1793
1794/**
1795 * cipso_v4_genopt - Generate a CIPSO option
1796 * @buf: the option buffer
1797 * @buf_len: the size of opt_buf
1798 * @doi_def: the CIPSO DOI to use
1799 * @secattr: the security attributes
1800 *
1801 * Description:
1802 * Generate a CIPSO option using the DOI definition and security attributes
1803 * passed to the function.  Returns the length of the option on success and
1804 * negative values on failure.
1805 *
1806 */
1807static int cipso_v4_genopt(unsigned char *buf, u32 buf_len,
1808                           const struct cipso_v4_doi *doi_def,
1809                           const struct netlbl_lsm_secattr *secattr)
1810{
1811        int ret_val;
1812        u32 iter;
1813
1814        if (buf_len <= CIPSO_V4_HDR_LEN)
1815                return -ENOSPC;
1816
1817        /* XXX - This code assumes only one tag per CIPSO option which isn't
1818         * really a good assumption to make but since we only support the MAC
1819         * tags right now it is a safe assumption. */
1820        iter = 0;
1821        do {
1822                memset(buf, 0, buf_len);
1823                switch (doi_def->tags[iter]) {
1824                case CIPSO_V4_TAG_RBITMAP:
1825                        ret_val = cipso_v4_gentag_rbm(doi_def,
1826                                                   secattr,
1827                                                   &buf[CIPSO_V4_HDR_LEN],
1828                                                   buf_len - CIPSO_V4_HDR_LEN);
1829                        break;
1830                case CIPSO_V4_TAG_ENUM:
1831                        ret_val = cipso_v4_gentag_enum(doi_def,
1832                                                   secattr,
1833                                                   &buf[CIPSO_V4_HDR_LEN],
1834                                                   buf_len - CIPSO_V4_HDR_LEN);
1835                        break;
1836                case CIPSO_V4_TAG_RANGE:
1837                        ret_val = cipso_v4_gentag_rng(doi_def,
1838                                                   secattr,
1839                                                   &buf[CIPSO_V4_HDR_LEN],
1840                                                   buf_len - CIPSO_V4_HDR_LEN);
1841                        break;
1842                case CIPSO_V4_TAG_LOCAL:
1843                        ret_val = cipso_v4_gentag_loc(doi_def,
1844                                                   secattr,
1845                                                   &buf[CIPSO_V4_HDR_LEN],
1846                                                   buf_len - CIPSO_V4_HDR_LEN);
1847                        break;
1848                default:
1849                        return -EPERM;
1850                }
1851
1852                iter++;
1853        } while (ret_val < 0 &&
1854                 iter < CIPSO_V4_TAG_MAXCNT &&
1855                 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1856        if (ret_val < 0)
1857                return ret_val;
1858        cipso_v4_gentag_hdr(doi_def, buf, ret_val);
1859        return CIPSO_V4_HDR_LEN + ret_val;
1860}
1861
1862/**
1863 * cipso_v4_sock_setattr - Add a CIPSO option to a socket
1864 * @sk: the socket
1865 * @doi_def: the CIPSO DOI to use
1866 * @secattr: the specific security attributes of the socket
1867 *
1868 * Description:
1869 * Set the CIPSO option on the given socket using the DOI definition and
1870 * security attributes passed to the function.  This function requires
1871 * exclusive access to @sk, which means it either needs to be in the
1872 * process of being created or locked.  Returns zero on success and negative
1873 * values on failure.
1874 *
1875 */
1876int cipso_v4_sock_setattr(struct sock *sk,
1877                          const struct cipso_v4_doi *doi_def,
1878                          const struct netlbl_lsm_secattr *secattr)
1879{
1880        int ret_val = -EPERM;
1881        unsigned char *buf = NULL;
1882        u32 buf_len;
1883        u32 opt_len;
1884        struct ip_options_rcu *old, *opt = NULL;
1885        struct inet_sock *sk_inet;
1886        struct inet_connection_sock *sk_conn;
1887
1888        /* In the case of sock_create_lite(), the sock->sk field is not
1889         * defined yet but it is not a problem as the only users of these
1890         * "lite" PF_INET sockets are functions which do an accept() call
1891         * afterwards so we will label the socket as part of the accept(). */
1892        if (sk == NULL)
1893                return 0;
1894
1895        /* We allocate the maximum CIPSO option size here so we are probably
1896         * being a little wasteful, but it makes our life _much_ easier later
1897         * on and after all we are only talking about 40 bytes. */
1898        buf_len = CIPSO_V4_OPT_LEN_MAX;
1899        buf = kmalloc(buf_len, GFP_ATOMIC);
1900        if (buf == NULL) {
1901                ret_val = -ENOMEM;
1902                goto socket_setattr_failure;
1903        }
1904
1905        ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1906        if (ret_val < 0)
1907                goto socket_setattr_failure;
1908        buf_len = ret_val;
1909
1910        /* We can't use ip_options_get() directly because it makes a call to
1911         * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
1912         * we won't always have CAP_NET_RAW even though we _always_ want to
1913         * set the IPOPT_CIPSO option. */
1914        opt_len = (buf_len + 3) & ~3;
1915        opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1916        if (opt == NULL) {
1917                ret_val = -ENOMEM;
1918                goto socket_setattr_failure;
1919        }
1920        memcpy(opt->opt.__data, buf, buf_len);
1921        opt->opt.optlen = opt_len;
1922        opt->opt.cipso = sizeof(struct iphdr);
1923        kfree(buf);
1924        buf = NULL;
1925
1926        sk_inet = inet_sk(sk);
1927
1928        old = rcu_dereference_protected(sk_inet->inet_opt, sock_owned_by_user(sk));
1929        if (sk_inet->is_icsk) {
1930                sk_conn = inet_csk(sk);
1931                if (old)
1932                        sk_conn->icsk_ext_hdr_len -= old->opt.optlen;
1933                sk_conn->icsk_ext_hdr_len += opt->opt.optlen;
1934                sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
1935        }
1936        rcu_assign_pointer(sk_inet->inet_opt, opt);
1937        if (old)
1938                kfree_rcu(old, rcu);
1939
1940        return 0;
1941
1942socket_setattr_failure:
1943        kfree(buf);
1944        kfree(opt);
1945        return ret_val;
1946}
1947
1948/**
1949 * cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
1950 * @req: the connection request socket
1951 * @doi_def: the CIPSO DOI to use
1952 * @secattr: the specific security attributes of the socket
1953 *
1954 * Description:
1955 * Set the CIPSO option on the given socket using the DOI definition and
1956 * security attributes passed to the function.  Returns zero on success and
1957 * negative values on failure.
1958 *
1959 */
1960int cipso_v4_req_setattr(struct request_sock *req,
1961                         const struct cipso_v4_doi *doi_def,
1962                         const struct netlbl_lsm_secattr *secattr)
1963{
1964        int ret_val = -EPERM;
1965        unsigned char *buf = NULL;
1966        u32 buf_len;
1967        u32 opt_len;
1968        struct ip_options_rcu *opt = NULL;
1969        struct inet_request_sock *req_inet;
1970
1971        /* We allocate the maximum CIPSO option size here so we are probably
1972         * being a little wasteful, but it makes our life _much_ easier later
1973         * on and after all we are only talking about 40 bytes. */
1974        buf_len = CIPSO_V4_OPT_LEN_MAX;
1975        buf = kmalloc(buf_len, GFP_ATOMIC);
1976        if (buf == NULL) {
1977                ret_val = -ENOMEM;
1978                goto req_setattr_failure;
1979        }
1980
1981        ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
1982        if (ret_val < 0)
1983                goto req_setattr_failure;
1984        buf_len = ret_val;
1985
1986        /* We can't use ip_options_get() directly because it makes a call to
1987         * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
1988         * we won't always have CAP_NET_RAW even though we _always_ want to
1989         * set the IPOPT_CIPSO option. */
1990        opt_len = (buf_len + 3) & ~3;
1991        opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1992        if (opt == NULL) {
1993                ret_val = -ENOMEM;
1994                goto req_setattr_failure;
1995        }
1996        memcpy(opt->opt.__data, buf, buf_len);
1997        opt->opt.optlen = opt_len;
1998        opt->opt.cipso = sizeof(struct iphdr);
1999        kfree(buf);
2000        buf = NULL;
2001
2002        req_inet = inet_rsk(req);
2003        opt = xchg(&req_inet->opt, opt);
2004        if (opt)
2005                kfree_rcu(opt, rcu);
2006
2007        return 0;
2008
2009req_setattr_failure:
2010        kfree(buf);
2011        kfree(opt);
2012        return ret_val;
2013}
2014
2015/**
2016 * cipso_v4_delopt - Delete the CIPSO option from a set of IP options
2017 * @opt_ptr: IP option pointer
2018 *
2019 * Description:
2020 * Deletes the CIPSO IP option from a set of IP options and makes the necessary
2021 * adjustments to the IP option structure.  Returns zero on success, negative
2022 * values on failure.
2023 *
2024 */
2025static int cipso_v4_delopt(struct ip_options_rcu **opt_ptr)
2026{
2027        int hdr_delta = 0;
2028        struct ip_options_rcu *opt = *opt_ptr;
2029
2030        if (opt->opt.srr || opt->opt.rr || opt->opt.ts || opt->opt.router_alert) {
2031                u8 cipso_len;
2032                u8 cipso_off;
2033                unsigned char *cipso_ptr;
2034                int iter;
2035                int optlen_new;
2036
2037                cipso_off = opt->opt.cipso - sizeof(struct iphdr);
2038                cipso_ptr = &opt->opt.__data[cipso_off];
2039                cipso_len = cipso_ptr[1];
2040
2041                if (opt->opt.srr > opt->opt.cipso)
2042                        opt->opt.srr -= cipso_len;
2043                if (opt->opt.rr > opt->opt.cipso)
2044                        opt->opt.rr -= cipso_len;
2045                if (opt->opt.ts > opt->opt.cipso)
2046                        opt->opt.ts -= cipso_len;
2047                if (opt->opt.router_alert > opt->opt.cipso)
2048                        opt->opt.router_alert -= cipso_len;
2049                opt->opt.cipso = 0;
2050
2051                memmove(cipso_ptr, cipso_ptr + cipso_len,
2052                        opt->opt.optlen - cipso_off - cipso_len);
2053
2054                /* determining the new total option length is tricky because of
2055                 * the padding necessary, the only thing i can think to do at
2056                 * this point is walk the options one-by-one, skipping the
2057                 * padding at the end to determine the actual option size and
2058                 * from there we can determine the new total option length */
2059                iter = 0;
2060                optlen_new = 0;
2061                while (iter < opt->opt.optlen)
2062                        if (opt->opt.__data[iter] != IPOPT_NOP) {
2063                                iter += opt->opt.__data[iter + 1];
2064                                optlen_new = iter;
2065                        } else
2066                                iter++;
2067                hdr_delta = opt->opt.optlen;
2068                opt->opt.optlen = (optlen_new + 3) & ~3;
2069                hdr_delta -= opt->opt.optlen;
2070        } else {
2071                /* only the cipso option was present on the socket so we can
2072                 * remove the entire option struct */
2073                *opt_ptr = NULL;
2074                hdr_delta = opt->opt.optlen;
2075                kfree_rcu(opt, rcu);
2076        }
2077
2078        return hdr_delta;
2079}
2080
2081/**
2082 * cipso_v4_sock_delattr - Delete the CIPSO option from a socket
2083 * @sk: the socket
2084 *
2085 * Description:
2086 * Removes the CIPSO option from a socket, if present.
2087 *
2088 */
2089void cipso_v4_sock_delattr(struct sock *sk)
2090{
2091        int hdr_delta;
2092        struct ip_options_rcu *opt;
2093        struct inet_sock *sk_inet;
2094
2095        sk_inet = inet_sk(sk);
2096        opt = rcu_dereference_protected(sk_inet->inet_opt, 1);
2097        if (opt == NULL || opt->opt.cipso == 0)
2098                return;
2099
2100        hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt);
2101        if (sk_inet->is_icsk && hdr_delta > 0) {
2102                struct inet_connection_sock *sk_conn = inet_csk(sk);
2103                sk_conn->icsk_ext_hdr_len -= hdr_delta;
2104                sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
2105        }
2106}
2107
2108/**
2109 * cipso_v4_req_delattr - Delete the CIPSO option from a request socket
2110 * @reg: the request socket
2111 *
2112 * Description:
2113 * Removes the CIPSO option from a request socket, if present.
2114 *
2115 */
2116void cipso_v4_req_delattr(struct request_sock *req)
2117{
2118        struct ip_options_rcu *opt;
2119        struct inet_request_sock *req_inet;
2120
2121        req_inet = inet_rsk(req);
2122        opt = req_inet->opt;
2123        if (opt == NULL || opt->opt.cipso == 0)
2124                return;
2125
2126        cipso_v4_delopt(&req_inet->opt);
2127}
2128
2129/**
2130 * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
2131 * @cipso: the CIPSO v4 option
2132 * @secattr: the security attributes
2133 *
2134 * Description:
2135 * Inspect @cipso and return the security attributes in @secattr.  Returns zero
2136 * on success and negative values on failure.
2137 *
2138 */
2139static int cipso_v4_getattr(const unsigned char *cipso,
2140                            struct netlbl_lsm_secattr *secattr)
2141{
2142        int ret_val = -ENOMSG;
2143        u32 doi;
2144        struct cipso_v4_doi *doi_def;
2145
2146        if (cipso_v4_cache_check(cipso, cipso[1], secattr) == 0)
2147                return 0;
2148
2149        doi = get_unaligned_be32(&cipso[2]);
2150        rcu_read_lock();
2151        doi_def = cipso_v4_doi_search(doi);
2152        if (doi_def == NULL)
2153                goto getattr_return;
2154        /* XXX - This code assumes only one tag per CIPSO option which isn't
2155         * really a good assumption to make but since we only support the MAC
2156         * tags right now it is a safe assumption. */
2157        switch (cipso[6]) {
2158        case CIPSO_V4_TAG_RBITMAP:
2159                ret_val = cipso_v4_parsetag_rbm(doi_def, &cipso[6], secattr);
2160                break;
2161        case CIPSO_V4_TAG_ENUM:
2162                ret_val = cipso_v4_parsetag_enum(doi_def, &cipso[6], secattr);
2163                break;
2164        case CIPSO_V4_TAG_RANGE:
2165                ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
2166                break;
2167        case CIPSO_V4_TAG_LOCAL:
2168                ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr);
2169                break;
2170        }
2171        if (ret_val == 0)
2172                secattr->type = NETLBL_NLTYPE_CIPSOV4;
2173
2174getattr_return:
2175        rcu_read_unlock();
2176        return ret_val;
2177}
2178
2179/**
2180 * cipso_v4_sock_getattr - Get the security attributes from a sock
2181 * @sk: the sock
2182 * @secattr: the security attributes
2183 *
2184 * Description:
2185 * Query @sk to see if there is a CIPSO option attached to the sock and if
2186 * there is return the CIPSO security attributes in @secattr.  This function
2187 * requires that @sk be locked, or privately held, but it does not do any
2188 * locking itself.  Returns zero on success and negative values on failure.
2189 *
2190 */
2191int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
2192{
2193        struct ip_options_rcu *opt;
2194        int res = -ENOMSG;
2195
2196        rcu_read_lock();
2197        opt = rcu_dereference(inet_sk(sk)->inet_opt);
2198        if (opt && opt->opt.cipso)
2199                res = cipso_v4_getattr(opt->opt.__data +
2200                                                opt->opt.cipso -
2201                                                sizeof(struct iphdr),
2202                                       secattr);
2203        rcu_read_unlock();
2204        return res;
2205}
2206
2207/**
2208 * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
2209 * @skb: the packet
2210 * @secattr: the security attributes
2211 *
2212 * Description:
2213 * Set the CIPSO option on the given packet based on the security attributes.
2214 * Returns a pointer to the IP header on success and NULL on failure.
2215 *
2216 */
2217int cipso_v4_skbuff_setattr(struct sk_buff *skb,
2218                            const struct cipso_v4_doi *doi_def,
2219                            const struct netlbl_lsm_secattr *secattr)
2220{
2221        int ret_val;
2222        struct iphdr *iph;
2223        struct ip_options *opt = &IPCB(skb)->opt;
2224        unsigned char buf[CIPSO_V4_OPT_LEN_MAX];
2225        u32 buf_len = CIPSO_V4_OPT_LEN_MAX;
2226        u32 opt_len;
2227        int len_delta;
2228
2229        ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
2230        if (ret_val < 0)
2231                return ret_val;
2232        buf_len = ret_val;
2233        opt_len = (buf_len + 3) & ~3;
2234
2235        /* we overwrite any existing options to ensure that we have enough
2236         * room for the CIPSO option, the reason is that we _need_ to guarantee
2237         * that the security label is applied to the packet - we do the same
2238         * thing when using the socket options and it hasn't caused a problem,
2239         * if we need to we can always revisit this choice later */
2240
2241        len_delta = opt_len - opt->optlen;
2242        /* if we don't ensure enough headroom we could panic on the skb_push()
2243         * call below so make sure we have enough, we are also "mangling" the
2244         * packet so we should probably do a copy-on-write call anyway */
2245        ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
2246        if (ret_val < 0)
2247                return ret_val;
2248
2249        if (len_delta > 0) {
2250                /* we assume that the header + opt->optlen have already been
2251                 * "pushed" in ip_options_build() or similar */
2252                iph = ip_hdr(skb);
2253                skb_push(skb, len_delta);
2254                memmove((char *)iph - len_delta, iph, iph->ihl << 2);
2255                skb_reset_network_header(skb);
2256                iph = ip_hdr(skb);
2257        } else if (len_delta < 0) {
2258                iph = ip_hdr(skb);
2259                memset(iph + 1, IPOPT_NOP, opt->optlen);
2260        } else
2261                iph = ip_hdr(skb);
2262
2263        if (opt->optlen > 0)
2264                memset(opt, 0, sizeof(*opt));
2265        opt->optlen = opt_len;
2266        opt->cipso = sizeof(struct iphdr);
2267        opt->is_changed = 1;
2268
2269        /* we have to do the following because we are being called from a
2270         * netfilter hook which means the packet already has had the header
2271         * fields populated and the checksum calculated - yes this means we
2272         * are doing more work than needed but we do it to keep the core
2273         * stack clean and tidy */
2274        memcpy(iph + 1, buf, buf_len);
2275        if (opt_len > buf_len)
2276                memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len);
2277        if (len_delta != 0) {
2278                iph->ihl = 5 + (opt_len >> 2);
2279                iph->tot_len = htons(skb->len);
2280        }
2281        ip_send_check(iph);
2282
2283        return 0;
2284}
2285
2286/**
2287 * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
2288 * @skb: the packet
2289 *
2290 * Description:
2291 * Removes any and all CIPSO options from the given packet.  Returns zero on
2292 * success, negative values on failure.
2293 *
2294 */
2295int cipso_v4_skbuff_delattr(struct sk_buff *skb)
2296{
2297        int ret_val;
2298        struct iphdr *iph;
2299        struct ip_options *opt = &IPCB(skb)->opt;
2300        unsigned char *cipso_ptr;
2301
2302        if (opt->cipso == 0)
2303                return 0;
2304
2305        /* since we are changing the packet we should make a copy */
2306        ret_val = skb_cow(skb, skb_headroom(skb));
2307        if (ret_val < 0)
2308                return ret_val;
2309
2310        /* the easiest thing to do is just replace the cipso option with noop
2311         * options since we don't change the size of the packet, although we
2312         * still need to recalculate the checksum */
2313
2314        iph = ip_hdr(skb);
2315        cipso_ptr = (unsigned char *)iph + opt->cipso;
2316        memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]);
2317        opt->cipso = 0;
2318        opt->is_changed = 1;
2319
2320        ip_send_check(iph);
2321
2322        return 0;
2323}
2324
2325/**
2326 * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
2327 * @skb: the packet
2328 * @secattr: the security attributes
2329 *
2330 * Description:
2331 * Parse the given packet's CIPSO option and return the security attributes.
2332 * Returns zero on success and negative values on failure.
2333 *
2334 */
2335int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
2336                            struct netlbl_lsm_secattr *secattr)
2337{
2338        return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr);
2339}
2340
2341/*
2342 * Setup Functions
2343 */
2344
2345/**
2346 * cipso_v4_init - Initialize the CIPSO module
2347 *
2348 * Description:
2349 * Initialize the CIPSO module and prepare it for use.  Returns zero on success
2350 * and negative values on failure.
2351 *
2352 */
2353static int __init cipso_v4_init(void)
2354{
2355        int ret_val;
2356
2357        ret_val = cipso_v4_cache_init();
2358        if (ret_val != 0)
2359                panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
2360                      ret_val);
2361
2362        return 0;
2363}
2364
2365subsys_initcall(cipso_v4_init);
2366
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.