⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cipso_ipv4.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * CIPSO - Commercial IP Security Option * * This is an implementation of the CIPSO 2.2 protocol as specified in * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in * FIPS-188, copies of both documents can be found in the Documentation * directory.  While CIPSO never became a full IETF RFC standard many vendors * have chosen to adopt the protocol and over the years it has become a * de-facto standard for labeled networking. * * Author: Paul Moore <paul.moore@hp.com> * *//* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 * * This program is free software;  you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY;  without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program;  if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <linux/init.h>#include <linux/types.h>#include <linux/rcupdate.h>#include <linux/list.h>#include <linux/spinlock.h>#include <linux/string.h>#include <linux/jhash.h>#include <net/ip.h>#include <net/icmp.h>#include <net/tcp.h>#include <net/netlabel.h>#include <net/cipso_ipv4.h>#include <asm/atomic.h>#include <asm/bug.h>#include <asm/unaligned.h>struct cipso_v4_domhsh_entry {	char *domain;	u32 valid;	struct list_head list;	struct rcu_head rcu;};/* List of available DOI definitions *//* XXX - Updates should be minimal so having a single lock for the * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be * okay. *//* XXX - This currently assumes a minimal number of different DOIs in use, * if in practice there are a lot of different DOIs this list should * probably be turned into a hash table or something similar so we * can do quick lookups. */static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);/* Label mapping cache */int cipso_v4_cache_enabled = 1;int cipso_v4_cache_bucketsize = 10;#define CIPSO_V4_CACHE_BUCKETBITS     7#define CIPSO_V4_CACHE_BUCKETS        (1 << CIPSO_V4_CACHE_BUCKETBITS)#define CIPSO_V4_CACHE_REORDERLIMIT   10struct cipso_v4_map_cache_bkt {	spinlock_t lock;	u32 size;	struct list_head list;};struct cipso_v4_map_cache_entry {	u32 hash;	unsigned char *key;	size_t key_len;	struct netlbl_lsm_cache *lsm_data;	u32 activity;	struct list_head list;};static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;/* Restricted bitmap (tag #1) flags */int cipso_v4_rbm_optfmt = 0;int cipso_v4_rbm_strictvalid = 1;/* * Protocol Constants *//* Maximum size of the CIPSO IP option, derived from the fact that the maximum * IPv4 header size is 60 bytes and the base IPv4 header is 20 bytes long. */#define CIPSO_V4_OPT_LEN_MAX          40/* Length of the base CIPSO option, this includes the option type (1 byte), the * option length (1 byte), and the DOI (4 bytes). */#define CIPSO_V4_HDR_LEN              6/* Base length of the restrictive category bitmap tag (tag #1). */#define CIPSO_V4_TAG_RBM_BLEN         4/* Base length of the enumerated category tag (tag #2). */#define CIPSO_V4_TAG_ENUM_BLEN        4/* Base length of the ranged categories bitmap tag (tag #5). */#define CIPSO_V4_TAG_RNG_BLEN         4/* The maximum number of category ranges permitted in the ranged category tag * (tag #5).  You may note that the IETF draft states that the maximum number * of category ranges is 7, but if the low end of the last category range is * zero then it is possibile to fit 8 category ranges because the zero should * be omitted. */#define CIPSO_V4_TAG_RNG_CAT_MAX      8/* * Helper Functions *//** * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit * @bitmap: the bitmap * @bitmap_len: length in bits * @offset: starting offset * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit * * Description: * Starting at @offset, walk the bitmap from left to right until either the * desired bit is found or we reach the end.  Return the bit offset, -1 if * not found, or -2 if error. */static int cipso_v4_bitmap_walk(const unsigned char *bitmap,				u32 bitmap_len,				u32 offset,				u8 state){	u32 bit_spot;	u32 byte_offset;	unsigned char bitmask;	unsigned char byte;	/* gcc always rounds to zero when doing integer division */	byte_offset = offset / 8;	byte = bitmap[byte_offset];	bit_spot = offset;	bitmask = 0x80 >> (offset % 8);	while (bit_spot < bitmap_len) {		if ((state && (byte & bitmask) == bitmask) ||		    (state == 0 && (byte & bitmask) == 0))			return bit_spot;		bit_spot++;		bitmask >>= 1;		if (bitmask == 0) {			byte = bitmap[++byte_offset];			bitmask = 0x80;		}	}	return -1;}/** * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap * @bitmap: the bitmap * @bit: the bit * @state: if non-zero, set the bit (1) else clear the bit (0) * * Description: * Set a single bit in the bitmask.  Returns zero on success, negative values * on error. */static void cipso_v4_bitmap_setbit(unsigned char *bitmap,				   u32 bit,				   u8 state){	u32 byte_spot;	u8 bitmask;	/* gcc always rounds to zero when doing integer division */	byte_spot = bit / 8;	bitmask = 0x80 >> (bit % 8);	if (state)		bitmap[byte_spot] |= bitmask;	else		bitmap[byte_spot] &= ~bitmask;}/** * cipso_v4_doi_domhsh_free - Frees a domain list entry * @entry: the entry's RCU field * * Description: * This function is designed to be used as a callback to the call_rcu() * function so that the memory allocated to a domain list entry can be released * safely. * */static void cipso_v4_doi_domhsh_free(struct rcu_head *entry){	struct cipso_v4_domhsh_entry *ptr;	ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);	kfree(ptr->domain);	kfree(ptr);}/** * cipso_v4_cache_entry_free - Frees a cache entry * @entry: the entry to free * * Description: * This function frees the memory associated with a cache entry including the * LSM cache data if there are no longer any users, i.e. reference count == 0. * */static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry){	if (entry->lsm_data)		netlbl_secattr_cache_free(entry->lsm_data);	kfree(entry->key);	kfree(entry);}/** * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache * @key: the hash key * @key_len: the length of the key in bytes * * Description: * The CIPSO tag hashing function.  Returns a 32-bit hash value. * */static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len){	return jhash(key, key_len, 0);}/* * Label Mapping Cache Functions *//** * cipso_v4_cache_init - Initialize the CIPSO cache * * Description: * Initializes the CIPSO label mapping cache, this function should be called * before any of the other functions defined in this file.  Returns zero on * success, negative values on error. * */static int cipso_v4_cache_init(void){	u32 iter;	cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,				 sizeof(struct cipso_v4_map_cache_bkt),				 GFP_KERNEL);	if (cipso_v4_cache == NULL)		return -ENOMEM;	for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {		spin_lock_init(&cipso_v4_cache[iter].lock);		cipso_v4_cache[iter].size = 0;		INIT_LIST_HEAD(&cipso_v4_cache[iter].list);	}	return 0;}/** * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache * * Description: * Invalidates and frees any entries in the CIPSO cache.  Returns zero on * success and negative values on failure. * */void cipso_v4_cache_invalidate(void){	struct cipso_v4_map_cache_entry *entry, *tmp_entry;	u32 iter;	for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {		spin_lock_bh(&cipso_v4_cache[iter].lock);		list_for_each_entry_safe(entry,					 tmp_entry,					 &cipso_v4_cache[iter].list, list) {			list_del(&entry->list);			cipso_v4_cache_entry_free(entry);		}		cipso_v4_cache[iter].size = 0;		spin_unlock_bh(&cipso_v4_cache[iter].lock);	}	return;}/** * cipso_v4_cache_check - Check the CIPSO cache for a label mapping * @key: the buffer to check * @key_len: buffer length in bytes * @secattr: the security attribute struct to use * * Description: * This function checks the cache to see if a label mapping already exists for * the given key.  If there is a match then the cache is adjusted and the * @secattr struct is populated with the correct LSM security attributes.  The * cache is adjusted in the following manner if the entry is not already the * first in the cache bucket: * *  1. The cache entry's activity counter is incremented *  2. The previous (higher ranking) entry's activity counter is decremented *  3. If the difference between the two activity counters is geater than *     CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped * * Returns zero on success, -ENOENT for a cache miss, and other negative values * on error. * */static int cipso_v4_cache_check(const unsigned char *key,				u32 key_len,				struct netlbl_lsm_secattr *secattr){	u32 bkt;	struct cipso_v4_map_cache_entry *entry;	struct cipso_v4_map_cache_entry *prev_entry = NULL;	u32 hash;	if (!cipso_v4_cache_enabled)		return -ENOENT;	hash = cipso_v4_map_cache_hash(key, key_len);	bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);	spin_lock_bh(&cipso_v4_cache[bkt].lock);	list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {		if (entry->hash == hash &&		    entry->key_len == key_len &&		    memcmp(entry->key, key, key_len) == 0) {			entry->activity += 1;			atomic_inc(&entry->lsm_data->refcount);			secattr->cache = entry->lsm_data;			secattr->flags |= NETLBL_SECATTR_CACHE;			if (prev_entry == NULL) {				spin_unlock_bh(&cipso_v4_cache[bkt].lock);				return 0;			}			if (prev_entry->activity > 0)				prev_entry->activity -= 1;			if (entry->activity > prev_entry->activity &&			    entry->activity - prev_entry->activity >			    CIPSO_V4_CACHE_REORDERLIMIT) {				__list_del(entry->list.prev, entry->list.next);				__list_add(&entry->list,					   prev_entry->list.prev,					   &prev_entry->list);			}			spin_unlock_bh(&cipso_v4_cache[bkt].lock);			return 0;		}		prev_entry = entry;	}	spin_unlock_bh(&cipso_v4_cache[bkt].lock);	return -ENOENT;}/** * cipso_v4_cache_add - Add an entry to the CIPSO cache * @skb: the packet * @secattr: the packet's security attributes * * Description: * Add a new entry into the CIPSO label mapping cache.  Add the new entry to * head of the cache bucket's list, if the cache bucket is out of room remove * the last entry in the list first.  It is important to note that there is * currently no checking for duplicate keys.  Returns zero on success, * negative values on failure. * */int cipso_v4_cache_add(const struct sk_buff *skb,		       const struct netlbl_lsm_secattr *secattr){	int ret_val = -EPERM;	u32 bkt;	struct cipso_v4_map_cache_entry *entry = NULL;	struct cipso_v4_map_cache_entry *old_entry = NULL;	unsigned char *cipso_ptr;	u32 cipso_ptr_len;	if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)		return 0;	cipso_ptr = CIPSO_V4_OPTPTR(skb);	cipso_ptr_len = cipso_ptr[1];	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);	if (entry == NULL)		return -ENOMEM;	entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC);	if (entry->key == NULL) {		ret_val = -ENOMEM;		goto cache_add_failure;	}	entry->key_len = cipso_ptr_len;	entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);	atomic_inc(&secattr->cache->refcount);	entry->lsm_data = secattr->cache;	bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);	spin_lock_bh(&cipso_v4_cache[bkt].lock);	if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {		list_add(&entry->list, &cipso_v4_cache[bkt].list);		cipso_v4_cache[bkt].size += 1;	} else {		old_entry = list_entry(cipso_v4_cache[bkt].list.prev,				       struct cipso_v4_map_cache_entry, list);		list_del(&old_entry->list);		list_add(&entry->list, &cipso_v4_cache[bkt].list);		cipso_v4_cache_entry_free(old_entry);	}	spin_unlock_bh(&cipso_v4_cache[bkt].lock);	return 0;cache_add_failure:	if (entry)		cipso_v4_cache_entry_free(entry);	return ret_val;}/* * DOI List Functions *//** * cipso_v4_doi_search - Searches for a DOI definition * @doi: the DOI to search for * * Description: * Search the DOI definition list for a DOI definition with a DOI value that * matches @doi.  The caller is responsibile for calling rcu_read_[un]lock(). * Returns a pointer to the DOI definition on success and NULL on failure. */static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi){	struct cipso_v4_doi *iter;	list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)		if (iter->doi == doi && iter->valid)			return iter;	return NULL;}/** * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine * @doi_def: the DOI structure * * Description: * The caller defines a new DOI for use by the CIPSO engine and calls this * function to add it to the list of acceptable domains.  The caller must * ensure that the mapping table specified in @doi_def->map meets all of the * requirements of the mapping type (see cipso_ipv4.h for details).  Returns * zero on success and non-zero on failure. * */int cipso_v4_doi_add(struct cipso_v4_doi *doi_def){	u32 iter;	if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)		return -EINVAL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -