1446fda4fSPaul Moore /* 2446fda4fSPaul Moore * CIPSO - Commercial IP Security Option 3446fda4fSPaul Moore * 4446fda4fSPaul Moore * This is an implementation of the CIPSO 2.2 protocol as specified in 5446fda4fSPaul Moore * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in 6446fda4fSPaul Moore * FIPS-188, copies of both documents can be found in the Documentation 7446fda4fSPaul Moore * directory. While CIPSO never became a full IETF RFC standard many vendors 8446fda4fSPaul Moore * have chosen to adopt the protocol and over the years it has become a 9446fda4fSPaul Moore * de-facto standard for labeled networking. 10446fda4fSPaul Moore * 11446fda4fSPaul Moore * Author: Paul Moore <paul.moore@hp.com> 12446fda4fSPaul Moore * 13446fda4fSPaul Moore */ 14446fda4fSPaul Moore 15446fda4fSPaul Moore /* 16446fda4fSPaul Moore * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 17446fda4fSPaul Moore * 18446fda4fSPaul Moore * This program is free software; you can redistribute it and/or modify 19446fda4fSPaul Moore * it under the terms of the GNU General Public License as published by 20446fda4fSPaul Moore * the Free Software Foundation; either version 2 of the License, or 21446fda4fSPaul Moore * (at your option) any later version. 22446fda4fSPaul Moore * 23446fda4fSPaul Moore * This program is distributed in the hope that it will be useful, 24446fda4fSPaul Moore * but WITHOUT ANY WARRANTY; without even the implied warranty of 25446fda4fSPaul Moore * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 26446fda4fSPaul Moore * the GNU General Public License for more details. 27446fda4fSPaul Moore * 28446fda4fSPaul Moore * You should have received a copy of the GNU General Public License 29446fda4fSPaul Moore * along with this program; if not, write to the Free Software 30446fda4fSPaul Moore * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31446fda4fSPaul Moore * 32446fda4fSPaul Moore */ 33446fda4fSPaul Moore 34446fda4fSPaul Moore #include <linux/init.h> 35446fda4fSPaul Moore #include <linux/types.h> 36446fda4fSPaul Moore #include <linux/rcupdate.h> 37446fda4fSPaul Moore #include <linux/list.h> 38446fda4fSPaul Moore #include <linux/spinlock.h> 39446fda4fSPaul Moore #include <linux/string.h> 40446fda4fSPaul Moore #include <linux/jhash.h> 41446fda4fSPaul Moore #include <net/ip.h> 42446fda4fSPaul Moore #include <net/icmp.h> 43446fda4fSPaul Moore #include <net/tcp.h> 44446fda4fSPaul Moore #include <net/netlabel.h> 45446fda4fSPaul Moore #include <net/cipso_ipv4.h> 46ffb733c6Spaul.moore@hp.com #include <asm/atomic.h> 47446fda4fSPaul Moore #include <asm/bug.h> 48*50e5d35cSPaul Moore #include <asm/unaligned.h> 49446fda4fSPaul Moore 50446fda4fSPaul Moore struct cipso_v4_domhsh_entry { 51446fda4fSPaul Moore char *domain; 52446fda4fSPaul Moore u32 valid; 53446fda4fSPaul Moore struct list_head list; 54446fda4fSPaul Moore struct rcu_head rcu; 55446fda4fSPaul Moore }; 56446fda4fSPaul Moore 57446fda4fSPaul Moore /* List of available DOI definitions */ 58446fda4fSPaul Moore /* XXX - Updates should be minimal so having a single lock for the 59446fda4fSPaul Moore * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be 60446fda4fSPaul Moore * okay. */ 61446fda4fSPaul Moore /* XXX - This currently assumes a minimal number of different DOIs in use, 62446fda4fSPaul Moore * if in practice there are a lot of different DOIs this list should 63446fda4fSPaul Moore * probably be turned into a hash table or something similar so we 64446fda4fSPaul Moore * can do quick lookups. */ 658ce11e6aSAdrian Bunk static DEFINE_SPINLOCK(cipso_v4_doi_list_lock); 66446fda4fSPaul Moore static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list); 67446fda4fSPaul Moore 68446fda4fSPaul Moore /* Label mapping cache */ 69446fda4fSPaul Moore int cipso_v4_cache_enabled = 1; 70446fda4fSPaul Moore int cipso_v4_cache_bucketsize = 10; 71446fda4fSPaul Moore #define CIPSO_V4_CACHE_BUCKETBITS 7 72446fda4fSPaul Moore #define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS) 73446fda4fSPaul Moore #define CIPSO_V4_CACHE_REORDERLIMIT 10 74446fda4fSPaul Moore struct cipso_v4_map_cache_bkt { 75446fda4fSPaul Moore spinlock_t lock; 76446fda4fSPaul Moore u32 size; 77446fda4fSPaul Moore struct list_head list; 78446fda4fSPaul Moore }; 79446fda4fSPaul Moore struct cipso_v4_map_cache_entry { 80446fda4fSPaul Moore u32 hash; 81446fda4fSPaul Moore unsigned char *key; 82446fda4fSPaul Moore size_t key_len; 83446fda4fSPaul Moore 84ffb733c6Spaul.moore@hp.com struct netlbl_lsm_cache *lsm_data; 85446fda4fSPaul Moore 86446fda4fSPaul Moore u32 activity; 87446fda4fSPaul Moore struct list_head list; 88446fda4fSPaul Moore }; 89446fda4fSPaul Moore static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL; 90446fda4fSPaul Moore 91446fda4fSPaul Moore /* Restricted bitmap (tag #1) flags */ 92446fda4fSPaul Moore int cipso_v4_rbm_optfmt = 0; 93446fda4fSPaul Moore int cipso_v4_rbm_strictvalid = 1; 94446fda4fSPaul Moore 95446fda4fSPaul Moore /* 96f998e8cbSPaul Moore * Protocol Constants 97f998e8cbSPaul Moore */ 98f998e8cbSPaul Moore 99f998e8cbSPaul Moore /* Maximum size of the CIPSO IP option, derived from the fact that the maximum 100f998e8cbSPaul Moore * IPv4 header size is 60 bytes and the base IPv4 header is 20 bytes long. */ 101f998e8cbSPaul Moore #define CIPSO_V4_OPT_LEN_MAX 40 102f998e8cbSPaul Moore 103f998e8cbSPaul Moore /* Length of the base CIPSO option, this includes the option type (1 byte), the 104f998e8cbSPaul Moore * option length (1 byte), and the DOI (4 bytes). */ 105f998e8cbSPaul Moore #define CIPSO_V4_HDR_LEN 6 106f998e8cbSPaul Moore 107f998e8cbSPaul Moore /* Base length of the restrictive category bitmap tag (tag #1). */ 108f998e8cbSPaul Moore #define CIPSO_V4_TAG_RBM_BLEN 4 109f998e8cbSPaul Moore 110f998e8cbSPaul Moore /* Base length of the enumerated category tag (tag #2). */ 111f998e8cbSPaul Moore #define CIPSO_V4_TAG_ENUM_BLEN 4 112f998e8cbSPaul Moore 113f998e8cbSPaul Moore /* Base length of the ranged categories bitmap tag (tag #5). */ 114f998e8cbSPaul Moore #define CIPSO_V4_TAG_RNG_BLEN 4 115f998e8cbSPaul Moore /* The maximum number of category ranges permitted in the ranged category tag 116f998e8cbSPaul Moore * (tag #5). You may note that the IETF draft states that the maximum number 117f998e8cbSPaul Moore * of category ranges is 7, but if the low end of the last category range is 118f998e8cbSPaul Moore * zero then it is possibile to fit 8 category ranges because the zero should 119f998e8cbSPaul Moore * be omitted. */ 120f998e8cbSPaul Moore #define CIPSO_V4_TAG_RNG_CAT_MAX 8 121f998e8cbSPaul Moore 122f998e8cbSPaul Moore /* 123446fda4fSPaul Moore * Helper Functions 124446fda4fSPaul Moore */ 125446fda4fSPaul Moore 126446fda4fSPaul Moore /** 127446fda4fSPaul Moore * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit 128446fda4fSPaul Moore * @bitmap: the bitmap 129446fda4fSPaul Moore * @bitmap_len: length in bits 130446fda4fSPaul Moore * @offset: starting offset 131446fda4fSPaul Moore * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit 132446fda4fSPaul Moore * 133446fda4fSPaul Moore * Description: 134446fda4fSPaul Moore * Starting at @offset, walk the bitmap from left to right until either the 135446fda4fSPaul Moore * desired bit is found or we reach the end. Return the bit offset, -1 if 136446fda4fSPaul Moore * not found, or -2 if error. 137446fda4fSPaul Moore */ 138446fda4fSPaul Moore static int cipso_v4_bitmap_walk(const unsigned char *bitmap, 139446fda4fSPaul Moore u32 bitmap_len, 140446fda4fSPaul Moore u32 offset, 141446fda4fSPaul Moore u8 state) 142446fda4fSPaul Moore { 143446fda4fSPaul Moore u32 bit_spot; 144446fda4fSPaul Moore u32 byte_offset; 145446fda4fSPaul Moore unsigned char bitmask; 146446fda4fSPaul Moore unsigned char byte; 147446fda4fSPaul Moore 148446fda4fSPaul Moore /* gcc always rounds to zero when doing integer division */ 149446fda4fSPaul Moore byte_offset = offset / 8; 150446fda4fSPaul Moore byte = bitmap[byte_offset]; 151446fda4fSPaul Moore bit_spot = offset; 152446fda4fSPaul Moore bitmask = 0x80 >> (offset % 8); 153446fda4fSPaul Moore 154446fda4fSPaul Moore while (bit_spot < bitmap_len) { 155446fda4fSPaul Moore if ((state && (byte & bitmask) == bitmask) || 156446fda4fSPaul Moore (state == 0 && (byte & bitmask) == 0)) 157446fda4fSPaul Moore return bit_spot; 158446fda4fSPaul Moore 159446fda4fSPaul Moore bit_spot++; 160446fda4fSPaul Moore bitmask >>= 1; 161446fda4fSPaul Moore if (bitmask == 0) { 162446fda4fSPaul Moore byte = bitmap[++byte_offset]; 163446fda4fSPaul Moore bitmask = 0x80; 164446fda4fSPaul Moore } 165446fda4fSPaul Moore } 166446fda4fSPaul Moore 167446fda4fSPaul Moore return -1; 168446fda4fSPaul Moore } 169446fda4fSPaul Moore 170446fda4fSPaul Moore /** 171446fda4fSPaul Moore * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap 172446fda4fSPaul Moore * @bitmap: the bitmap 173446fda4fSPaul Moore * @bit: the bit 174446fda4fSPaul Moore * @state: if non-zero, set the bit (1) else clear the bit (0) 175446fda4fSPaul Moore * 176446fda4fSPaul Moore * Description: 177446fda4fSPaul Moore * Set a single bit in the bitmask. Returns zero on success, negative values 178446fda4fSPaul Moore * on error. 179446fda4fSPaul Moore */ 180446fda4fSPaul Moore static void cipso_v4_bitmap_setbit(unsigned char *bitmap, 181446fda4fSPaul Moore u32 bit, 182446fda4fSPaul Moore u8 state) 183446fda4fSPaul Moore { 184446fda4fSPaul Moore u32 byte_spot; 185446fda4fSPaul Moore u8 bitmask; 186446fda4fSPaul Moore 187446fda4fSPaul Moore /* gcc always rounds to zero when doing integer division */ 188446fda4fSPaul Moore byte_spot = bit / 8; 189446fda4fSPaul Moore bitmask = 0x80 >> (bit % 8); 190446fda4fSPaul Moore if (state) 191446fda4fSPaul Moore bitmap[byte_spot] |= bitmask; 192446fda4fSPaul Moore else 193446fda4fSPaul Moore bitmap[byte_spot] &= ~bitmask; 194446fda4fSPaul Moore } 195446fda4fSPaul Moore 196446fda4fSPaul Moore /** 197446fda4fSPaul Moore * cipso_v4_doi_domhsh_free - Frees a domain list entry 198446fda4fSPaul Moore * @entry: the entry's RCU field 199446fda4fSPaul Moore * 200446fda4fSPaul Moore * Description: 201446fda4fSPaul Moore * This function is designed to be used as a callback to the call_rcu() 202446fda4fSPaul Moore * function so that the memory allocated to a domain list entry can be released 203446fda4fSPaul Moore * safely. 204446fda4fSPaul Moore * 205446fda4fSPaul Moore */ 206446fda4fSPaul Moore static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) 207446fda4fSPaul Moore { 208446fda4fSPaul Moore struct cipso_v4_domhsh_entry *ptr; 209446fda4fSPaul Moore 210446fda4fSPaul Moore ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu); 211446fda4fSPaul Moore kfree(ptr->domain); 212446fda4fSPaul Moore kfree(ptr); 213446fda4fSPaul Moore } 214446fda4fSPaul Moore 215446fda4fSPaul Moore /** 216446fda4fSPaul Moore * cipso_v4_cache_entry_free - Frees a cache entry 217446fda4fSPaul Moore * @entry: the entry to free 218446fda4fSPaul Moore * 219446fda4fSPaul Moore * Description: 220ffb733c6Spaul.moore@hp.com * This function frees the memory associated with a cache entry including the 221ffb733c6Spaul.moore@hp.com * LSM cache data if there are no longer any users, i.e. reference count == 0. 222446fda4fSPaul Moore * 223446fda4fSPaul Moore */ 224446fda4fSPaul Moore static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry) 225446fda4fSPaul Moore { 226ffb733c6Spaul.moore@hp.com if (entry->lsm_data) 227ffb733c6Spaul.moore@hp.com netlbl_secattr_cache_free(entry->lsm_data); 228446fda4fSPaul Moore kfree(entry->key); 229446fda4fSPaul Moore kfree(entry); 230446fda4fSPaul Moore } 231446fda4fSPaul Moore 232446fda4fSPaul Moore /** 233446fda4fSPaul Moore * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache 234446fda4fSPaul Moore * @key: the hash key 235446fda4fSPaul Moore * @key_len: the length of the key in bytes 236446fda4fSPaul Moore * 237446fda4fSPaul Moore * Description: 238446fda4fSPaul Moore * The CIPSO tag hashing function. Returns a 32-bit hash value. 239446fda4fSPaul Moore * 240446fda4fSPaul Moore */ 241446fda4fSPaul Moore static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len) 242446fda4fSPaul Moore { 243446fda4fSPaul Moore return jhash(key, key_len, 0); 244446fda4fSPaul Moore } 245446fda4fSPaul Moore 246446fda4fSPaul Moore /* 247446fda4fSPaul Moore * Label Mapping Cache Functions 248446fda4fSPaul Moore */ 249446fda4fSPaul Moore 250446fda4fSPaul Moore /** 251446fda4fSPaul Moore * cipso_v4_cache_init - Initialize the CIPSO cache 252446fda4fSPaul Moore * 253446fda4fSPaul Moore * Description: 254446fda4fSPaul Moore * Initializes the CIPSO label mapping cache, this function should be called 255446fda4fSPaul Moore * before any of the other functions defined in this file. Returns zero on 256446fda4fSPaul Moore * success, negative values on error. 257446fda4fSPaul Moore * 258446fda4fSPaul Moore */ 259446fda4fSPaul Moore static int cipso_v4_cache_init(void) 260446fda4fSPaul Moore { 261446fda4fSPaul Moore u32 iter; 262446fda4fSPaul Moore 263446fda4fSPaul Moore cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS, 264446fda4fSPaul Moore sizeof(struct cipso_v4_map_cache_bkt), 265446fda4fSPaul Moore GFP_KERNEL); 266446fda4fSPaul Moore if (cipso_v4_cache == NULL) 267446fda4fSPaul Moore return -ENOMEM; 268446fda4fSPaul Moore 269446fda4fSPaul Moore for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { 270446fda4fSPaul Moore spin_lock_init(&cipso_v4_cache[iter].lock); 271446fda4fSPaul Moore cipso_v4_cache[iter].size = 0; 272446fda4fSPaul Moore INIT_LIST_HEAD(&cipso_v4_cache[iter].list); 273446fda4fSPaul Moore } 274446fda4fSPaul Moore 275446fda4fSPaul Moore return 0; 276446fda4fSPaul Moore } 277446fda4fSPaul Moore 278446fda4fSPaul Moore /** 279446fda4fSPaul Moore * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache 280446fda4fSPaul Moore * 281446fda4fSPaul Moore * Description: 282446fda4fSPaul Moore * Invalidates and frees any entries in the CIPSO cache. Returns zero on 283446fda4fSPaul Moore * success and negative values on failure. 284446fda4fSPaul Moore * 285446fda4fSPaul Moore */ 286446fda4fSPaul Moore void cipso_v4_cache_invalidate(void) 287446fda4fSPaul Moore { 288446fda4fSPaul Moore struct cipso_v4_map_cache_entry *entry, *tmp_entry; 289446fda4fSPaul Moore u32 iter; 290446fda4fSPaul Moore 291446fda4fSPaul Moore for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { 292609c92feSPaul Moore spin_lock_bh(&cipso_v4_cache[iter].lock); 293446fda4fSPaul Moore list_for_each_entry_safe(entry, 294446fda4fSPaul Moore tmp_entry, 295446fda4fSPaul Moore &cipso_v4_cache[iter].list, list) { 296446fda4fSPaul Moore list_del(&entry->list); 297446fda4fSPaul Moore cipso_v4_cache_entry_free(entry); 298446fda4fSPaul Moore } 299446fda4fSPaul Moore cipso_v4_cache[iter].size = 0; 300609c92feSPaul Moore spin_unlock_bh(&cipso_v4_cache[iter].lock); 301446fda4fSPaul Moore } 302446fda4fSPaul Moore 303446fda4fSPaul Moore return; 304446fda4fSPaul Moore } 305446fda4fSPaul Moore 306446fda4fSPaul Moore /** 307446fda4fSPaul Moore * cipso_v4_cache_check - Check the CIPSO cache for a label mapping 308446fda4fSPaul Moore * @key: the buffer to check 309446fda4fSPaul Moore * @key_len: buffer length in bytes 310446fda4fSPaul Moore * @secattr: the security attribute struct to use 311446fda4fSPaul Moore * 312446fda4fSPaul Moore * Description: 313446fda4fSPaul Moore * This function checks the cache to see if a label mapping already exists for 314446fda4fSPaul Moore * the given key. If there is a match then the cache is adjusted and the 315446fda4fSPaul Moore * @secattr struct is populated with the correct LSM security attributes. The 316446fda4fSPaul Moore * cache is adjusted in the following manner if the entry is not already the 317446fda4fSPaul Moore * first in the cache bucket: 318446fda4fSPaul Moore * 319446fda4fSPaul Moore * 1. The cache entry's activity counter is incremented 320446fda4fSPaul Moore * 2. The previous (higher ranking) entry's activity counter is decremented 321446fda4fSPaul Moore * 3. If the difference between the two activity counters is geater than 322446fda4fSPaul Moore * CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped 323446fda4fSPaul Moore * 324446fda4fSPaul Moore * Returns zero on success, -ENOENT for a cache miss, and other negative values 325446fda4fSPaul Moore * on error. 326446fda4fSPaul Moore * 327446fda4fSPaul Moore */ 328446fda4fSPaul Moore static int cipso_v4_cache_check(const unsigned char *key, 329446fda4fSPaul Moore u32 key_len, 330446fda4fSPaul Moore struct netlbl_lsm_secattr *secattr) 331446fda4fSPaul Moore { 332446fda4fSPaul Moore u32 bkt; 333446fda4fSPaul Moore struct cipso_v4_map_cache_entry *entry; 334446fda4fSPaul Moore struct cipso_v4_map_cache_entry *prev_entry = NULL; 335446fda4fSPaul Moore u32 hash; 336446fda4fSPaul Moore 337446fda4fSPaul Moore if (!cipso_v4_cache_enabled) 338446fda4fSPaul Moore return -ENOENT; 339446fda4fSPaul Moore 340446fda4fSPaul Moore hash = cipso_v4_map_cache_hash(key, key_len); 341446fda4fSPaul Moore bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); 342609c92feSPaul Moore spin_lock_bh(&cipso_v4_cache[bkt].lock); 343446fda4fSPaul Moore list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) { 344446fda4fSPaul Moore if (entry->hash == hash && 345446fda4fSPaul Moore entry->key_len == key_len && 346446fda4fSPaul Moore memcmp(entry->key, key, key_len) == 0) { 347446fda4fSPaul Moore entry->activity += 1; 348ffb733c6Spaul.moore@hp.com atomic_inc(&entry->lsm_data->refcount); 349ffb733c6Spaul.moore@hp.com secattr->cache = entry->lsm_data; 350701a90baSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 351446fda4fSPaul Moore if (prev_entry == NULL) { 352609c92feSPaul Moore spin_unlock_bh(&cipso_v4_cache[bkt].lock); 353446fda4fSPaul Moore return 0; 354446fda4fSPaul Moore } 355446fda4fSPaul Moore 356446fda4fSPaul Moore if (prev_entry->activity > 0) 357446fda4fSPaul Moore prev_entry->activity -= 1; 358446fda4fSPaul Moore if (entry->activity > prev_entry->activity && 359446fda4fSPaul Moore entry->activity - prev_entry->activity > 360446fda4fSPaul Moore CIPSO_V4_CACHE_REORDERLIMIT) { 361446fda4fSPaul Moore __list_del(entry->list.prev, entry->list.next); 362446fda4fSPaul Moore __list_add(&entry->list, 363446fda4fSPaul Moore prev_entry->list.prev, 364446fda4fSPaul Moore &prev_entry->list); 365446fda4fSPaul Moore } 366446fda4fSPaul Moore 367609c92feSPaul Moore spin_unlock_bh(&cipso_v4_cache[bkt].lock); 368446fda4fSPaul Moore return 0; 369446fda4fSPaul Moore } 370446fda4fSPaul Moore prev_entry = entry; 371446fda4fSPaul Moore } 372609c92feSPaul Moore spin_unlock_bh(&cipso_v4_cache[bkt].lock); 373446fda4fSPaul Moore 374446fda4fSPaul Moore return -ENOENT; 375446fda4fSPaul Moore } 376446fda4fSPaul Moore 377446fda4fSPaul Moore /** 378446fda4fSPaul Moore * cipso_v4_cache_add - Add an entry to the CIPSO cache 379446fda4fSPaul Moore * @skb: the packet 380446fda4fSPaul Moore * @secattr: the packet's security attributes 381446fda4fSPaul Moore * 382446fda4fSPaul Moore * Description: 383446fda4fSPaul Moore * Add a new entry into the CIPSO label mapping cache. Add the new entry to 384446fda4fSPaul Moore * head of the cache bucket's list, if the cache bucket is out of room remove 385446fda4fSPaul Moore * the last entry in the list first. It is important to note that there is 386446fda4fSPaul Moore * currently no checking for duplicate keys. Returns zero on success, 387446fda4fSPaul Moore * negative values on failure. 388446fda4fSPaul Moore * 389446fda4fSPaul Moore */ 390446fda4fSPaul Moore int cipso_v4_cache_add(const struct sk_buff *skb, 391446fda4fSPaul Moore const struct netlbl_lsm_secattr *secattr) 392446fda4fSPaul Moore { 393446fda4fSPaul Moore int ret_val = -EPERM; 394446fda4fSPaul Moore u32 bkt; 395446fda4fSPaul Moore struct cipso_v4_map_cache_entry *entry = NULL; 396446fda4fSPaul Moore struct cipso_v4_map_cache_entry *old_entry = NULL; 397446fda4fSPaul Moore unsigned char *cipso_ptr; 398446fda4fSPaul Moore u32 cipso_ptr_len; 399446fda4fSPaul Moore 400446fda4fSPaul Moore if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0) 401446fda4fSPaul Moore return 0; 402446fda4fSPaul Moore 403446fda4fSPaul Moore cipso_ptr = CIPSO_V4_OPTPTR(skb); 404446fda4fSPaul Moore cipso_ptr_len = cipso_ptr[1]; 405446fda4fSPaul Moore 406446fda4fSPaul Moore entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 407446fda4fSPaul Moore if (entry == NULL) 408446fda4fSPaul Moore return -ENOMEM; 409fac5d731SArnaldo Carvalho de Melo entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC); 410446fda4fSPaul Moore if (entry->key == NULL) { 411446fda4fSPaul Moore ret_val = -ENOMEM; 412446fda4fSPaul Moore goto cache_add_failure; 413446fda4fSPaul Moore } 414446fda4fSPaul Moore entry->key_len = cipso_ptr_len; 415446fda4fSPaul Moore entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); 416ffb733c6Spaul.moore@hp.com atomic_inc(&secattr->cache->refcount); 417ffb733c6Spaul.moore@hp.com entry->lsm_data = secattr->cache; 418446fda4fSPaul Moore 419446fda4fSPaul Moore bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); 420609c92feSPaul Moore spin_lock_bh(&cipso_v4_cache[bkt].lock); 421446fda4fSPaul Moore if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) { 422446fda4fSPaul Moore list_add(&entry->list, &cipso_v4_cache[bkt].list); 423446fda4fSPaul Moore cipso_v4_cache[bkt].size += 1; 424446fda4fSPaul Moore } else { 425446fda4fSPaul Moore old_entry = list_entry(cipso_v4_cache[bkt].list.prev, 426446fda4fSPaul Moore struct cipso_v4_map_cache_entry, list); 427446fda4fSPaul Moore list_del(&old_entry->list); 428446fda4fSPaul Moore list_add(&entry->list, &cipso_v4_cache[bkt].list); 429446fda4fSPaul Moore cipso_v4_cache_entry_free(old_entry); 430446fda4fSPaul Moore } 431609c92feSPaul Moore spin_unlock_bh(&cipso_v4_cache[bkt].lock); 432446fda4fSPaul Moore 433446fda4fSPaul Moore return 0; 434446fda4fSPaul Moore 435446fda4fSPaul Moore cache_add_failure: 436446fda4fSPaul Moore if (entry) 437446fda4fSPaul Moore cipso_v4_cache_entry_free(entry); 438446fda4fSPaul Moore return ret_val; 439446fda4fSPaul Moore } 440446fda4fSPaul Moore 441446fda4fSPaul Moore /* 442446fda4fSPaul Moore * DOI List Functions 443446fda4fSPaul Moore */ 444446fda4fSPaul Moore 445446fda4fSPaul Moore /** 446446fda4fSPaul Moore * cipso_v4_doi_search - Searches for a DOI definition 447446fda4fSPaul Moore * @doi: the DOI to search for 448446fda4fSPaul Moore * 449446fda4fSPaul Moore * Description: 450446fda4fSPaul Moore * Search the DOI definition list for a DOI definition with a DOI value that 451446fda4fSPaul Moore * matches @doi. The caller is responsibile for calling rcu_read_[un]lock(). 452446fda4fSPaul Moore * Returns a pointer to the DOI definition on success and NULL on failure. 453446fda4fSPaul Moore */ 454446fda4fSPaul Moore static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) 455446fda4fSPaul Moore { 456446fda4fSPaul Moore struct cipso_v4_doi *iter; 457446fda4fSPaul Moore 458446fda4fSPaul Moore list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) 459446fda4fSPaul Moore if (iter->doi == doi && iter->valid) 460446fda4fSPaul Moore return iter; 461446fda4fSPaul Moore return NULL; 462446fda4fSPaul Moore } 463446fda4fSPaul Moore 464446fda4fSPaul Moore /** 465446fda4fSPaul Moore * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine 466446fda4fSPaul Moore * @doi_def: the DOI structure 467446fda4fSPaul Moore * 468446fda4fSPaul Moore * Description: 469446fda4fSPaul Moore * The caller defines a new DOI for use by the CIPSO engine and calls this 470446fda4fSPaul Moore * function to add it to the list of acceptable domains. The caller must 471446fda4fSPaul Moore * ensure that the mapping table specified in @doi_def->map meets all of the 472446fda4fSPaul Moore * requirements of the mapping type (see cipso_ipv4.h for details). Returns 473446fda4fSPaul Moore * zero on success and non-zero on failure. 474446fda4fSPaul Moore * 475446fda4fSPaul Moore */ 476446fda4fSPaul Moore int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) 477446fda4fSPaul Moore { 4786ce61a7cSPaul Moore u32 iter; 4796ce61a7cSPaul Moore 480446fda4fSPaul Moore if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) 481446fda4fSPaul Moore return -EINVAL; 4826ce61a7cSPaul Moore for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { 4836ce61a7cSPaul Moore switch (doi_def->tags[iter]) { 4846ce61a7cSPaul Moore case CIPSO_V4_TAG_RBITMAP: 4856ce61a7cSPaul Moore break; 486484b3669SPaul Moore case CIPSO_V4_TAG_RANGE: 487484b3669SPaul Moore if (doi_def->type != CIPSO_V4_MAP_PASS) 488484b3669SPaul Moore return -EINVAL; 489484b3669SPaul Moore break; 4906ce61a7cSPaul Moore case CIPSO_V4_TAG_INVALID: 4916ce61a7cSPaul Moore if (iter == 0) 4926ce61a7cSPaul Moore return -EINVAL; 4936ce61a7cSPaul Moore break; 494654bbc2aSPaul Moore case CIPSO_V4_TAG_ENUM: 495654bbc2aSPaul Moore if (doi_def->type != CIPSO_V4_MAP_PASS) 496654bbc2aSPaul Moore return -EINVAL; 497654bbc2aSPaul Moore break; 4986ce61a7cSPaul Moore default: 4996ce61a7cSPaul Moore return -EINVAL; 5006ce61a7cSPaul Moore } 5016ce61a7cSPaul Moore } 502446fda4fSPaul Moore 503446fda4fSPaul Moore doi_def->valid = 1; 504446fda4fSPaul Moore INIT_RCU_HEAD(&doi_def->rcu); 505446fda4fSPaul Moore INIT_LIST_HEAD(&doi_def->dom_list); 506446fda4fSPaul Moore 507446fda4fSPaul Moore rcu_read_lock(); 508446fda4fSPaul Moore if (cipso_v4_doi_search(doi_def->doi) != NULL) 509446fda4fSPaul Moore goto doi_add_failure_rlock; 510446fda4fSPaul Moore spin_lock(&cipso_v4_doi_list_lock); 511446fda4fSPaul Moore if (cipso_v4_doi_search(doi_def->doi) != NULL) 512446fda4fSPaul Moore goto doi_add_failure_slock; 513446fda4fSPaul Moore list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list); 514446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 515446fda4fSPaul Moore rcu_read_unlock(); 516446fda4fSPaul Moore 517446fda4fSPaul Moore return 0; 518446fda4fSPaul Moore 519446fda4fSPaul Moore doi_add_failure_slock: 520446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 521446fda4fSPaul Moore doi_add_failure_rlock: 522446fda4fSPaul Moore rcu_read_unlock(); 523446fda4fSPaul Moore return -EEXIST; 524446fda4fSPaul Moore } 525446fda4fSPaul Moore 526446fda4fSPaul Moore /** 527446fda4fSPaul Moore * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine 528446fda4fSPaul Moore * @doi: the DOI value 52932f50cdeSPaul Moore * @audit_secid: the LSM secid to use in the audit message 530446fda4fSPaul Moore * @callback: the DOI cleanup/free callback 531446fda4fSPaul Moore * 532446fda4fSPaul Moore * Description: 533446fda4fSPaul Moore * Removes a DOI definition from the CIPSO engine, @callback is called to 534446fda4fSPaul Moore * free any memory. The NetLabel routines will be called to release their own 535446fda4fSPaul Moore * LSM domain mappings as well as our own domain list. Returns zero on 536446fda4fSPaul Moore * success and negative values on failure. 537446fda4fSPaul Moore * 538446fda4fSPaul Moore */ 53932f50cdeSPaul Moore int cipso_v4_doi_remove(u32 doi, 54095d4e6beSPaul Moore struct netlbl_audit *audit_info, 54132f50cdeSPaul Moore void (*callback) (struct rcu_head * head)) 542446fda4fSPaul Moore { 543446fda4fSPaul Moore struct cipso_v4_doi *doi_def; 544446fda4fSPaul Moore struct cipso_v4_domhsh_entry *dom_iter; 545446fda4fSPaul Moore 546446fda4fSPaul Moore rcu_read_lock(); 547446fda4fSPaul Moore if (cipso_v4_doi_search(doi) != NULL) { 548446fda4fSPaul Moore spin_lock(&cipso_v4_doi_list_lock); 549446fda4fSPaul Moore doi_def = cipso_v4_doi_search(doi); 550446fda4fSPaul Moore if (doi_def == NULL) { 551446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 552446fda4fSPaul Moore rcu_read_unlock(); 553446fda4fSPaul Moore return -ENOENT; 554446fda4fSPaul Moore } 555446fda4fSPaul Moore doi_def->valid = 0; 556446fda4fSPaul Moore list_del_rcu(&doi_def->list); 557446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 558446fda4fSPaul Moore list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) 559446fda4fSPaul Moore if (dom_iter->valid) 56032f50cdeSPaul Moore netlbl_domhsh_remove(dom_iter->domain, 56195d4e6beSPaul Moore audit_info); 562446fda4fSPaul Moore cipso_v4_cache_invalidate(); 563446fda4fSPaul Moore rcu_read_unlock(); 564446fda4fSPaul Moore 565446fda4fSPaul Moore call_rcu(&doi_def->rcu, callback); 566446fda4fSPaul Moore return 0; 567446fda4fSPaul Moore } 568446fda4fSPaul Moore rcu_read_unlock(); 569446fda4fSPaul Moore 570446fda4fSPaul Moore return -ENOENT; 571446fda4fSPaul Moore } 572446fda4fSPaul Moore 573446fda4fSPaul Moore /** 574446fda4fSPaul Moore * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition 575446fda4fSPaul Moore * @doi: the DOI value 576446fda4fSPaul Moore * 577446fda4fSPaul Moore * Description: 578446fda4fSPaul Moore * Searches for a valid DOI definition and if one is found it is returned to 579446fda4fSPaul Moore * the caller. Otherwise NULL is returned. The caller must ensure that 580446fda4fSPaul Moore * rcu_read_lock() is held while accessing the returned definition. 581446fda4fSPaul Moore * 582446fda4fSPaul Moore */ 583446fda4fSPaul Moore struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) 584446fda4fSPaul Moore { 585446fda4fSPaul Moore return cipso_v4_doi_search(doi); 586446fda4fSPaul Moore } 587446fda4fSPaul Moore 588446fda4fSPaul Moore /** 589fcd48280SPaul Moore * cipso_v4_doi_walk - Iterate through the DOI definitions 590fcd48280SPaul Moore * @skip_cnt: skip past this number of DOI definitions, updated 591fcd48280SPaul Moore * @callback: callback for each DOI definition 592fcd48280SPaul Moore * @cb_arg: argument for the callback function 593446fda4fSPaul Moore * 594446fda4fSPaul Moore * Description: 595fcd48280SPaul Moore * Iterate over the DOI definition list, skipping the first @skip_cnt entries. 596fcd48280SPaul Moore * For each entry call @callback, if @callback returns a negative value stop 597fcd48280SPaul Moore * 'walking' through the list and return. Updates the value in @skip_cnt upon 598fcd48280SPaul Moore * return. Returns zero on success, negative values on failure. 599446fda4fSPaul Moore * 600446fda4fSPaul Moore */ 601fcd48280SPaul Moore int cipso_v4_doi_walk(u32 *skip_cnt, 602fcd48280SPaul Moore int (*callback) (struct cipso_v4_doi *doi_def, void *arg), 603fcd48280SPaul Moore void *cb_arg) 604446fda4fSPaul Moore { 605fcd48280SPaul Moore int ret_val = -ENOENT; 606446fda4fSPaul Moore u32 doi_cnt = 0; 607fcd48280SPaul Moore struct cipso_v4_doi *iter_doi; 608446fda4fSPaul Moore 609446fda4fSPaul Moore rcu_read_lock(); 610fcd48280SPaul Moore list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) 611fcd48280SPaul Moore if (iter_doi->valid) { 612fcd48280SPaul Moore if (doi_cnt++ < *skip_cnt) 613fcd48280SPaul Moore continue; 614fcd48280SPaul Moore ret_val = callback(iter_doi, cb_arg); 615fcd48280SPaul Moore if (ret_val < 0) { 616fcd48280SPaul Moore doi_cnt--; 617fcd48280SPaul Moore goto doi_walk_return; 618446fda4fSPaul Moore } 619446fda4fSPaul Moore } 620446fda4fSPaul Moore 621fcd48280SPaul Moore doi_walk_return: 622446fda4fSPaul Moore rcu_read_unlock(); 623fcd48280SPaul Moore *skip_cnt = doi_cnt; 624fcd48280SPaul Moore return ret_val; 625446fda4fSPaul Moore } 626446fda4fSPaul Moore 627446fda4fSPaul Moore /** 628446fda4fSPaul Moore * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition 629446fda4fSPaul Moore * @doi_def: the DOI definition 630446fda4fSPaul Moore * @domain: the domain to add 631446fda4fSPaul Moore * 632446fda4fSPaul Moore * Description: 63359c51591SMichael Opdenacker * Adds the @domain to the DOI specified by @doi_def, this function 634446fda4fSPaul Moore * should only be called by external functions (i.e. NetLabel). This function 635446fda4fSPaul Moore * does allocate memory. Returns zero on success, negative values on failure. 636446fda4fSPaul Moore * 637446fda4fSPaul Moore */ 638446fda4fSPaul Moore int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain) 639446fda4fSPaul Moore { 640446fda4fSPaul Moore struct cipso_v4_domhsh_entry *iter; 641446fda4fSPaul Moore struct cipso_v4_domhsh_entry *new_dom; 642446fda4fSPaul Moore 643446fda4fSPaul Moore new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL); 644446fda4fSPaul Moore if (new_dom == NULL) 645446fda4fSPaul Moore return -ENOMEM; 646446fda4fSPaul Moore if (domain) { 647446fda4fSPaul Moore new_dom->domain = kstrdup(domain, GFP_KERNEL); 648446fda4fSPaul Moore if (new_dom->domain == NULL) { 649446fda4fSPaul Moore kfree(new_dom); 650446fda4fSPaul Moore return -ENOMEM; 651446fda4fSPaul Moore } 652446fda4fSPaul Moore } 653446fda4fSPaul Moore new_dom->valid = 1; 654446fda4fSPaul Moore INIT_RCU_HEAD(&new_dom->rcu); 655446fda4fSPaul Moore 656446fda4fSPaul Moore rcu_read_lock(); 657446fda4fSPaul Moore spin_lock(&cipso_v4_doi_list_lock); 658446fda4fSPaul Moore list_for_each_entry_rcu(iter, &doi_def->dom_list, list) 659446fda4fSPaul Moore if (iter->valid && 660446fda4fSPaul Moore ((domain != NULL && iter->domain != NULL && 661446fda4fSPaul Moore strcmp(iter->domain, domain) == 0) || 662446fda4fSPaul Moore (domain == NULL && iter->domain == NULL))) { 663446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 664446fda4fSPaul Moore rcu_read_unlock(); 665446fda4fSPaul Moore kfree(new_dom->domain); 666446fda4fSPaul Moore kfree(new_dom); 667446fda4fSPaul Moore return -EEXIST; 668446fda4fSPaul Moore } 669446fda4fSPaul Moore list_add_tail_rcu(&new_dom->list, &doi_def->dom_list); 670446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 671446fda4fSPaul Moore rcu_read_unlock(); 672446fda4fSPaul Moore 673446fda4fSPaul Moore return 0; 674446fda4fSPaul Moore } 675446fda4fSPaul Moore 676446fda4fSPaul Moore /** 677446fda4fSPaul Moore * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition 678446fda4fSPaul Moore * @doi_def: the DOI definition 679446fda4fSPaul Moore * @domain: the domain to remove 680446fda4fSPaul Moore * 681446fda4fSPaul Moore * Description: 682446fda4fSPaul Moore * Removes the @domain from the DOI specified by @doi_def, this function 683446fda4fSPaul Moore * should only be called by external functions (i.e. NetLabel). Returns zero 684446fda4fSPaul Moore * on success and negative values on error. 685446fda4fSPaul Moore * 686446fda4fSPaul Moore */ 687446fda4fSPaul Moore int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, 688446fda4fSPaul Moore const char *domain) 689446fda4fSPaul Moore { 690446fda4fSPaul Moore struct cipso_v4_domhsh_entry *iter; 691446fda4fSPaul Moore 692446fda4fSPaul Moore rcu_read_lock(); 693446fda4fSPaul Moore spin_lock(&cipso_v4_doi_list_lock); 694446fda4fSPaul Moore list_for_each_entry_rcu(iter, &doi_def->dom_list, list) 695446fda4fSPaul Moore if (iter->valid && 696446fda4fSPaul Moore ((domain != NULL && iter->domain != NULL && 697446fda4fSPaul Moore strcmp(iter->domain, domain) == 0) || 698446fda4fSPaul Moore (domain == NULL && iter->domain == NULL))) { 699446fda4fSPaul Moore iter->valid = 0; 700446fda4fSPaul Moore list_del_rcu(&iter->list); 701446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 702446fda4fSPaul Moore rcu_read_unlock(); 703446fda4fSPaul Moore call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free); 704446fda4fSPaul Moore 705446fda4fSPaul Moore return 0; 706446fda4fSPaul Moore } 707446fda4fSPaul Moore spin_unlock(&cipso_v4_doi_list_lock); 708446fda4fSPaul Moore rcu_read_unlock(); 709446fda4fSPaul Moore 710446fda4fSPaul Moore return -ENOENT; 711446fda4fSPaul Moore } 712446fda4fSPaul Moore 713446fda4fSPaul Moore /* 714446fda4fSPaul Moore * Label Mapping Functions 715446fda4fSPaul Moore */ 716446fda4fSPaul Moore 717446fda4fSPaul Moore /** 718446fda4fSPaul Moore * cipso_v4_map_lvl_valid - Checks to see if the given level is understood 719446fda4fSPaul Moore * @doi_def: the DOI definition 720446fda4fSPaul Moore * @level: the level to check 721446fda4fSPaul Moore * 722446fda4fSPaul Moore * Description: 723446fda4fSPaul Moore * Checks the given level against the given DOI definition and returns a 724446fda4fSPaul Moore * negative value if the level does not have a valid mapping and a zero value 725446fda4fSPaul Moore * if the level is defined by the DOI. 726446fda4fSPaul Moore * 727446fda4fSPaul Moore */ 728446fda4fSPaul Moore static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level) 729446fda4fSPaul Moore { 730446fda4fSPaul Moore switch (doi_def->type) { 731446fda4fSPaul Moore case CIPSO_V4_MAP_PASS: 732446fda4fSPaul Moore return 0; 733446fda4fSPaul Moore case CIPSO_V4_MAP_STD: 734446fda4fSPaul Moore if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) 735446fda4fSPaul Moore return 0; 736446fda4fSPaul Moore break; 737446fda4fSPaul Moore } 738446fda4fSPaul Moore 739446fda4fSPaul Moore return -EFAULT; 740446fda4fSPaul Moore } 741446fda4fSPaul Moore 742446fda4fSPaul Moore /** 743446fda4fSPaul Moore * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network 744446fda4fSPaul Moore * @doi_def: the DOI definition 745446fda4fSPaul Moore * @host_lvl: the host MLS level 746446fda4fSPaul Moore * @net_lvl: the network/CIPSO MLS level 747446fda4fSPaul Moore * 748446fda4fSPaul Moore * Description: 749446fda4fSPaul Moore * Perform a label mapping to translate a local MLS level to the correct 750446fda4fSPaul Moore * CIPSO level using the given DOI definition. Returns zero on success, 751446fda4fSPaul Moore * negative values otherwise. 752446fda4fSPaul Moore * 753446fda4fSPaul Moore */ 754446fda4fSPaul Moore static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def, 755446fda4fSPaul Moore u32 host_lvl, 756446fda4fSPaul Moore u32 *net_lvl) 757446fda4fSPaul Moore { 758446fda4fSPaul Moore switch (doi_def->type) { 759446fda4fSPaul Moore case CIPSO_V4_MAP_PASS: 760446fda4fSPaul Moore *net_lvl = host_lvl; 761446fda4fSPaul Moore return 0; 762446fda4fSPaul Moore case CIPSO_V4_MAP_STD: 763c6387a86SPaul Moore if (host_lvl < doi_def->map.std->lvl.local_size && 764c6387a86SPaul Moore doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) { 765446fda4fSPaul Moore *net_lvl = doi_def->map.std->lvl.local[host_lvl]; 766446fda4fSPaul Moore return 0; 767446fda4fSPaul Moore } 768c6387a86SPaul Moore return -EPERM; 769446fda4fSPaul Moore } 770446fda4fSPaul Moore 771446fda4fSPaul Moore return -EINVAL; 772446fda4fSPaul Moore } 773446fda4fSPaul Moore 774446fda4fSPaul Moore /** 775446fda4fSPaul Moore * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host 776446fda4fSPaul Moore * @doi_def: the DOI definition 777446fda4fSPaul Moore * @net_lvl: the network/CIPSO MLS level 778446fda4fSPaul Moore * @host_lvl: the host MLS level 779446fda4fSPaul Moore * 780446fda4fSPaul Moore * Description: 781446fda4fSPaul Moore * Perform a label mapping to translate a CIPSO level to the correct local MLS 782446fda4fSPaul Moore * level using the given DOI definition. Returns zero on success, negative 783446fda4fSPaul Moore * values otherwise. 784446fda4fSPaul Moore * 785446fda4fSPaul Moore */ 786446fda4fSPaul Moore static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def, 787446fda4fSPaul Moore u32 net_lvl, 788446fda4fSPaul Moore u32 *host_lvl) 789446fda4fSPaul Moore { 790446fda4fSPaul Moore struct cipso_v4_std_map_tbl *map_tbl; 791446fda4fSPaul Moore 792446fda4fSPaul Moore switch (doi_def->type) { 793446fda4fSPaul Moore case CIPSO_V4_MAP_PASS: 794446fda4fSPaul Moore *host_lvl = net_lvl; 795446fda4fSPaul Moore return 0; 796446fda4fSPaul Moore case CIPSO_V4_MAP_STD: 797446fda4fSPaul Moore map_tbl = doi_def->map.std; 798446fda4fSPaul Moore if (net_lvl < map_tbl->lvl.cipso_size && 799446fda4fSPaul Moore map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { 800446fda4fSPaul Moore *host_lvl = doi_def->map.std->lvl.cipso[net_lvl]; 801446fda4fSPaul Moore return 0; 802446fda4fSPaul Moore } 803c6387a86SPaul Moore return -EPERM; 804446fda4fSPaul Moore } 805446fda4fSPaul Moore 806446fda4fSPaul Moore return -EINVAL; 807446fda4fSPaul Moore } 808446fda4fSPaul Moore 809446fda4fSPaul Moore /** 810446fda4fSPaul Moore * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid 811446fda4fSPaul Moore * @doi_def: the DOI definition 812446fda4fSPaul Moore * @bitmap: category bitmap 813446fda4fSPaul Moore * @bitmap_len: bitmap length in bytes 814446fda4fSPaul Moore * 815446fda4fSPaul Moore * Description: 816446fda4fSPaul Moore * Checks the given category bitmap against the given DOI definition and 817446fda4fSPaul Moore * returns a negative value if any of the categories in the bitmap do not have 818446fda4fSPaul Moore * a valid mapping and a zero value if all of the categories are valid. 819446fda4fSPaul Moore * 820446fda4fSPaul Moore */ 821446fda4fSPaul Moore static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, 822446fda4fSPaul Moore const unsigned char *bitmap, 823446fda4fSPaul Moore u32 bitmap_len) 824446fda4fSPaul Moore { 825446fda4fSPaul Moore int cat = -1; 826446fda4fSPaul Moore u32 bitmap_len_bits = bitmap_len * 8; 827044a68edSPaul Moore u32 cipso_cat_size; 828044a68edSPaul Moore u32 *cipso_array; 829446fda4fSPaul Moore 830446fda4fSPaul Moore switch (doi_def->type) { 831446fda4fSPaul Moore case CIPSO_V4_MAP_PASS: 832446fda4fSPaul Moore return 0; 833446fda4fSPaul Moore case CIPSO_V4_MAP_STD: 834044a68edSPaul Moore cipso_cat_size = doi_def->map.std->cat.cipso_size; 835044a68edSPaul Moore cipso_array = doi_def->map.std->cat.cipso; 836446fda4fSPaul Moore for (;;) { 837446fda4fSPaul Moore cat = cipso_v4_bitmap_walk(bitmap, 838446fda4fSPaul Moore bitmap_len_bits, 839446fda4fSPaul Moore cat + 1, 840446fda4fSPaul Moore 1); 841446fda4fSPaul Moore if (cat < 0) 842446fda4fSPaul Moore break; 843446fda4fSPaul Moore if (cat >= cipso_cat_size || 844446fda4fSPaul Moore cipso_array[cat] >= CIPSO_V4_INV_CAT) 845446fda4fSPaul Moore return -EFAULT; 846446fda4fSPaul Moore } 847446fda4fSPaul Moore 848446fda4fSPaul Moore if (cat == -1) 849446fda4fSPaul Moore return 0; 850446fda4fSPaul Moore break; 851446fda4fSPaul Moore } 852446fda4fSPaul Moore 853446fda4fSPaul Moore return -EFAULT; 854446fda4fSPaul Moore } 855446fda4fSPaul Moore 856446fda4fSPaul Moore /** 857446fda4fSPaul Moore * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network 858446fda4fSPaul Moore * @doi_def: the DOI definition 85902752760SPaul Moore * @secattr: the security attributes 860446fda4fSPaul Moore * @net_cat: the zero'd out category bitmap in network/CIPSO format 861446fda4fSPaul Moore * @net_cat_len: the length of the CIPSO bitmap in bytes 862446fda4fSPaul Moore * 863446fda4fSPaul Moore * Description: 864446fda4fSPaul Moore * Perform a label mapping to translate a local MLS category bitmap to the 865446fda4fSPaul Moore * correct CIPSO bitmap using the given DOI definition. Returns the minimum 866446fda4fSPaul Moore * size in bytes of the network bitmap on success, negative values otherwise. 867446fda4fSPaul Moore * 868446fda4fSPaul Moore */ 869446fda4fSPaul Moore static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, 87002752760SPaul Moore const struct netlbl_lsm_secattr *secattr, 871446fda4fSPaul Moore unsigned char *net_cat, 872446fda4fSPaul Moore u32 net_cat_len) 873446fda4fSPaul Moore { 874446fda4fSPaul Moore int host_spot = -1; 87502752760SPaul Moore u32 net_spot = CIPSO_V4_INV_CAT; 876446fda4fSPaul Moore u32 net_spot_max = 0; 877446fda4fSPaul Moore u32 net_clen_bits = net_cat_len * 8; 87802752760SPaul Moore u32 host_cat_size = 0; 87902752760SPaul Moore u32 *host_cat_array = NULL; 88002752760SPaul Moore 88102752760SPaul Moore if (doi_def->type == CIPSO_V4_MAP_STD) { 88202752760SPaul Moore host_cat_size = doi_def->map.std->cat.local_size; 88302752760SPaul Moore host_cat_array = doi_def->map.std->cat.local; 88402752760SPaul Moore } 88502752760SPaul Moore 88602752760SPaul Moore for (;;) { 88702752760SPaul Moore host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, 88802752760SPaul Moore host_spot + 1); 88902752760SPaul Moore if (host_spot < 0) 89002752760SPaul Moore break; 891446fda4fSPaul Moore 892446fda4fSPaul Moore switch (doi_def->type) { 893446fda4fSPaul Moore case CIPSO_V4_MAP_PASS: 89402752760SPaul Moore net_spot = host_spot; 895446fda4fSPaul Moore break; 89602752760SPaul Moore case CIPSO_V4_MAP_STD: 897446fda4fSPaul Moore if (host_spot >= host_cat_size) 898446fda4fSPaul Moore return -EPERM; 899446fda4fSPaul Moore net_spot = host_cat_array[host_spot]; 9009fade4bfSPaul Moore if (net_spot >= CIPSO_V4_INV_CAT) 9019fade4bfSPaul Moore return -EPERM; 90202752760SPaul Moore break; 90302752760SPaul Moore } 904446fda4fSPaul Moore if (net_spot >= net_clen_bits) 905446fda4fSPaul Moore return -ENOSPC; 906446fda4fSPaul Moore cipso_v4_bitmap_setbit(net_cat, net_spot, 1); 907446fda4fSPaul Moore 908446fda4fSPaul Moore if (net_spot > net_spot_max) 909446fda4fSPaul Moore net_spot_max = net_spot; 910446fda4fSPaul Moore } 911446fda4fSPaul Moore 912446fda4fSPaul Moore if (++net_spot_max % 8) 913446fda4fSPaul Moore return net_spot_max / 8 + 1; 914446fda4fSPaul Moore return net_spot_max / 8; 915446fda4fSPaul Moore } 916446fda4fSPaul Moore 917446fda4fSPaul Moore /** 918446fda4fSPaul Moore * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host 919446fda4fSPaul Moore * @doi_def: the DOI definition 920446fda4fSPaul Moore * @net_cat: the category bitmap in network/CIPSO format 921446fda4fSPaul Moore * @net_cat_len: the length of the CIPSO bitmap in bytes 92202752760SPaul Moore * @secattr: the security attributes 923446fda4fSPaul Moore * 924446fda4fSPaul Moore * Description: 925446fda4fSPaul Moore * Perform a label mapping to translate a CIPSO bitmap to the correct local 92602752760SPaul Moore * MLS category bitmap using the given DOI definition. Returns zero on 92702752760SPaul Moore * success, negative values on failure. 928446fda4fSPaul Moore * 929446fda4fSPaul Moore */ 930446fda4fSPaul Moore static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, 931446fda4fSPaul Moore const unsigned char *net_cat, 932446fda4fSPaul Moore u32 net_cat_len, 93302752760SPaul Moore struct netlbl_lsm_secattr *secattr) 934446fda4fSPaul Moore { 93502752760SPaul Moore int ret_val; 936446fda4fSPaul Moore int net_spot = -1; 93702752760SPaul Moore u32 host_spot = CIPSO_V4_INV_CAT; 938446fda4fSPaul Moore u32 net_clen_bits = net_cat_len * 8; 93902752760SPaul Moore u32 net_cat_size = 0; 94002752760SPaul Moore u32 *net_cat_array = NULL; 941446fda4fSPaul Moore 94202752760SPaul Moore if (doi_def->type == CIPSO_V4_MAP_STD) { 943044a68edSPaul Moore net_cat_size = doi_def->map.std->cat.cipso_size; 944044a68edSPaul Moore net_cat_array = doi_def->map.std->cat.cipso; 94502752760SPaul Moore } 94602752760SPaul Moore 947446fda4fSPaul Moore for (;;) { 948446fda4fSPaul Moore net_spot = cipso_v4_bitmap_walk(net_cat, 949446fda4fSPaul Moore net_clen_bits, 950446fda4fSPaul Moore net_spot + 1, 951446fda4fSPaul Moore 1); 95202752760SPaul Moore if (net_spot < 0) { 95302752760SPaul Moore if (net_spot == -2) 95402752760SPaul Moore return -EFAULT; 95502752760SPaul Moore return 0; 95602752760SPaul Moore } 957446fda4fSPaul Moore 95802752760SPaul Moore switch (doi_def->type) { 95902752760SPaul Moore case CIPSO_V4_MAP_PASS: 96002752760SPaul Moore host_spot = net_spot; 96102752760SPaul Moore break; 96202752760SPaul Moore case CIPSO_V4_MAP_STD: 96302752760SPaul Moore if (net_spot >= net_cat_size) 96402752760SPaul Moore return -EPERM; 965446fda4fSPaul Moore host_spot = net_cat_array[net_spot]; 9669fade4bfSPaul Moore if (host_spot >= CIPSO_V4_INV_CAT) 9679fade4bfSPaul Moore return -EPERM; 96802752760SPaul Moore break; 969446fda4fSPaul Moore } 97002752760SPaul Moore ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, 97102752760SPaul Moore host_spot, 97202752760SPaul Moore GFP_ATOMIC); 97302752760SPaul Moore if (ret_val != 0) 97402752760SPaul Moore return ret_val; 975446fda4fSPaul Moore } 976446fda4fSPaul Moore 977446fda4fSPaul Moore return -EINVAL; 978446fda4fSPaul Moore } 979446fda4fSPaul Moore 980654bbc2aSPaul Moore /** 981654bbc2aSPaul Moore * cipso_v4_map_cat_enum_valid - Checks to see if the categories are valid 982654bbc2aSPaul Moore * @doi_def: the DOI definition 983654bbc2aSPaul Moore * @enumcat: category list 984654bbc2aSPaul Moore * @enumcat_len: length of the category list in bytes 985654bbc2aSPaul Moore * 986654bbc2aSPaul Moore * Description: 987654bbc2aSPaul Moore * Checks the given categories against the given DOI definition and returns a 988654bbc2aSPaul Moore * negative value if any of the categories do not have a valid mapping and a 989654bbc2aSPaul Moore * zero value if all of the categories are valid. 990654bbc2aSPaul Moore * 991654bbc2aSPaul Moore */ 992654bbc2aSPaul Moore static int cipso_v4_map_cat_enum_valid(const struct cipso_v4_doi *doi_def, 993654bbc2aSPaul Moore const unsigned char *enumcat, 994654bbc2aSPaul Moore u32 enumcat_len) 995654bbc2aSPaul Moore { 996654bbc2aSPaul Moore u16 cat; 997654bbc2aSPaul Moore int cat_prev = -1; 998654bbc2aSPaul Moore u32 iter; 999654bbc2aSPaul Moore 1000654bbc2aSPaul Moore if (doi_def->type != CIPSO_V4_MAP_PASS || enumcat_len & 0x01) 1001654bbc2aSPaul Moore return -EFAULT; 1002654bbc2aSPaul Moore 1003654bbc2aSPaul Moore for (iter = 0; iter < enumcat_len; iter += 2) { 1004*50e5d35cSPaul Moore cat = ntohs(get_unaligned((__be16 *)&enumcat[iter])); 1005654bbc2aSPaul Moore if (cat <= cat_prev) 1006654bbc2aSPaul Moore return -EFAULT; 1007654bbc2aSPaul Moore cat_prev = cat; 1008654bbc2aSPaul Moore } 1009654bbc2aSPaul Moore 1010654bbc2aSPaul Moore return 0; 1011654bbc2aSPaul Moore } 1012654bbc2aSPaul Moore 1013654bbc2aSPaul Moore /** 1014654bbc2aSPaul Moore * cipso_v4_map_cat_enum_hton - Perform a category mapping from host to network 1015654bbc2aSPaul Moore * @doi_def: the DOI definition 1016654bbc2aSPaul Moore * @secattr: the security attributes 1017654bbc2aSPaul Moore * @net_cat: the zero'd out category list in network/CIPSO format 1018654bbc2aSPaul Moore * @net_cat_len: the length of the CIPSO category list in bytes 1019654bbc2aSPaul Moore * 1020654bbc2aSPaul Moore * Description: 1021654bbc2aSPaul Moore * Perform a label mapping to translate a local MLS category bitmap to the 1022654bbc2aSPaul Moore * correct CIPSO category list using the given DOI definition. Returns the 1023654bbc2aSPaul Moore * size in bytes of the network category bitmap on success, negative values 1024654bbc2aSPaul Moore * otherwise. 1025654bbc2aSPaul Moore * 1026654bbc2aSPaul Moore */ 1027654bbc2aSPaul Moore static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, 1028654bbc2aSPaul Moore const struct netlbl_lsm_secattr *secattr, 1029654bbc2aSPaul Moore unsigned char *net_cat, 1030654bbc2aSPaul Moore u32 net_cat_len) 1031654bbc2aSPaul Moore { 1032654bbc2aSPaul Moore int cat = -1; 1033654bbc2aSPaul Moore u32 cat_iter = 0; 1034654bbc2aSPaul Moore 1035654bbc2aSPaul Moore for (;;) { 1036654bbc2aSPaul Moore cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); 1037654bbc2aSPaul Moore if (cat < 0) 1038654bbc2aSPaul Moore break; 1039654bbc2aSPaul Moore if ((cat_iter + 2) > net_cat_len) 1040654bbc2aSPaul Moore return -ENOSPC; 1041654bbc2aSPaul Moore 1042654bbc2aSPaul Moore *((__be16 *)&net_cat[cat_iter]) = htons(cat); 1043654bbc2aSPaul Moore cat_iter += 2; 1044654bbc2aSPaul Moore } 1045654bbc2aSPaul Moore 1046654bbc2aSPaul Moore return cat_iter; 1047654bbc2aSPaul Moore } 1048654bbc2aSPaul Moore 1049654bbc2aSPaul Moore /** 1050654bbc2aSPaul Moore * cipso_v4_map_cat_enum_ntoh - Perform a category mapping from network to host 1051654bbc2aSPaul Moore * @doi_def: the DOI definition 1052654bbc2aSPaul Moore * @net_cat: the category list in network/CIPSO format 1053654bbc2aSPaul Moore * @net_cat_len: the length of the CIPSO bitmap in bytes 1054654bbc2aSPaul Moore * @secattr: the security attributes 1055654bbc2aSPaul Moore * 1056654bbc2aSPaul Moore * Description: 1057654bbc2aSPaul Moore * Perform a label mapping to translate a CIPSO category list to the correct 1058654bbc2aSPaul Moore * local MLS category bitmap using the given DOI definition. Returns zero on 1059654bbc2aSPaul Moore * success, negative values on failure. 1060654bbc2aSPaul Moore * 1061654bbc2aSPaul Moore */ 1062654bbc2aSPaul Moore static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, 1063654bbc2aSPaul Moore const unsigned char *net_cat, 1064654bbc2aSPaul Moore u32 net_cat_len, 1065654bbc2aSPaul Moore struct netlbl_lsm_secattr *secattr) 1066654bbc2aSPaul Moore { 1067654bbc2aSPaul Moore int ret_val; 1068654bbc2aSPaul Moore u32 iter; 1069654bbc2aSPaul Moore 1070654bbc2aSPaul Moore for (iter = 0; iter < net_cat_len; iter += 2) { 1071654bbc2aSPaul Moore ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, 1072*50e5d35cSPaul Moore ntohs(get_unaligned((__be16 *)&net_cat[iter])), 1073654bbc2aSPaul Moore GFP_ATOMIC); 1074654bbc2aSPaul Moore if (ret_val != 0) 1075654bbc2aSPaul Moore return ret_val; 1076654bbc2aSPaul Moore } 1077654bbc2aSPaul Moore 1078654bbc2aSPaul Moore return 0; 1079654bbc2aSPaul Moore } 1080654bbc2aSPaul Moore 1081484b3669SPaul Moore /** 1082484b3669SPaul Moore * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid 1083484b3669SPaul Moore * @doi_def: the DOI definition 1084484b3669SPaul Moore * @rngcat: category list 1085484b3669SPaul Moore * @rngcat_len: length of the category list in bytes 1086484b3669SPaul Moore * 1087484b3669SPaul Moore * Description: 1088484b3669SPaul Moore * Checks the given categories against the given DOI definition and returns a 1089484b3669SPaul Moore * negative value if any of the categories do not have a valid mapping and a 1090484b3669SPaul Moore * zero value if all of the categories are valid. 1091484b3669SPaul Moore * 1092484b3669SPaul Moore */ 1093484b3669SPaul Moore static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def, 1094484b3669SPaul Moore const unsigned char *rngcat, 1095484b3669SPaul Moore u32 rngcat_len) 1096484b3669SPaul Moore { 1097484b3669SPaul Moore u16 cat_high; 1098484b3669SPaul Moore u16 cat_low; 1099484b3669SPaul Moore u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1; 1100484b3669SPaul Moore u32 iter; 1101484b3669SPaul Moore 1102484b3669SPaul Moore if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01) 1103484b3669SPaul Moore return -EFAULT; 1104484b3669SPaul Moore 1105484b3669SPaul Moore for (iter = 0; iter < rngcat_len; iter += 4) { 1106*50e5d35cSPaul Moore cat_high = ntohs(get_unaligned((__be16 *)&rngcat[iter])); 1107484b3669SPaul Moore if ((iter + 4) <= rngcat_len) 1108*50e5d35cSPaul Moore cat_low = ntohs( 1109*50e5d35cSPaul Moore get_unaligned((__be16 *)&rngcat[iter + 2])); 1110484b3669SPaul Moore else 1111484b3669SPaul Moore cat_low = 0; 1112484b3669SPaul Moore 1113484b3669SPaul Moore if (cat_high > cat_prev) 1114484b3669SPaul Moore return -EFAULT; 1115484b3669SPaul Moore 1116484b3669SPaul Moore cat_prev = cat_low; 1117484b3669SPaul Moore } 1118484b3669SPaul Moore 1119484b3669SPaul Moore return 0; 1120484b3669SPaul Moore } 1121484b3669SPaul Moore 1122484b3669SPaul Moore /** 1123484b3669SPaul Moore * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network 1124484b3669SPaul Moore * @doi_def: the DOI definition 1125484b3669SPaul Moore * @secattr: the security attributes 1126484b3669SPaul Moore * @net_cat: the zero'd out category list in network/CIPSO format 1127484b3669SPaul Moore * @net_cat_len: the length of the CIPSO category list in bytes 1128484b3669SPaul Moore * 1129484b3669SPaul Moore * Description: 1130484b3669SPaul Moore * Perform a label mapping to translate a local MLS category bitmap to the 1131484b3669SPaul Moore * correct CIPSO category list using the given DOI definition. Returns the 1132484b3669SPaul Moore * size in bytes of the network category bitmap on success, negative values 1133484b3669SPaul Moore * otherwise. 1134484b3669SPaul Moore * 1135484b3669SPaul Moore */ 1136484b3669SPaul Moore static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, 1137484b3669SPaul Moore const struct netlbl_lsm_secattr *secattr, 1138484b3669SPaul Moore unsigned char *net_cat, 1139484b3669SPaul Moore u32 net_cat_len) 1140484b3669SPaul Moore { 1141484b3669SPaul Moore int iter = -1; 1142f998e8cbSPaul Moore u16 array[CIPSO_V4_TAG_RNG_CAT_MAX * 2]; 1143484b3669SPaul Moore u32 array_cnt = 0; 1144484b3669SPaul Moore u32 cat_size = 0; 1145484b3669SPaul Moore 1146f998e8cbSPaul Moore /* make sure we don't overflow the 'array[]' variable */ 1147128c6b6cSPaul Moore if (net_cat_len > 1148128c6b6cSPaul Moore (CIPSO_V4_OPT_LEN_MAX - CIPSO_V4_HDR_LEN - CIPSO_V4_TAG_RNG_BLEN)) 1149128c6b6cSPaul Moore return -ENOSPC; 1150484b3669SPaul Moore 1151484b3669SPaul Moore for (;;) { 1152484b3669SPaul Moore iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); 1153484b3669SPaul Moore if (iter < 0) 1154484b3669SPaul Moore break; 1155484b3669SPaul Moore cat_size += (iter == 0 ? 0 : sizeof(u16)); 1156484b3669SPaul Moore if (cat_size > net_cat_len) 1157484b3669SPaul Moore return -ENOSPC; 1158484b3669SPaul Moore array[array_cnt++] = iter; 1159484b3669SPaul Moore 1160484b3669SPaul Moore iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); 1161484b3669SPaul Moore if (iter < 0) 1162484b3669SPaul Moore return -EFAULT; 1163484b3669SPaul Moore cat_size += sizeof(u16); 1164484b3669SPaul Moore if (cat_size > net_cat_len) 1165484b3669SPaul Moore return -ENOSPC; 1166484b3669SPaul Moore array[array_cnt++] = iter; 1167484b3669SPaul Moore } 1168484b3669SPaul Moore 1169484b3669SPaul Moore for (iter = 0; array_cnt > 0;) { 1170484b3669SPaul Moore *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]); 1171484b3669SPaul Moore iter += 2; 1172484b3669SPaul Moore array_cnt--; 1173484b3669SPaul Moore if (array[array_cnt] != 0) { 1174484b3669SPaul Moore *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]); 1175484b3669SPaul Moore iter += 2; 1176484b3669SPaul Moore } 1177484b3669SPaul Moore } 1178484b3669SPaul Moore 1179484b3669SPaul Moore return cat_size; 1180484b3669SPaul Moore } 1181484b3669SPaul Moore 1182484b3669SPaul Moore /** 1183484b3669SPaul Moore * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host 1184484b3669SPaul Moore * @doi_def: the DOI definition 1185484b3669SPaul Moore * @net_cat: the category list in network/CIPSO format 1186484b3669SPaul Moore * @net_cat_len: the length of the CIPSO bitmap in bytes 1187484b3669SPaul Moore * @secattr: the security attributes 1188484b3669SPaul Moore * 1189484b3669SPaul Moore * Description: 1190484b3669SPaul Moore * Perform a label mapping to translate a CIPSO category list to the correct 1191484b3669SPaul Moore * local MLS category bitmap using the given DOI definition. Returns zero on 1192484b3669SPaul Moore * success, negative values on failure. 1193484b3669SPaul Moore * 1194484b3669SPaul Moore */ 1195484b3669SPaul Moore static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, 1196484b3669SPaul Moore const unsigned char *net_cat, 1197484b3669SPaul Moore u32 net_cat_len, 1198484b3669SPaul Moore struct netlbl_lsm_secattr *secattr) 1199484b3669SPaul Moore { 1200484b3669SPaul Moore int ret_val; 1201484b3669SPaul Moore u32 net_iter; 1202484b3669SPaul Moore u16 cat_low; 1203484b3669SPaul Moore u16 cat_high; 1204484b3669SPaul Moore 1205484b3669SPaul Moore for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) { 1206*50e5d35cSPaul Moore cat_high = ntohs(get_unaligned((__be16 *)&net_cat[net_iter])); 1207484b3669SPaul Moore if ((net_iter + 4) <= net_cat_len) 1208*50e5d35cSPaul Moore cat_low = ntohs( 1209*50e5d35cSPaul Moore get_unaligned((__be16 *)&net_cat[net_iter + 2])); 1210484b3669SPaul Moore else 1211484b3669SPaul Moore cat_low = 0; 1212484b3669SPaul Moore 1213484b3669SPaul Moore ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, 1214484b3669SPaul Moore cat_low, 1215484b3669SPaul Moore cat_high, 1216484b3669SPaul Moore GFP_ATOMIC); 1217484b3669SPaul Moore if (ret_val != 0) 1218484b3669SPaul Moore return ret_val; 1219484b3669SPaul Moore } 1220484b3669SPaul Moore 1221484b3669SPaul Moore return 0; 1222484b3669SPaul Moore } 1223484b3669SPaul Moore 1224446fda4fSPaul Moore /* 1225446fda4fSPaul Moore * Protocol Handling Functions 1226446fda4fSPaul Moore */ 1227446fda4fSPaul Moore 1228446fda4fSPaul Moore /** 1229446fda4fSPaul Moore * cipso_v4_gentag_hdr - Generate a CIPSO option header 1230446fda4fSPaul Moore * @doi_def: the DOI definition 123191b1ed0aSPaul Moore * @len: the total tag length in bytes, not including this header 1232446fda4fSPaul Moore * @buf: the CIPSO option buffer 1233446fda4fSPaul Moore * 1234446fda4fSPaul Moore * Description: 123591b1ed0aSPaul Moore * Write a CIPSO header into the beginning of @buffer. 1236446fda4fSPaul Moore * 1237446fda4fSPaul Moore */ 123891b1ed0aSPaul Moore static void cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, 123991b1ed0aSPaul Moore unsigned char *buf, 124091b1ed0aSPaul Moore u32 len) 1241446fda4fSPaul Moore { 1242446fda4fSPaul Moore buf[0] = IPOPT_CIPSO; 1243446fda4fSPaul Moore buf[1] = CIPSO_V4_HDR_LEN + len; 1244714e85beSAl Viro *(__be32 *)&buf[2] = htonl(doi_def->doi); 1245446fda4fSPaul Moore } 1246446fda4fSPaul Moore 1247446fda4fSPaul Moore /** 1248446fda4fSPaul Moore * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) 1249446fda4fSPaul Moore * @doi_def: the DOI definition 1250446fda4fSPaul Moore * @secattr: the security attributes 1251446fda4fSPaul Moore * @buffer: the option buffer 1252446fda4fSPaul Moore * @buffer_len: length of buffer in bytes 1253446fda4fSPaul Moore * 1254446fda4fSPaul Moore * Description: 1255446fda4fSPaul Moore * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The 1256446fda4fSPaul Moore * actual buffer length may be larger than the indicated size due to 125791b1ed0aSPaul Moore * translation between host and network category bitmaps. Returns the size of 125891b1ed0aSPaul Moore * the tag on success, negative values on failure. 1259446fda4fSPaul Moore * 1260446fda4fSPaul Moore */ 1261446fda4fSPaul Moore static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, 1262446fda4fSPaul Moore const struct netlbl_lsm_secattr *secattr, 126391b1ed0aSPaul Moore unsigned char *buffer, 126491b1ed0aSPaul Moore u32 buffer_len) 1265446fda4fSPaul Moore { 1266701a90baSPaul Moore int ret_val; 126791b1ed0aSPaul Moore u32 tag_len; 1268446fda4fSPaul Moore u32 level; 1269446fda4fSPaul Moore 1270701a90baSPaul Moore if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) 1271701a90baSPaul Moore return -EPERM; 1272701a90baSPaul Moore 127391b1ed0aSPaul Moore ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 127491b1ed0aSPaul Moore if (ret_val != 0) 127591b1ed0aSPaul Moore return ret_val; 1276446fda4fSPaul Moore 127791b1ed0aSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 1278446fda4fSPaul Moore ret_val = cipso_v4_map_cat_rbm_hton(doi_def, 127902752760SPaul Moore secattr, 128091b1ed0aSPaul Moore &buffer[4], 128191b1ed0aSPaul Moore buffer_len - 4); 1282446fda4fSPaul Moore if (ret_val < 0) 128391b1ed0aSPaul Moore return ret_val; 1284446fda4fSPaul Moore 1285446fda4fSPaul Moore /* This will send packets using the "optimized" format when 1286446fda4fSPaul Moore * possibile as specified in section 3.4.2.6 of the 1287446fda4fSPaul Moore * CIPSO draft. */ 1288701a90baSPaul Moore if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10) 128991b1ed0aSPaul Moore tag_len = 14; 1290701a90baSPaul Moore else 129191b1ed0aSPaul Moore tag_len = 4 + ret_val; 129291b1ed0aSPaul Moore } else 129391b1ed0aSPaul Moore tag_len = 4; 1294446fda4fSPaul Moore 129591b1ed0aSPaul Moore buffer[0] = 0x01; 129691b1ed0aSPaul Moore buffer[1] = tag_len; 129791b1ed0aSPaul Moore buffer[3] = level; 1298446fda4fSPaul Moore 129991b1ed0aSPaul Moore return tag_len; 1300446fda4fSPaul Moore } 1301446fda4fSPaul Moore 1302446fda4fSPaul Moore /** 1303446fda4fSPaul Moore * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag 1304446fda4fSPaul Moore * @doi_def: the DOI definition 1305446fda4fSPaul Moore * @tag: the CIPSO tag 1306446fda4fSPaul Moore * @secattr: the security attributes 1307446fda4fSPaul Moore * 1308446fda4fSPaul Moore * Description: 1309446fda4fSPaul Moore * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security 1310446fda4fSPaul Moore * attributes in @secattr. Return zero on success, negatives values on 1311446fda4fSPaul Moore * failure. 1312446fda4fSPaul Moore * 1313446fda4fSPaul Moore */ 1314446fda4fSPaul Moore static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, 1315446fda4fSPaul Moore const unsigned char *tag, 1316446fda4fSPaul Moore struct netlbl_lsm_secattr *secattr) 1317446fda4fSPaul Moore { 1318446fda4fSPaul Moore int ret_val; 1319446fda4fSPaul Moore u8 tag_len = tag[1]; 1320446fda4fSPaul Moore u32 level; 1321446fda4fSPaul Moore 1322446fda4fSPaul Moore ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1323446fda4fSPaul Moore if (ret_val != 0) 1324446fda4fSPaul Moore return ret_val; 1325446fda4fSPaul Moore secattr->mls_lvl = level; 1326701a90baSPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1327446fda4fSPaul Moore 1328446fda4fSPaul Moore if (tag_len > 4) { 132902752760SPaul Moore secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1330446fda4fSPaul Moore if (secattr->mls_cat == NULL) 1331446fda4fSPaul Moore return -ENOMEM; 1332446fda4fSPaul Moore 1333446fda4fSPaul Moore ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, 1334446fda4fSPaul Moore &tag[4], 1335446fda4fSPaul Moore tag_len - 4, 133602752760SPaul Moore secattr); 133702752760SPaul Moore if (ret_val != 0) { 133802752760SPaul Moore netlbl_secattr_catmap_free(secattr->mls_cat); 1339446fda4fSPaul Moore return ret_val; 1340701a90baSPaul Moore } 134102752760SPaul Moore 134202752760SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_CAT; 1343446fda4fSPaul Moore } 1344446fda4fSPaul Moore 1345446fda4fSPaul Moore return 0; 1346446fda4fSPaul Moore } 1347446fda4fSPaul Moore 1348446fda4fSPaul Moore /** 1349654bbc2aSPaul Moore * cipso_v4_gentag_enum - Generate a CIPSO enumerated tag (type #2) 1350654bbc2aSPaul Moore * @doi_def: the DOI definition 1351654bbc2aSPaul Moore * @secattr: the security attributes 1352654bbc2aSPaul Moore * @buffer: the option buffer 1353654bbc2aSPaul Moore * @buffer_len: length of buffer in bytes 1354654bbc2aSPaul Moore * 1355654bbc2aSPaul Moore * Description: 1356654bbc2aSPaul Moore * Generate a CIPSO option using the enumerated tag, tag type #2. Returns the 1357654bbc2aSPaul Moore * size of the tag on success, negative values on failure. 1358654bbc2aSPaul Moore * 1359654bbc2aSPaul Moore */ 1360654bbc2aSPaul Moore static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, 1361654bbc2aSPaul Moore const struct netlbl_lsm_secattr *secattr, 1362654bbc2aSPaul Moore unsigned char *buffer, 1363654bbc2aSPaul Moore u32 buffer_len) 1364654bbc2aSPaul Moore { 1365654bbc2aSPaul Moore int ret_val; 1366654bbc2aSPaul Moore u32 tag_len; 1367654bbc2aSPaul Moore u32 level; 1368654bbc2aSPaul Moore 1369654bbc2aSPaul Moore if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) 1370654bbc2aSPaul Moore return -EPERM; 1371654bbc2aSPaul Moore 1372654bbc2aSPaul Moore ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 1373654bbc2aSPaul Moore if (ret_val != 0) 1374654bbc2aSPaul Moore return ret_val; 1375654bbc2aSPaul Moore 1376654bbc2aSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 1377654bbc2aSPaul Moore ret_val = cipso_v4_map_cat_enum_hton(doi_def, 1378654bbc2aSPaul Moore secattr, 1379654bbc2aSPaul Moore &buffer[4], 1380654bbc2aSPaul Moore buffer_len - 4); 1381654bbc2aSPaul Moore if (ret_val < 0) 1382654bbc2aSPaul Moore return ret_val; 1383654bbc2aSPaul Moore 1384654bbc2aSPaul Moore tag_len = 4 + ret_val; 1385654bbc2aSPaul Moore } else 1386654bbc2aSPaul Moore tag_len = 4; 1387654bbc2aSPaul Moore 1388654bbc2aSPaul Moore buffer[0] = 0x02; 1389654bbc2aSPaul Moore buffer[1] = tag_len; 1390654bbc2aSPaul Moore buffer[3] = level; 1391654bbc2aSPaul Moore 1392654bbc2aSPaul Moore return tag_len; 1393654bbc2aSPaul Moore } 1394654bbc2aSPaul Moore 1395654bbc2aSPaul Moore /** 1396654bbc2aSPaul Moore * cipso_v4_parsetag_enum - Parse a CIPSO enumerated tag 1397654bbc2aSPaul Moore * @doi_def: the DOI definition 1398654bbc2aSPaul Moore * @tag: the CIPSO tag 1399654bbc2aSPaul Moore * @secattr: the security attributes 1400654bbc2aSPaul Moore * 1401654bbc2aSPaul Moore * Description: 1402654bbc2aSPaul Moore * Parse a CIPSO enumerated tag (tag type #2) and return the security 1403654bbc2aSPaul Moore * attributes in @secattr. Return zero on success, negatives values on 1404654bbc2aSPaul Moore * failure. 1405654bbc2aSPaul Moore * 1406654bbc2aSPaul Moore */ 1407654bbc2aSPaul Moore static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, 1408654bbc2aSPaul Moore const unsigned char *tag, 1409654bbc2aSPaul Moore struct netlbl_lsm_secattr *secattr) 1410654bbc2aSPaul Moore { 1411654bbc2aSPaul Moore int ret_val; 1412654bbc2aSPaul Moore u8 tag_len = tag[1]; 1413654bbc2aSPaul Moore u32 level; 1414654bbc2aSPaul Moore 1415654bbc2aSPaul Moore ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1416654bbc2aSPaul Moore if (ret_val != 0) 1417654bbc2aSPaul Moore return ret_val; 1418654bbc2aSPaul Moore secattr->mls_lvl = level; 1419654bbc2aSPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1420654bbc2aSPaul Moore 1421654bbc2aSPaul Moore if (tag_len > 4) { 1422654bbc2aSPaul Moore secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1423654bbc2aSPaul Moore if (secattr->mls_cat == NULL) 1424654bbc2aSPaul Moore return -ENOMEM; 1425654bbc2aSPaul Moore 1426654bbc2aSPaul Moore ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, 1427654bbc2aSPaul Moore &tag[4], 1428654bbc2aSPaul Moore tag_len - 4, 1429654bbc2aSPaul Moore secattr); 1430654bbc2aSPaul Moore if (ret_val != 0) { 1431654bbc2aSPaul Moore netlbl_secattr_catmap_free(secattr->mls_cat); 1432654bbc2aSPaul Moore return ret_val; 1433654bbc2aSPaul Moore } 1434654bbc2aSPaul Moore 1435654bbc2aSPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_CAT; 1436654bbc2aSPaul Moore } 1437654bbc2aSPaul Moore 1438654bbc2aSPaul Moore return 0; 1439654bbc2aSPaul Moore } 1440654bbc2aSPaul Moore 1441654bbc2aSPaul Moore /** 1442484b3669SPaul Moore * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5) 1443484b3669SPaul Moore * @doi_def: the DOI definition 1444484b3669SPaul Moore * @secattr: the security attributes 1445484b3669SPaul Moore * @buffer: the option buffer 1446484b3669SPaul Moore * @buffer_len: length of buffer in bytes 1447484b3669SPaul Moore * 1448484b3669SPaul Moore * Description: 1449484b3669SPaul Moore * Generate a CIPSO option using the ranged tag, tag type #5. Returns the 1450484b3669SPaul Moore * size of the tag on success, negative values on failure. 1451484b3669SPaul Moore * 1452484b3669SPaul Moore */ 1453484b3669SPaul Moore static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, 1454484b3669SPaul Moore const struct netlbl_lsm_secattr *secattr, 1455484b3669SPaul Moore unsigned char *buffer, 1456484b3669SPaul Moore u32 buffer_len) 1457484b3669SPaul Moore { 1458484b3669SPaul Moore int ret_val; 1459484b3669SPaul Moore u32 tag_len; 1460484b3669SPaul Moore u32 level; 1461484b3669SPaul Moore 1462484b3669SPaul Moore if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) 1463484b3669SPaul Moore return -EPERM; 1464484b3669SPaul Moore 1465484b3669SPaul Moore ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); 1466484b3669SPaul Moore if (ret_val != 0) 1467484b3669SPaul Moore return ret_val; 1468484b3669SPaul Moore 1469484b3669SPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 1470484b3669SPaul Moore ret_val = cipso_v4_map_cat_rng_hton(doi_def, 1471484b3669SPaul Moore secattr, 1472484b3669SPaul Moore &buffer[4], 1473484b3669SPaul Moore buffer_len - 4); 1474484b3669SPaul Moore if (ret_val < 0) 1475484b3669SPaul Moore return ret_val; 1476484b3669SPaul Moore 1477484b3669SPaul Moore tag_len = 4 + ret_val; 1478484b3669SPaul Moore } else 1479484b3669SPaul Moore tag_len = 4; 1480484b3669SPaul Moore 1481484b3669SPaul Moore buffer[0] = 0x05; 1482484b3669SPaul Moore buffer[1] = tag_len; 1483484b3669SPaul Moore buffer[3] = level; 1484484b3669SPaul Moore 1485484b3669SPaul Moore return tag_len; 1486484b3669SPaul Moore } 1487484b3669SPaul Moore 1488484b3669SPaul Moore /** 1489484b3669SPaul Moore * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag 1490484b3669SPaul Moore * @doi_def: the DOI definition 1491484b3669SPaul Moore * @tag: the CIPSO tag 1492484b3669SPaul Moore * @secattr: the security attributes 1493484b3669SPaul Moore * 1494484b3669SPaul Moore * Description: 1495484b3669SPaul Moore * Parse a CIPSO ranged tag (tag type #5) and return the security attributes 1496484b3669SPaul Moore * in @secattr. Return zero on success, negatives values on failure. 1497484b3669SPaul Moore * 1498484b3669SPaul Moore */ 1499484b3669SPaul Moore static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, 1500484b3669SPaul Moore const unsigned char *tag, 1501484b3669SPaul Moore struct netlbl_lsm_secattr *secattr) 1502484b3669SPaul Moore { 1503484b3669SPaul Moore int ret_val; 1504484b3669SPaul Moore u8 tag_len = tag[1]; 1505484b3669SPaul Moore u32 level; 1506484b3669SPaul Moore 1507484b3669SPaul Moore ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); 1508484b3669SPaul Moore if (ret_val != 0) 1509484b3669SPaul Moore return ret_val; 1510484b3669SPaul Moore secattr->mls_lvl = level; 1511484b3669SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1512484b3669SPaul Moore 1513484b3669SPaul Moore if (tag_len > 4) { 1514484b3669SPaul Moore secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); 1515484b3669SPaul Moore if (secattr->mls_cat == NULL) 1516484b3669SPaul Moore return -ENOMEM; 1517484b3669SPaul Moore 1518484b3669SPaul Moore ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, 1519484b3669SPaul Moore &tag[4], 1520484b3669SPaul Moore tag_len - 4, 1521484b3669SPaul Moore secattr); 1522484b3669SPaul Moore if (ret_val != 0) { 1523484b3669SPaul Moore netlbl_secattr_catmap_free(secattr->mls_cat); 1524484b3669SPaul Moore return ret_val; 1525484b3669SPaul Moore } 1526484b3669SPaul Moore 1527484b3669SPaul Moore secattr->flags |= NETLBL_SECATTR_MLS_CAT; 1528484b3669SPaul Moore } 1529484b3669SPaul Moore 1530484b3669SPaul Moore return 0; 1531484b3669SPaul Moore } 1532484b3669SPaul Moore 1533484b3669SPaul Moore /** 1534446fda4fSPaul Moore * cipso_v4_validate - Validate a CIPSO option 1535446fda4fSPaul Moore * @option: the start of the option, on error it is set to point to the error 1536446fda4fSPaul Moore * 1537446fda4fSPaul Moore * Description: 1538446fda4fSPaul Moore * This routine is called to validate a CIPSO option, it checks all of the 1539446fda4fSPaul Moore * fields to ensure that they are at least valid, see the draft snippet below 1540446fda4fSPaul Moore * for details. If the option is valid then a zero value is returned and 1541446fda4fSPaul Moore * the value of @option is unchanged. If the option is invalid then a 1542446fda4fSPaul Moore * non-zero value is returned and @option is adjusted to point to the 1543446fda4fSPaul Moore * offending portion of the option. From the IETF draft ... 1544446fda4fSPaul Moore * 1545446fda4fSPaul Moore * "If any field within the CIPSO options, such as the DOI identifier, is not 1546446fda4fSPaul Moore * recognized the IP datagram is discarded and an ICMP 'parameter problem' 1547446fda4fSPaul Moore * (type 12) is generated and returned. The ICMP code field is set to 'bad 1548446fda4fSPaul Moore * parameter' (code 0) and the pointer is set to the start of the CIPSO field 1549446fda4fSPaul Moore * that is unrecognized." 1550446fda4fSPaul Moore * 1551446fda4fSPaul Moore */ 1552446fda4fSPaul Moore int cipso_v4_validate(unsigned char **option) 1553446fda4fSPaul Moore { 1554446fda4fSPaul Moore unsigned char *opt = *option; 1555446fda4fSPaul Moore unsigned char *tag; 1556446fda4fSPaul Moore unsigned char opt_iter; 1557446fda4fSPaul Moore unsigned char err_offset = 0; 1558446fda4fSPaul Moore u8 opt_len; 1559446fda4fSPaul Moore u8 tag_len; 1560446fda4fSPaul Moore struct cipso_v4_doi *doi_def = NULL; 1561446fda4fSPaul Moore u32 tag_iter; 1562446fda4fSPaul Moore 1563446fda4fSPaul Moore /* caller already checks for length values that are too large */ 1564446fda4fSPaul Moore opt_len = opt[1]; 1565446fda4fSPaul Moore if (opt_len < 8) { 1566446fda4fSPaul Moore err_offset = 1; 1567446fda4fSPaul Moore goto validate_return; 1568446fda4fSPaul Moore } 1569446fda4fSPaul Moore 1570446fda4fSPaul Moore rcu_read_lock(); 1571*50e5d35cSPaul Moore doi_def = cipso_v4_doi_search(ntohl(get_unaligned((__be32 *)&opt[2]))); 1572446fda4fSPaul Moore if (doi_def == NULL) { 1573446fda4fSPaul Moore err_offset = 2; 1574446fda4fSPaul Moore goto validate_return_locked; 1575446fda4fSPaul Moore } 1576446fda4fSPaul Moore 1577446fda4fSPaul Moore opt_iter = 6; 1578446fda4fSPaul Moore tag = opt + opt_iter; 1579446fda4fSPaul Moore while (opt_iter < opt_len) { 1580446fda4fSPaul Moore for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) 1581446fda4fSPaul Moore if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID || 1582446fda4fSPaul Moore ++tag_iter == CIPSO_V4_TAG_MAXCNT) { 1583446fda4fSPaul Moore err_offset = opt_iter; 1584446fda4fSPaul Moore goto validate_return_locked; 1585446fda4fSPaul Moore } 1586446fda4fSPaul Moore 1587446fda4fSPaul Moore tag_len = tag[1]; 1588446fda4fSPaul Moore if (tag_len > (opt_len - opt_iter)) { 1589446fda4fSPaul Moore err_offset = opt_iter + 1; 1590446fda4fSPaul Moore goto validate_return_locked; 1591446fda4fSPaul Moore } 1592446fda4fSPaul Moore 1593446fda4fSPaul Moore switch (tag[0]) { 1594446fda4fSPaul Moore case CIPSO_V4_TAG_RBITMAP: 1595446fda4fSPaul Moore if (tag_len < 4) { 1596446fda4fSPaul Moore err_offset = opt_iter + 1; 1597446fda4fSPaul Moore goto validate_return_locked; 1598446fda4fSPaul Moore } 1599446fda4fSPaul Moore 1600446fda4fSPaul Moore /* We are already going to do all the verification 1601446fda4fSPaul Moore * necessary at the socket layer so from our point of 1602446fda4fSPaul Moore * view it is safe to turn these checks off (and less 1603446fda4fSPaul Moore * work), however, the CIPSO draft says we should do 1604446fda4fSPaul Moore * all the CIPSO validations here but it doesn't 1605446fda4fSPaul Moore * really specify _exactly_ what we need to validate 1606446fda4fSPaul Moore * ... so, just make it a sysctl tunable. */ 1607446fda4fSPaul Moore if (cipso_v4_rbm_strictvalid) { 1608446fda4fSPaul Moore if (cipso_v4_map_lvl_valid(doi_def, 1609446fda4fSPaul Moore tag[3]) < 0) { 1610446fda4fSPaul Moore err_offset = opt_iter + 3; 1611446fda4fSPaul Moore goto validate_return_locked; 1612446fda4fSPaul Moore } 1613446fda4fSPaul Moore if (tag_len > 4 && 1614446fda4fSPaul Moore cipso_v4_map_cat_rbm_valid(doi_def, 1615446fda4fSPaul Moore &tag[4], 1616446fda4fSPaul Moore tag_len - 4) < 0) { 1617446fda4fSPaul Moore err_offset = opt_iter + 4; 1618446fda4fSPaul Moore goto validate_return_locked; 1619446fda4fSPaul Moore } 1620446fda4fSPaul Moore } 1621446fda4fSPaul Moore break; 1622654bbc2aSPaul Moore case CIPSO_V4_TAG_ENUM: 1623654bbc2aSPaul Moore if (tag_len < 4) { 1624654bbc2aSPaul Moore err_offset = opt_iter + 1; 1625654bbc2aSPaul Moore goto validate_return_locked; 1626654bbc2aSPaul Moore } 1627654bbc2aSPaul Moore 1628654bbc2aSPaul Moore if (cipso_v4_map_lvl_valid(doi_def, 1629654bbc2aSPaul Moore tag[3]) < 0) { 1630654bbc2aSPaul Moore err_offset = opt_iter + 3; 1631654bbc2aSPaul Moore goto validate_return_locked; 1632654bbc2aSPaul Moore } 1633654bbc2aSPaul Moore if (tag_len > 4 && 1634654bbc2aSPaul Moore cipso_v4_map_cat_enum_valid(doi_def, 1635654bbc2aSPaul Moore &tag[4], 1636654bbc2aSPaul Moore tag_len - 4) < 0) { 1637654bbc2aSPaul Moore err_offset = opt_iter + 4; 1638654bbc2aSPaul Moore goto validate_return_locked; 1639654bbc2aSPaul Moore } 1640654bbc2aSPaul Moore break; 1641484b3669SPaul Moore case CIPSO_V4_TAG_RANGE: 1642484b3669SPaul Moore if (tag_len < 4) { 1643484b3669SPaul Moore err_offset = opt_iter + 1; 1644484b3669SPaul Moore goto validate_return_locked; 1645484b3669SPaul Moore } 1646484b3669SPaul Moore 1647484b3669SPaul Moore if (cipso_v4_map_lvl_valid(doi_def, 1648484b3669SPaul Moore tag[3]) < 0) { 1649484b3669SPaul Moore err_offset = opt_iter + 3; 1650484b3669SPaul Moore goto validate_return_locked; 1651484b3669SPaul Moore } 1652484b3669SPaul Moore if (tag_len > 4 && 1653484b3669SPaul Moore cipso_v4_map_cat_rng_valid(doi_def, 1654484b3669SPaul Moore &tag[4], 1655484b3669SPaul Moore tag_len - 4) < 0) { 1656484b3669SPaul Moore err_offset = opt_iter + 4; 1657484b3669SPaul Moore goto validate_return_locked; 1658484b3669SPaul Moore } 1659484b3669SPaul Moore break; 1660446fda4fSPaul Moore default: 1661446fda4fSPaul Moore err_offset = opt_iter; 1662446fda4fSPaul Moore goto validate_return_locked; 1663446fda4fSPaul Moore } 1664446fda4fSPaul Moore 1665446fda4fSPaul Moore tag += tag_len; 1666446fda4fSPaul Moore opt_iter += tag_len; 1667446fda4fSPaul Moore } 1668446fda4fSPaul Moore 1669446fda4fSPaul Moore validate_return_locked: 1670446fda4fSPaul Moore rcu_read_unlock(); 1671446fda4fSPaul Moore validate_return: 1672446fda4fSPaul Moore *option = opt + err_offset; 1673446fda4fSPaul Moore return err_offset; 1674446fda4fSPaul Moore } 1675446fda4fSPaul Moore 1676446fda4fSPaul Moore /** 1677446fda4fSPaul Moore * cipso_v4_error - Send the correct reponse for a bad packet 1678446fda4fSPaul Moore * @skb: the packet 1679446fda4fSPaul Moore * @error: the error code 1680446fda4fSPaul Moore * @gateway: CIPSO gateway flag 1681446fda4fSPaul Moore * 1682446fda4fSPaul Moore * Description: 1683446fda4fSPaul Moore * Based on the error code given in @error, send an ICMP error message back to 1684446fda4fSPaul Moore * the originating host. From the IETF draft ... 1685446fda4fSPaul Moore * 1686446fda4fSPaul Moore * "If the contents of the CIPSO [option] are valid but the security label is 1687446fda4fSPaul Moore * outside of the configured host or port label range, the datagram is 1688446fda4fSPaul Moore * discarded and an ICMP 'destination unreachable' (type 3) is generated and 1689446fda4fSPaul Moore * returned. The code field of the ICMP is set to 'communication with 1690446fda4fSPaul Moore * destination network administratively prohibited' (code 9) or to 1691446fda4fSPaul Moore * 'communication with destination host administratively prohibited' 1692446fda4fSPaul Moore * (code 10). The value of the code is dependent on whether the originator 1693446fda4fSPaul Moore * of the ICMP message is acting as a CIPSO host or a CIPSO gateway. The 1694446fda4fSPaul Moore * recipient of the ICMP message MUST be able to handle either value. The 1695446fda4fSPaul Moore * same procedure is performed if a CIPSO [option] can not be added to an 1696446fda4fSPaul Moore * IP packet because it is too large to fit in the IP options area." 1697446fda4fSPaul Moore * 1698446fda4fSPaul Moore * "If the error is triggered by receipt of an ICMP message, the message is 1699446fda4fSPaul Moore * discarded and no response is permitted (consistent with general ICMP 1700446fda4fSPaul Moore * processing rules)." 1701446fda4fSPaul Moore * 1702446fda4fSPaul Moore */ 1703446fda4fSPaul Moore void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) 1704446fda4fSPaul Moore { 1705eddc9ec5SArnaldo Carvalho de Melo if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES) 1706446fda4fSPaul Moore return; 1707446fda4fSPaul Moore 1708446fda4fSPaul Moore if (gateway) 1709446fda4fSPaul Moore icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0); 1710446fda4fSPaul Moore else 1711446fda4fSPaul Moore icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0); 1712446fda4fSPaul Moore } 1713446fda4fSPaul Moore 1714446fda4fSPaul Moore /** 1715ba6ff9f2SPaul Moore * cipso_v4_sock_setattr - Add a CIPSO option to a socket 1716ba6ff9f2SPaul Moore * @sk: the socket 1717446fda4fSPaul Moore * @doi_def: the CIPSO DOI to use 1718446fda4fSPaul Moore * @secattr: the specific security attributes of the socket 1719446fda4fSPaul Moore * 1720446fda4fSPaul Moore * Description: 1721446fda4fSPaul Moore * Set the CIPSO option on the given socket using the DOI definition and 1722446fda4fSPaul Moore * security attributes passed to the function. This function requires 1723ba6ff9f2SPaul Moore * exclusive access to @sk, which means it either needs to be in the 1724ba6ff9f2SPaul Moore * process of being created or locked. Returns zero on success and negative 1725ba6ff9f2SPaul Moore * values on failure. 1726446fda4fSPaul Moore * 1727446fda4fSPaul Moore */ 1728ba6ff9f2SPaul Moore int cipso_v4_sock_setattr(struct sock *sk, 1729446fda4fSPaul Moore const struct cipso_v4_doi *doi_def, 1730446fda4fSPaul Moore const struct netlbl_lsm_secattr *secattr) 1731446fda4fSPaul Moore { 1732446fda4fSPaul Moore int ret_val = -EPERM; 1733446fda4fSPaul Moore u32 iter; 173491b1ed0aSPaul Moore unsigned char *buf; 1735446fda4fSPaul Moore u32 buf_len = 0; 1736446fda4fSPaul Moore u32 opt_len; 1737446fda4fSPaul Moore struct ip_options *opt = NULL; 1738446fda4fSPaul Moore struct inet_sock *sk_inet; 1739446fda4fSPaul Moore struct inet_connection_sock *sk_conn; 1740446fda4fSPaul Moore 1741446fda4fSPaul Moore /* In the case of sock_create_lite(), the sock->sk field is not 1742446fda4fSPaul Moore * defined yet but it is not a problem as the only users of these 1743446fda4fSPaul Moore * "lite" PF_INET sockets are functions which do an accept() call 1744446fda4fSPaul Moore * afterwards so we will label the socket as part of the accept(). */ 1745446fda4fSPaul Moore if (sk == NULL) 1746446fda4fSPaul Moore return 0; 1747446fda4fSPaul Moore 174891b1ed0aSPaul Moore /* We allocate the maximum CIPSO option size here so we are probably 174991b1ed0aSPaul Moore * being a little wasteful, but it makes our life _much_ easier later 175091b1ed0aSPaul Moore * on and after all we are only talking about 40 bytes. */ 175191b1ed0aSPaul Moore buf_len = CIPSO_V4_OPT_LEN_MAX; 175291b1ed0aSPaul Moore buf = kmalloc(buf_len, GFP_ATOMIC); 175391b1ed0aSPaul Moore if (buf == NULL) { 175491b1ed0aSPaul Moore ret_val = -ENOMEM; 175591b1ed0aSPaul Moore goto socket_setattr_failure; 175691b1ed0aSPaul Moore } 175791b1ed0aSPaul Moore 1758446fda4fSPaul Moore /* XXX - This code assumes only one tag per CIPSO option which isn't 1759446fda4fSPaul Moore * really a good assumption to make but since we only support the MAC 1760446fda4fSPaul Moore * tags right now it is a safe assumption. */ 1761446fda4fSPaul Moore iter = 0; 1762446fda4fSPaul Moore do { 176391b1ed0aSPaul Moore memset(buf, 0, buf_len); 1764446fda4fSPaul Moore switch (doi_def->tags[iter]) { 1765446fda4fSPaul Moore case CIPSO_V4_TAG_RBITMAP: 1766446fda4fSPaul Moore ret_val = cipso_v4_gentag_rbm(doi_def, 1767446fda4fSPaul Moore secattr, 176891b1ed0aSPaul Moore &buf[CIPSO_V4_HDR_LEN], 176991b1ed0aSPaul Moore buf_len - CIPSO_V4_HDR_LEN); 1770446fda4fSPaul Moore break; 1771654bbc2aSPaul Moore case CIPSO_V4_TAG_ENUM: 1772654bbc2aSPaul Moore ret_val = cipso_v4_gentag_enum(doi_def, 1773654bbc2aSPaul Moore secattr, 1774654bbc2aSPaul Moore &buf[CIPSO_V4_HDR_LEN], 1775654bbc2aSPaul Moore buf_len - CIPSO_V4_HDR_LEN); 1776654bbc2aSPaul Moore break; 1777484b3669SPaul Moore case CIPSO_V4_TAG_RANGE: 1778484b3669SPaul Moore ret_val = cipso_v4_gentag_rng(doi_def, 1779484b3669SPaul Moore secattr, 1780484b3669SPaul Moore &buf[CIPSO_V4_HDR_LEN], 1781484b3669SPaul Moore buf_len - CIPSO_V4_HDR_LEN); 1782484b3669SPaul Moore break; 1783446fda4fSPaul Moore default: 1784446fda4fSPaul Moore ret_val = -EPERM; 1785446fda4fSPaul Moore goto socket_setattr_failure; 1786446fda4fSPaul Moore } 1787446fda4fSPaul Moore 1788446fda4fSPaul Moore iter++; 178991b1ed0aSPaul Moore } while (ret_val < 0 && 1790446fda4fSPaul Moore iter < CIPSO_V4_TAG_MAXCNT && 1791446fda4fSPaul Moore doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); 179291b1ed0aSPaul Moore if (ret_val < 0) 1793446fda4fSPaul Moore goto socket_setattr_failure; 179491b1ed0aSPaul Moore cipso_v4_gentag_hdr(doi_def, buf, ret_val); 179591b1ed0aSPaul Moore buf_len = CIPSO_V4_HDR_LEN + ret_val; 1796446fda4fSPaul Moore 1797446fda4fSPaul Moore /* We can't use ip_options_get() directly because it makes a call to 1798446fda4fSPaul Moore * ip_options_get_alloc() which allocates memory with GFP_KERNEL and 1799f8687afeSPaul Moore * we won't always have CAP_NET_RAW even though we _always_ want to 1800f8687afeSPaul Moore * set the IPOPT_CIPSO option. */ 1801446fda4fSPaul Moore opt_len = (buf_len + 3) & ~3; 1802446fda4fSPaul Moore opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); 1803446fda4fSPaul Moore if (opt == NULL) { 1804446fda4fSPaul Moore ret_val = -ENOMEM; 1805446fda4fSPaul Moore goto socket_setattr_failure; 1806446fda4fSPaul Moore } 1807446fda4fSPaul Moore memcpy(opt->__data, buf, buf_len); 1808446fda4fSPaul Moore opt->optlen = opt_len; 1809446fda4fSPaul Moore opt->is_data = 1; 1810f8687afeSPaul Moore opt->cipso = sizeof(struct iphdr); 1811446fda4fSPaul Moore kfree(buf); 1812446fda4fSPaul Moore buf = NULL; 1813446fda4fSPaul Moore 1814446fda4fSPaul Moore sk_inet = inet_sk(sk); 1815446fda4fSPaul Moore if (sk_inet->is_icsk) { 1816446fda4fSPaul Moore sk_conn = inet_csk(sk); 1817446fda4fSPaul Moore if (sk_inet->opt) 1818446fda4fSPaul Moore sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen; 1819446fda4fSPaul Moore sk_conn->icsk_ext_hdr_len += opt->optlen; 1820446fda4fSPaul Moore sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); 1821446fda4fSPaul Moore } 1822446fda4fSPaul Moore opt = xchg(&sk_inet->opt, opt); 1823446fda4fSPaul Moore kfree(opt); 1824446fda4fSPaul Moore 1825446fda4fSPaul Moore return 0; 1826446fda4fSPaul Moore 1827446fda4fSPaul Moore socket_setattr_failure: 1828446fda4fSPaul Moore kfree(buf); 1829446fda4fSPaul Moore kfree(opt); 1830446fda4fSPaul Moore return ret_val; 1831446fda4fSPaul Moore } 1832446fda4fSPaul Moore 1833446fda4fSPaul Moore /** 183414a72f53SPaul Moore * cipso_v4_sock_getattr - Get the security attributes from a sock 183514a72f53SPaul Moore * @sk: the sock 183614a72f53SPaul Moore * @secattr: the security attributes 183714a72f53SPaul Moore * 183814a72f53SPaul Moore * Description: 183914a72f53SPaul Moore * Query @sk to see if there is a CIPSO option attached to the sock and if 184014a72f53SPaul Moore * there is return the CIPSO security attributes in @secattr. This function 184114a72f53SPaul Moore * requires that @sk be locked, or privately held, but it does not do any 184214a72f53SPaul Moore * locking itself. Returns zero on success and negative values on failure. 184314a72f53SPaul Moore * 184414a72f53SPaul Moore */ 184514a72f53SPaul Moore int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 184614a72f53SPaul Moore { 184714a72f53SPaul Moore int ret_val = -ENOMSG; 184814a72f53SPaul Moore struct inet_sock *sk_inet; 184914a72f53SPaul Moore unsigned char *cipso_ptr; 185014a72f53SPaul Moore u32 doi; 185114a72f53SPaul Moore struct cipso_v4_doi *doi_def; 185214a72f53SPaul Moore 185314a72f53SPaul Moore sk_inet = inet_sk(sk); 185414a72f53SPaul Moore if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) 185514a72f53SPaul Moore return -ENOMSG; 185614a72f53SPaul Moore cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso - 185714a72f53SPaul Moore sizeof(struct iphdr); 185814a72f53SPaul Moore ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr); 185914a72f53SPaul Moore if (ret_val == 0) 186014a72f53SPaul Moore return ret_val; 186114a72f53SPaul Moore 1862*50e5d35cSPaul Moore doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2])); 186314a72f53SPaul Moore rcu_read_lock(); 18649bb5fd2bSPaul Moore doi_def = cipso_v4_doi_search(doi); 186514a72f53SPaul Moore if (doi_def == NULL) { 186614a72f53SPaul Moore rcu_read_unlock(); 186714a72f53SPaul Moore return -ENOMSG; 186814a72f53SPaul Moore } 186991b1ed0aSPaul Moore 187091b1ed0aSPaul Moore /* XXX - This code assumes only one tag per CIPSO option which isn't 187191b1ed0aSPaul Moore * really a good assumption to make but since we only support the MAC 187291b1ed0aSPaul Moore * tags right now it is a safe assumption. */ 187314a72f53SPaul Moore switch (cipso_ptr[6]) { 187414a72f53SPaul Moore case CIPSO_V4_TAG_RBITMAP: 187514a72f53SPaul Moore ret_val = cipso_v4_parsetag_rbm(doi_def, 187614a72f53SPaul Moore &cipso_ptr[6], 187714a72f53SPaul Moore secattr); 187814a72f53SPaul Moore break; 1879654bbc2aSPaul Moore case CIPSO_V4_TAG_ENUM: 1880654bbc2aSPaul Moore ret_val = cipso_v4_parsetag_enum(doi_def, 1881654bbc2aSPaul Moore &cipso_ptr[6], 1882654bbc2aSPaul Moore secattr); 1883654bbc2aSPaul Moore break; 1884484b3669SPaul Moore case CIPSO_V4_TAG_RANGE: 1885484b3669SPaul Moore ret_val = cipso_v4_parsetag_rng(doi_def, 1886484b3669SPaul Moore &cipso_ptr[6], 1887484b3669SPaul Moore secattr); 1888484b3669SPaul Moore break; 188914a72f53SPaul Moore } 189014a72f53SPaul Moore rcu_read_unlock(); 189114a72f53SPaul Moore 189214a72f53SPaul Moore return ret_val; 189314a72f53SPaul Moore } 189414a72f53SPaul Moore 189514a72f53SPaul Moore /** 1896446fda4fSPaul Moore * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option 1897446fda4fSPaul Moore * @skb: the packet 1898446fda4fSPaul Moore * @secattr: the security attributes 1899446fda4fSPaul Moore * 1900446fda4fSPaul Moore * Description: 1901446fda4fSPaul Moore * Parse the given packet's CIPSO option and return the security attributes. 1902446fda4fSPaul Moore * Returns zero on success and negative values on failure. 1903446fda4fSPaul Moore * 1904446fda4fSPaul Moore */ 1905446fda4fSPaul Moore int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 1906446fda4fSPaul Moore struct netlbl_lsm_secattr *secattr) 1907446fda4fSPaul Moore { 1908446fda4fSPaul Moore int ret_val = -ENOMSG; 1909446fda4fSPaul Moore unsigned char *cipso_ptr; 1910446fda4fSPaul Moore u32 doi; 1911446fda4fSPaul Moore struct cipso_v4_doi *doi_def; 1912446fda4fSPaul Moore 1913446fda4fSPaul Moore cipso_ptr = CIPSO_V4_OPTPTR(skb); 1914446fda4fSPaul Moore if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) 1915446fda4fSPaul Moore return 0; 1916446fda4fSPaul Moore 1917*50e5d35cSPaul Moore doi = ntohl(get_unaligned((__be32 *)&cipso_ptr[2])); 1918446fda4fSPaul Moore rcu_read_lock(); 19199bb5fd2bSPaul Moore doi_def = cipso_v4_doi_search(doi); 1920446fda4fSPaul Moore if (doi_def == NULL) 1921446fda4fSPaul Moore goto skbuff_getattr_return; 192291b1ed0aSPaul Moore 192391b1ed0aSPaul Moore /* XXX - This code assumes only one tag per CIPSO option which isn't 192491b1ed0aSPaul Moore * really a good assumption to make but since we only support the MAC 192591b1ed0aSPaul Moore * tags right now it is a safe assumption. */ 1926446fda4fSPaul Moore switch (cipso_ptr[6]) { 1927446fda4fSPaul Moore case CIPSO_V4_TAG_RBITMAP: 1928446fda4fSPaul Moore ret_val = cipso_v4_parsetag_rbm(doi_def, 1929446fda4fSPaul Moore &cipso_ptr[6], 1930446fda4fSPaul Moore secattr); 1931446fda4fSPaul Moore break; 1932654bbc2aSPaul Moore case CIPSO_V4_TAG_ENUM: 1933654bbc2aSPaul Moore ret_val = cipso_v4_parsetag_enum(doi_def, 1934654bbc2aSPaul Moore &cipso_ptr[6], 1935654bbc2aSPaul Moore secattr); 1936654bbc2aSPaul Moore break; 193738c8947cSPaul Moore case CIPSO_V4_TAG_RANGE: 193838c8947cSPaul Moore ret_val = cipso_v4_parsetag_rng(doi_def, 193938c8947cSPaul Moore &cipso_ptr[6], 194038c8947cSPaul Moore secattr); 194138c8947cSPaul Moore break; 1942446fda4fSPaul Moore } 1943446fda4fSPaul Moore 1944446fda4fSPaul Moore skbuff_getattr_return: 1945446fda4fSPaul Moore rcu_read_unlock(); 1946446fda4fSPaul Moore return ret_val; 1947446fda4fSPaul Moore } 1948446fda4fSPaul Moore 1949446fda4fSPaul Moore /* 1950446fda4fSPaul Moore * Setup Functions 1951446fda4fSPaul Moore */ 1952446fda4fSPaul Moore 1953446fda4fSPaul Moore /** 1954446fda4fSPaul Moore * cipso_v4_init - Initialize the CIPSO module 1955446fda4fSPaul Moore * 1956446fda4fSPaul Moore * Description: 1957446fda4fSPaul Moore * Initialize the CIPSO module and prepare it for use. Returns zero on success 1958446fda4fSPaul Moore * and negative values on failure. 1959446fda4fSPaul Moore * 1960446fda4fSPaul Moore */ 1961446fda4fSPaul Moore static int __init cipso_v4_init(void) 1962446fda4fSPaul Moore { 1963446fda4fSPaul Moore int ret_val; 1964446fda4fSPaul Moore 1965446fda4fSPaul Moore ret_val = cipso_v4_cache_init(); 1966446fda4fSPaul Moore if (ret_val != 0) 1967446fda4fSPaul Moore panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n", 1968446fda4fSPaul Moore ret_val); 1969446fda4fSPaul Moore 1970446fda4fSPaul Moore return 0; 1971446fda4fSPaul Moore } 1972446fda4fSPaul Moore 1973446fda4fSPaul Moore subsys_initcall(cipso_v4_init); 1974