[NetLabel]: CIPSOv4 engine
[linux-2.6.git] / net / ipv4 / cipso_ipv4.c
1 /*
2  * CIPSO - Commercial IP Security Option
3  *
4  * This is an implementation of the CIPSO 2.2 protocol as specified in
5  * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
6  * FIPS-188, copies of both documents can be found in the Documentation
7  * directory.  While CIPSO never became a full IETF RFC standard many vendors
8  * have chosen to adopt the protocol and over the years it has become a
9  * de-facto standard for labeled networking.
10  *
11  * Author: Paul Moore <paul.moore@hp.com>
12  *
13  */
14
15 /*
16  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
17  *
18  * This program is free software;  you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
26  * the GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program;  if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31  *
32  */
33
34 #include <linux/init.h>
35 #include <linux/types.h>
36 #include <linux/rcupdate.h>
37 #include <linux/list.h>
38 #include <linux/spinlock.h>
39 #include <linux/string.h>
40 #include <linux/jhash.h>
41 #include <net/ip.h>
42 #include <net/icmp.h>
43 #include <net/tcp.h>
44 #include <net/netlabel.h>
45 #include <net/cipso_ipv4.h>
46 #include <asm/bug.h>
47
48 struct cipso_v4_domhsh_entry {
49         char *domain;
50         u32 valid;
51         struct list_head list;
52         struct rcu_head rcu;
53 };
54
55 /* List of available DOI definitions */
56 /* XXX - Updates should be minimal so having a single lock for the
57  * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
58  * okay. */
59 /* XXX - This currently assumes a minimal number of different DOIs in use,
60  * if in practice there are a lot of different DOIs this list should
61  * probably be turned into a hash table or something similar so we
62  * can do quick lookups. */
63 DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
64 static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);
65
66 /* Label mapping cache */
67 int cipso_v4_cache_enabled = 1;
68 int cipso_v4_cache_bucketsize = 10;
69 #define CIPSO_V4_CACHE_BUCKETBITS     7
70 #define CIPSO_V4_CACHE_BUCKETS        (1 << CIPSO_V4_CACHE_BUCKETBITS)
71 #define CIPSO_V4_CACHE_REORDERLIMIT   10
72 struct cipso_v4_map_cache_bkt {
73         spinlock_t lock;
74         u32 size;
75         struct list_head list;
76 };
77 struct cipso_v4_map_cache_entry {
78         u32 hash;
79         unsigned char *key;
80         size_t key_len;
81
82         struct netlbl_lsm_cache lsm_data;
83
84         u32 activity;
85         struct list_head list;
86 };
87 static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
88
89 /* Restricted bitmap (tag #1) flags */
90 int cipso_v4_rbm_optfmt = 0;
91 int cipso_v4_rbm_strictvalid = 1;
92
93 /*
94  * Helper Functions
95  */
96
97 /**
98  * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
99  * @bitmap: the bitmap
100  * @bitmap_len: length in bits
101  * @offset: starting offset
102  * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
103  *
104  * Description:
105  * Starting at @offset, walk the bitmap from left to right until either the
106  * desired bit is found or we reach the end.  Return the bit offset, -1 if
107  * not found, or -2 if error.
108  */
109 static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
110                                 u32 bitmap_len,
111                                 u32 offset,
112                                 u8 state)
113 {
114         u32 bit_spot;
115         u32 byte_offset;
116         unsigned char bitmask;
117         unsigned char byte;
118
119         /* gcc always rounds to zero when doing integer division */
120         byte_offset = offset / 8;
121         byte = bitmap[byte_offset];
122         bit_spot = offset;
123         bitmask = 0x80 >> (offset % 8);
124
125         while (bit_spot < bitmap_len) {
126                 if ((state && (byte & bitmask) == bitmask) ||
127                     (state == 0 && (byte & bitmask) == 0))
128                         return bit_spot;
129
130                 bit_spot++;
131                 bitmask >>= 1;
132                 if (bitmask == 0) {
133                         byte = bitmap[++byte_offset];
134                         bitmask = 0x80;
135                 }
136         }
137
138         return -1;
139 }
140
141 /**
142  * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
143  * @bitmap: the bitmap
144  * @bit: the bit
145  * @state: if non-zero, set the bit (1) else clear the bit (0)
146  *
147  * Description:
148  * Set a single bit in the bitmask.  Returns zero on success, negative values
149  * on error.
150  */
151 static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
152                                    u32 bit,
153                                    u8 state)
154 {
155         u32 byte_spot;
156         u8 bitmask;
157
158         /* gcc always rounds to zero when doing integer division */
159         byte_spot = bit / 8;
160         bitmask = 0x80 >> (bit % 8);
161         if (state)
162                 bitmap[byte_spot] |= bitmask;
163         else
164                 bitmap[byte_spot] &= ~bitmask;
165 }
166
167 /**
168  * cipso_v4_doi_domhsh_free - Frees a domain list entry
169  * @entry: the entry's RCU field
170  *
171  * Description:
172  * This function is designed to be used as a callback to the call_rcu()
173  * function so that the memory allocated to a domain list entry can be released
174  * safely.
175  *
176  */
177 static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
178 {
179         struct cipso_v4_domhsh_entry *ptr;
180
181         ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
182         kfree(ptr->domain);
183         kfree(ptr);
184 }
185
186 /**
187  * cipso_v4_cache_entry_free - Frees a cache entry
188  * @entry: the entry to free
189  *
190  * Description:
191  * This function frees the memory associated with a cache entry.
192  *
193  */
194 static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
195 {
196         if (entry->lsm_data.free)
197                 entry->lsm_data.free(entry->lsm_data.data);
198         kfree(entry->key);
199         kfree(entry);
200 }
201
202 /**
203  * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
204  * @key: the hash key
205  * @key_len: the length of the key in bytes
206  *
207  * Description:
208  * The CIPSO tag hashing function.  Returns a 32-bit hash value.
209  *
210  */
211 static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len)
212 {
213         return jhash(key, key_len, 0);
214 }
215
216 /*
217  * Label Mapping Cache Functions
218  */
219
220 /**
221  * cipso_v4_cache_init - Initialize the CIPSO cache
222  *
223  * Description:
224  * Initializes the CIPSO label mapping cache, this function should be called
225  * before any of the other functions defined in this file.  Returns zero on
226  * success, negative values on error.
227  *
228  */
229 static int cipso_v4_cache_init(void)
230 {
231         u32 iter;
232
233         cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,
234                                  sizeof(struct cipso_v4_map_cache_bkt),
235                                  GFP_KERNEL);
236         if (cipso_v4_cache == NULL)
237                 return -ENOMEM;
238
239         for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
240                 spin_lock_init(&cipso_v4_cache[iter].lock);
241                 cipso_v4_cache[iter].size = 0;
242                 INIT_LIST_HEAD(&cipso_v4_cache[iter].list);
243         }
244
245         return 0;
246 }
247
248 /**
249  * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
250  *
251  * Description:
252  * Invalidates and frees any entries in the CIPSO cache.  Returns zero on
253  * success and negative values on failure.
254  *
255  */
256 void cipso_v4_cache_invalidate(void)
257 {
258         struct cipso_v4_map_cache_entry *entry, *tmp_entry;
259         u32 iter;
260
261         for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
262                 spin_lock(&cipso_v4_cache[iter].lock);
263                 list_for_each_entry_safe(entry,
264                                          tmp_entry,
265                                          &cipso_v4_cache[iter].list, list) {
266                         list_del(&entry->list);
267                         cipso_v4_cache_entry_free(entry);
268                 }
269                 cipso_v4_cache[iter].size = 0;
270                 spin_unlock(&cipso_v4_cache[iter].lock);
271         }
272
273         return;
274 }
275
276 /**
277  * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
278  * @key: the buffer to check
279  * @key_len: buffer length in bytes
280  * @secattr: the security attribute struct to use
281  *
282  * Description:
283  * This function checks the cache to see if a label mapping already exists for
284  * the given key.  If there is a match then the cache is adjusted and the
285  * @secattr struct is populated with the correct LSM security attributes.  The
286  * cache is adjusted in the following manner if the entry is not already the
287  * first in the cache bucket:
288  *
289  *  1. The cache entry's activity counter is incremented
290  *  2. The previous (higher ranking) entry's activity counter is decremented
291  *  3. If the difference between the two activity counters is geater than
292  *     CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
293  *
294  * Returns zero on success, -ENOENT for a cache miss, and other negative values
295  * on error.
296  *
297  */
298 static int cipso_v4_cache_check(const unsigned char *key,
299                                 u32 key_len,
300                                 struct netlbl_lsm_secattr *secattr)
301 {
302         u32 bkt;
303         struct cipso_v4_map_cache_entry *entry;
304         struct cipso_v4_map_cache_entry *prev_entry = NULL;
305         u32 hash;
306
307         if (!cipso_v4_cache_enabled)
308                 return -ENOENT;
309
310         hash = cipso_v4_map_cache_hash(key, key_len);
311         bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
312         spin_lock(&cipso_v4_cache[bkt].lock);
313         list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
314                 if (entry->hash == hash &&
315                     entry->key_len == key_len &&
316                     memcmp(entry->key, key, key_len) == 0) {
317                         entry->activity += 1;
318                         secattr->cache.free = entry->lsm_data.free;
319                         secattr->cache.data = entry->lsm_data.data;
320                         if (prev_entry == NULL) {
321                                 spin_unlock(&cipso_v4_cache[bkt].lock);
322                                 return 0;
323                         }
324
325                         if (prev_entry->activity > 0)
326                                 prev_entry->activity -= 1;
327                         if (entry->activity > prev_entry->activity &&
328                             entry->activity - prev_entry->activity >
329                             CIPSO_V4_CACHE_REORDERLIMIT) {
330                                 __list_del(entry->list.prev, entry->list.next);
331                                 __list_add(&entry->list,
332                                            prev_entry->list.prev,
333                                            &prev_entry->list);
334                         }
335
336                         spin_unlock(&cipso_v4_cache[bkt].lock);
337                         return 0;
338                 }
339                 prev_entry = entry;
340         }
341         spin_unlock(&cipso_v4_cache[bkt].lock);
342
343         return -ENOENT;
344 }
345
346 /**
347  * cipso_v4_cache_add - Add an entry to the CIPSO cache
348  * @skb: the packet
349  * @secattr: the packet's security attributes
350  *
351  * Description:
352  * Add a new entry into the CIPSO label mapping cache.  Add the new entry to
353  * head of the cache bucket's list, if the cache bucket is out of room remove
354  * the last entry in the list first.  It is important to note that there is
355  * currently no checking for duplicate keys.  Returns zero on success,
356  * negative values on failure.
357  *
358  */
359 int cipso_v4_cache_add(const struct sk_buff *skb,
360                        const struct netlbl_lsm_secattr *secattr)
361 {
362         int ret_val = -EPERM;
363         u32 bkt;
364         struct cipso_v4_map_cache_entry *entry = NULL;
365         struct cipso_v4_map_cache_entry *old_entry = NULL;
366         unsigned char *cipso_ptr;
367         u32 cipso_ptr_len;
368
369         if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
370                 return 0;
371
372         cipso_ptr = CIPSO_V4_OPTPTR(skb);
373         cipso_ptr_len = cipso_ptr[1];
374
375         entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
376         if (entry == NULL)
377                 return -ENOMEM;
378         entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC);
379         if (entry->key == NULL) {
380                 ret_val = -ENOMEM;
381                 goto cache_add_failure;
382         }
383         memcpy(entry->key, cipso_ptr, cipso_ptr_len);
384         entry->key_len = cipso_ptr_len;
385         entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
386         entry->lsm_data.free = secattr->cache.free;
387         entry->lsm_data.data = secattr->cache.data;
388
389         bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
390         spin_lock(&cipso_v4_cache[bkt].lock);
391         if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
392                 list_add(&entry->list, &cipso_v4_cache[bkt].list);
393                 cipso_v4_cache[bkt].size += 1;
394         } else {
395                 old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
396                                        struct cipso_v4_map_cache_entry, list);
397                 list_del(&old_entry->list);
398                 list_add(&entry->list, &cipso_v4_cache[bkt].list);
399                 cipso_v4_cache_entry_free(old_entry);
400         }
401         spin_unlock(&cipso_v4_cache[bkt].lock);
402
403         return 0;
404
405 cache_add_failure:
406         if (entry)
407                 cipso_v4_cache_entry_free(entry);
408         return ret_val;
409 }
410
411 /*
412  * DOI List Functions
413  */
414
415 /**
416  * cipso_v4_doi_search - Searches for a DOI definition
417  * @doi: the DOI to search for
418  *
419  * Description:
420  * Search the DOI definition list for a DOI definition with a DOI value that
421  * matches @doi.  The caller is responsibile for calling rcu_read_[un]lock().
422  * Returns a pointer to the DOI definition on success and NULL on failure.
423  */
424 static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
425 {
426         struct cipso_v4_doi *iter;
427
428         list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
429                 if (iter->doi == doi && iter->valid)
430                         return iter;
431         return NULL;
432 }
433
434 /**
435  * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
436  * @doi_def: the DOI structure
437  *
438  * Description:
439  * The caller defines a new DOI for use by the CIPSO engine and calls this
440  * function to add it to the list of acceptable domains.  The caller must
441  * ensure that the mapping table specified in @doi_def->map meets all of the
442  * requirements of the mapping type (see cipso_ipv4.h for details).  Returns
443  * zero on success and non-zero on failure.
444  *
445  */
446 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
447 {
448         if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
449                 return -EINVAL;
450
451         doi_def->valid = 1;
452         INIT_RCU_HEAD(&doi_def->rcu);
453         INIT_LIST_HEAD(&doi_def->dom_list);
454
455         rcu_read_lock();
456         if (cipso_v4_doi_search(doi_def->doi) != NULL)
457                 goto doi_add_failure_rlock;
458         spin_lock(&cipso_v4_doi_list_lock);
459         if (cipso_v4_doi_search(doi_def->doi) != NULL)
460                 goto doi_add_failure_slock;
461         list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
462         spin_unlock(&cipso_v4_doi_list_lock);
463         rcu_read_unlock();
464
465         return 0;
466
467 doi_add_failure_slock:
468         spin_unlock(&cipso_v4_doi_list_lock);
469 doi_add_failure_rlock:
470         rcu_read_unlock();
471         return -EEXIST;
472 }
473
474 /**
475  * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
476  * @doi: the DOI value
477  * @callback: the DOI cleanup/free callback
478  *
479  * Description:
480  * Removes a DOI definition from the CIPSO engine, @callback is called to
481  * free any memory.  The NetLabel routines will be called to release their own
482  * LSM domain mappings as well as our own domain list.  Returns zero on
483  * success and negative values on failure.
484  *
485  */
486 int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head))
487 {
488         struct cipso_v4_doi *doi_def;
489         struct cipso_v4_domhsh_entry *dom_iter;
490
491         rcu_read_lock();
492         if (cipso_v4_doi_search(doi) != NULL) {
493                 spin_lock(&cipso_v4_doi_list_lock);
494                 doi_def = cipso_v4_doi_search(doi);
495                 if (doi_def == NULL) {
496                         spin_unlock(&cipso_v4_doi_list_lock);
497                         rcu_read_unlock();
498                         return -ENOENT;
499                 }
500                 doi_def->valid = 0;
501                 list_del_rcu(&doi_def->list);
502                 spin_unlock(&cipso_v4_doi_list_lock);
503                 list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
504                         if (dom_iter->valid)
505                                 netlbl_domhsh_remove(dom_iter->domain);
506                 cipso_v4_cache_invalidate();
507                 rcu_read_unlock();
508
509                 call_rcu(&doi_def->rcu, callback);
510                 return 0;
511         }
512         rcu_read_unlock();
513
514         return -ENOENT;
515 }
516
517 /**
518  * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
519  * @doi: the DOI value
520  *
521  * Description:
522  * Searches for a valid DOI definition and if one is found it is returned to
523  * the caller.  Otherwise NULL is returned.  The caller must ensure that
524  * rcu_read_lock() is held while accessing the returned definition.
525  *
526  */
527 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
528 {
529         return cipso_v4_doi_search(doi);
530 }
531
532 /**
533  * cipso_v4_doi_dump_all - Dump all the CIPSO DOI definitions into a sk_buff
534  * @headroom: the amount of headroom to allocate for the sk_buff
535  *
536  * Description:
537  * Dump a list of all the configured DOI values into a sk_buff.  The returned
538  * sk_buff has room at the front of the sk_buff for @headroom bytes.  See
539  * net/netlabel/netlabel_cipso_v4.h for the LISTALL message format.  This
540  * function may fail if another process is changing the DOI list at the same
541  * time.  Returns a pointer to a sk_buff on success, NULL on error.
542  *
543  */
544 struct sk_buff *cipso_v4_doi_dump_all(size_t headroom)
545 {
546         struct sk_buff *skb = NULL;
547         struct cipso_v4_doi *iter;
548         u32 doi_cnt = 0;
549         ssize_t buf_len;
550
551         buf_len = NETLBL_LEN_U32;
552         rcu_read_lock();
553         list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
554                 if (iter->valid) {
555                         doi_cnt += 1;
556                         buf_len += 2 * NETLBL_LEN_U32;
557                 }
558
559         skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
560         if (skb == NULL)
561                 goto doi_dump_all_failure;
562
563         if (nla_put_u32(skb, NLA_U32, doi_cnt) != 0)
564                 goto doi_dump_all_failure;
565         buf_len -= NETLBL_LEN_U32;
566         list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
567                 if (iter->valid) {
568                         if (buf_len < 2 * NETLBL_LEN_U32)
569                                 goto doi_dump_all_failure;
570                         if (nla_put_u32(skb, NLA_U32, iter->doi) != 0)
571                                 goto doi_dump_all_failure;
572                         if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
573                                 goto doi_dump_all_failure;
574                         buf_len -= 2 * NETLBL_LEN_U32;
575                 }
576         rcu_read_unlock();
577
578         return skb;
579
580 doi_dump_all_failure:
581         rcu_read_unlock();
582         kfree(skb);
583         return NULL;
584 }
585
586 /**
587  * cipso_v4_doi_dump - Dump a CIPSO DOI definition into a sk_buff
588  * @doi: the DOI value
589  * @headroom: the amount of headroom to allocate for the sk_buff
590  *
591  * Description:
592  * Lookup the DOI definition matching @doi and dump it's contents into a
593  * sk_buff.  The returned sk_buff has room at the front of the sk_buff for
594  * @headroom bytes.  See net/netlabel/netlabel_cipso_v4.h for the LIST message
595  * format.  This function may fail if another process is changing the DOI list
596  * at the same time.  Returns a pointer to a sk_buff on success, NULL on error.
597  *
598  */
599 struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom)
600 {
601         struct sk_buff *skb = NULL;
602         struct cipso_v4_doi *iter;
603         u32 tag_cnt = 0;
604         u32 lvl_cnt = 0;
605         u32 cat_cnt = 0;
606         ssize_t buf_len;
607         ssize_t tmp;
608
609         rcu_read_lock();
610         iter = cipso_v4_doi_getdef(doi);
611         if (iter == NULL)
612                 goto doi_dump_failure;
613         buf_len = NETLBL_LEN_U32;
614         switch (iter->type) {
615         case CIPSO_V4_MAP_PASS:
616                 buf_len += NETLBL_LEN_U32;
617                 while(tag_cnt < CIPSO_V4_TAG_MAXCNT &&
618                       iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
619                         tag_cnt += 1;
620                         buf_len += NETLBL_LEN_U8;
621                 }
622                 break;
623         case CIPSO_V4_MAP_STD:
624                 buf_len += 3 * NETLBL_LEN_U32;
625                 while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
626                        iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
627                         tag_cnt += 1;
628                         buf_len += NETLBL_LEN_U8;
629                 }
630                 for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
631                         if (iter->map.std->lvl.local[tmp] !=
632                             CIPSO_V4_INV_LVL) {
633                                 lvl_cnt += 1;
634                                 buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U8;
635                         }
636                 for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
637                         if (iter->map.std->cat.local[tmp] !=
638                             CIPSO_V4_INV_CAT) {
639                                 cat_cnt += 1;
640                                 buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U16;
641                         }
642                 break;
643         }
644
645         skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
646         if (skb == NULL)
647                 goto doi_dump_failure;
648
649         if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
650                 goto doi_dump_failure;
651         buf_len -= NETLBL_LEN_U32;
652         if (iter != cipso_v4_doi_getdef(doi))
653                 goto doi_dump_failure;
654         switch (iter->type) {
655         case CIPSO_V4_MAP_PASS:
656                 if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
657                         goto doi_dump_failure;
658                 buf_len -= NETLBL_LEN_U32;
659                 for (tmp = 0;
660                      tmp < CIPSO_V4_TAG_MAXCNT &&
661                              iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
662                      tmp++) {
663                         if (buf_len < NETLBL_LEN_U8)
664                                 goto doi_dump_failure;
665                         if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
666                                 goto doi_dump_failure;
667                         buf_len -= NETLBL_LEN_U8;
668                 }
669                 break;
670         case CIPSO_V4_MAP_STD:
671                 if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
672                         goto doi_dump_failure;
673                 if (nla_put_u32(skb, NLA_U32, lvl_cnt) != 0)
674                         goto doi_dump_failure;
675                 if (nla_put_u32(skb, NLA_U32, cat_cnt) != 0)
676                         goto doi_dump_failure;
677                 buf_len -= 3 * NETLBL_LEN_U32;
678                 for (tmp = 0;
679                      tmp < CIPSO_V4_TAG_MAXCNT &&
680                              iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
681                      tmp++) {
682                         if (buf_len < NETLBL_LEN_U8)
683                                 goto doi_dump_failure;
684                         if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
685                                 goto doi_dump_failure;
686                         buf_len -= NETLBL_LEN_U8;
687                 }
688                 for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
689                         if (iter->map.std->lvl.local[tmp] !=
690                             CIPSO_V4_INV_LVL) {
691                                 if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U8)
692                                         goto doi_dump_failure;
693                                 if (nla_put_u32(skb, NLA_U32, tmp) != 0)
694                                         goto doi_dump_failure;
695                                 if (nla_put_u8(skb,
696                                            NLA_U8,
697                                            iter->map.std->lvl.local[tmp]) != 0)
698                                         goto doi_dump_failure;
699                                 buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U8;
700                         }
701                 for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
702                         if (iter->map.std->cat.local[tmp] !=
703                             CIPSO_V4_INV_CAT) {
704                                 if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U16)
705                                         goto doi_dump_failure;
706                                 if (nla_put_u32(skb, NLA_U32, tmp) != 0)
707                                         goto doi_dump_failure;
708                                 if (nla_put_u16(skb,
709                                            NLA_U16,
710                                            iter->map.std->cat.local[tmp]) != 0)
711                                         goto doi_dump_failure;
712                                 buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U16;
713                         }
714                 break;
715         }
716         rcu_read_unlock();
717
718         return skb;
719
720 doi_dump_failure:
721         rcu_read_unlock();
722         kfree(skb);
723         return NULL;
724 }
725
726 /**
727  * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
728  * @doi_def: the DOI definition
729  * @domain: the domain to add
730  *
731  * Description:
732  * Adds the @domain to the the DOI specified by @doi_def, this function
733  * should only be called by external functions (i.e. NetLabel).  This function
734  * does allocate memory.  Returns zero on success, negative values on failure.
735  *
736  */
737 int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
738 {
739         struct cipso_v4_domhsh_entry *iter;
740         struct cipso_v4_domhsh_entry *new_dom;
741
742         new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
743         if (new_dom == NULL)
744                 return -ENOMEM;
745         if (domain) {
746                 new_dom->domain = kstrdup(domain, GFP_KERNEL);
747                 if (new_dom->domain == NULL) {
748                         kfree(new_dom);
749                         return -ENOMEM;
750                 }
751         }
752         new_dom->valid = 1;
753         INIT_RCU_HEAD(&new_dom->rcu);
754
755         rcu_read_lock();
756         spin_lock(&cipso_v4_doi_list_lock);
757         list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
758                 if (iter->valid &&
759                     ((domain != NULL && iter->domain != NULL &&
760                       strcmp(iter->domain, domain) == 0) ||
761                      (domain == NULL && iter->domain == NULL))) {
762                         spin_unlock(&cipso_v4_doi_list_lock);
763                         rcu_read_unlock();
764                         kfree(new_dom->domain);
765                         kfree(new_dom);
766                         return -EEXIST;
767                 }
768         list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
769         spin_unlock(&cipso_v4_doi_list_lock);
770         rcu_read_unlock();
771
772         return 0;
773 }
774
775 /**
776  * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
777  * @doi_def: the DOI definition
778  * @domain: the domain to remove
779  *
780  * Description:
781  * Removes the @domain from the DOI specified by @doi_def, this function
782  * should only be called by external functions (i.e. NetLabel).   Returns zero
783  * on success and negative values on error.
784  *
785  */
786 int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
787                                const char *domain)
788 {
789         struct cipso_v4_domhsh_entry *iter;
790
791         rcu_read_lock();
792         spin_lock(&cipso_v4_doi_list_lock);
793         list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
794                 if (iter->valid &&
795                     ((domain != NULL && iter->domain != NULL &&
796                       strcmp(iter->domain, domain) == 0) ||
797                      (domain == NULL && iter->domain == NULL))) {
798                         iter->valid = 0;
799                         list_del_rcu(&iter->list);
800                         spin_unlock(&cipso_v4_doi_list_lock);
801                         rcu_read_unlock();
802                         call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
803
804                         return 0;
805                 }
806         spin_unlock(&cipso_v4_doi_list_lock);
807         rcu_read_unlock();
808
809         return -ENOENT;
810 }
811
812 /*
813  * Label Mapping Functions
814  */
815
816 /**
817  * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
818  * @doi_def: the DOI definition
819  * @level: the level to check
820  *
821  * Description:
822  * Checks the given level against the given DOI definition and returns a
823  * negative value if the level does not have a valid mapping and a zero value
824  * if the level is defined by the DOI.
825  *
826  */
827 static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
828 {
829         switch (doi_def->type) {
830         case CIPSO_V4_MAP_PASS:
831                 return 0;
832         case CIPSO_V4_MAP_STD:
833                 if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
834                         return 0;
835                 break;
836         }
837
838         return -EFAULT;
839 }
840
841 /**
842  * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
843  * @doi_def: the DOI definition
844  * @host_lvl: the host MLS level
845  * @net_lvl: the network/CIPSO MLS level
846  *
847  * Description:
848  * Perform a label mapping to translate a local MLS level to the correct
849  * CIPSO level using the given DOI definition.  Returns zero on success,
850  * negative values otherwise.
851  *
852  */
853 static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
854                                  u32 host_lvl,
855                                  u32 *net_lvl)
856 {
857         switch (doi_def->type) {
858         case CIPSO_V4_MAP_PASS:
859                 *net_lvl = host_lvl;
860                 return 0;
861         case CIPSO_V4_MAP_STD:
862                 if (host_lvl < doi_def->map.std->lvl.local_size) {
863                         *net_lvl = doi_def->map.std->lvl.local[host_lvl];
864                         return 0;
865                 }
866                 break;
867         }
868
869         return -EINVAL;
870 }
871
872 /**
873  * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
874  * @doi_def: the DOI definition
875  * @net_lvl: the network/CIPSO MLS level
876  * @host_lvl: the host MLS level
877  *
878  * Description:
879  * Perform a label mapping to translate a CIPSO level to the correct local MLS
880  * level using the given DOI definition.  Returns zero on success, negative
881  * values otherwise.
882  *
883  */
884 static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
885                                  u32 net_lvl,
886                                  u32 *host_lvl)
887 {
888         struct cipso_v4_std_map_tbl *map_tbl;
889
890         switch (doi_def->type) {
891         case CIPSO_V4_MAP_PASS:
892                 *host_lvl = net_lvl;
893                 return 0;
894         case CIPSO_V4_MAP_STD:
895                 map_tbl = doi_def->map.std;
896                 if (net_lvl < map_tbl->lvl.cipso_size &&
897                     map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
898                         *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
899                         return 0;
900                 }
901                 break;
902         }
903
904         return -EINVAL;
905 }
906
907 /**
908  * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
909  * @doi_def: the DOI definition
910  * @bitmap: category bitmap
911  * @bitmap_len: bitmap length in bytes
912  *
913  * Description:
914  * Checks the given category bitmap against the given DOI definition and
915  * returns a negative value if any of the categories in the bitmap do not have
916  * a valid mapping and a zero value if all of the categories are valid.
917  *
918  */
919 static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
920                                       const unsigned char *bitmap,
921                                       u32 bitmap_len)
922 {
923         int cat = -1;
924         u32 bitmap_len_bits = bitmap_len * 8;
925         u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
926         u32 *cipso_array = doi_def->map.std->cat.cipso;
927
928         switch (doi_def->type) {
929         case CIPSO_V4_MAP_PASS:
930                 return 0;
931         case CIPSO_V4_MAP_STD:
932                 for (;;) {
933                         cat = cipso_v4_bitmap_walk(bitmap,
934                                                    bitmap_len_bits,
935                                                    cat + 1,
936                                                    1);
937                         if (cat < 0)
938                                 break;
939                         if (cat >= cipso_cat_size ||
940                             cipso_array[cat] >= CIPSO_V4_INV_CAT)
941                                 return -EFAULT;
942                 }
943
944                 if (cat == -1)
945                         return 0;
946                 break;
947         }
948
949         return -EFAULT;
950 }
951
952 /**
953  * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
954  * @doi_def: the DOI definition
955  * @host_cat: the category bitmap in host format
956  * @host_cat_len: the length of the host's category bitmap in bytes
957  * @net_cat: the zero'd out category bitmap in network/CIPSO format
958  * @net_cat_len: the length of the CIPSO bitmap in bytes
959  *
960  * Description:
961  * Perform a label mapping to translate a local MLS category bitmap to the
962  * correct CIPSO bitmap using the given DOI definition.  Returns the minimum
963  * size in bytes of the network bitmap on success, negative values otherwise.
964  *
965  */
966 static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
967                                      const unsigned char *host_cat,
968                                      u32 host_cat_len,
969                                      unsigned char *net_cat,
970                                      u32 net_cat_len)
971 {
972         int host_spot = -1;
973         u32 net_spot;
974         u32 net_spot_max = 0;
975         u32 host_clen_bits = host_cat_len * 8;
976         u32 net_clen_bits = net_cat_len * 8;
977         u32 host_cat_size = doi_def->map.std->cat.local_size;
978         u32 *host_cat_array = doi_def->map.std->cat.local;
979
980         switch (doi_def->type) {
981         case CIPSO_V4_MAP_PASS:
982                 net_spot_max = host_cat_len - 1;
983                 while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
984                         net_spot_max--;
985                 if (net_spot_max > net_cat_len)
986                         return -EINVAL;
987                 memcpy(net_cat, host_cat, net_spot_max);
988                 return net_spot_max;
989         case CIPSO_V4_MAP_STD:
990                 for (;;) {
991                         host_spot = cipso_v4_bitmap_walk(host_cat,
992                                                          host_clen_bits,
993                                                          host_spot + 1,
994                                                          1);
995                         if (host_spot < 0)
996                                 break;
997                         if (host_spot >= host_cat_size)
998                                 return -EPERM;
999
1000                         net_spot = host_cat_array[host_spot];
1001                         if (net_spot >= net_clen_bits)
1002                                 return -ENOSPC;
1003                         cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
1004
1005                         if (net_spot > net_spot_max)
1006                                 net_spot_max = net_spot;
1007                 }
1008
1009                 if (host_spot == -2)
1010                         return -EFAULT;
1011
1012                 if (++net_spot_max % 8)
1013                         return net_spot_max / 8 + 1;
1014                 return net_spot_max / 8;
1015         }
1016
1017         return -EINVAL;
1018 }
1019
1020 /**
1021  * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
1022  * @doi_def: the DOI definition
1023  * @net_cat: the category bitmap in network/CIPSO format
1024  * @net_cat_len: the length of the CIPSO bitmap in bytes
1025  * @host_cat: the zero'd out category bitmap in host format
1026  * @host_cat_len: the length of the host's category bitmap in bytes
1027  *
1028  * Description:
1029  * Perform a label mapping to translate a CIPSO bitmap to the correct local
1030  * MLS category bitmap using the given DOI definition.  Returns the minimum
1031  * size in bytes of the host bitmap on success, negative values otherwise.
1032  *
1033  */
1034 static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
1035                                      const unsigned char *net_cat,
1036                                      u32 net_cat_len,
1037                                      unsigned char *host_cat,
1038                                      u32 host_cat_len)
1039 {
1040         u32 host_spot;
1041         u32 host_spot_max = 0;
1042         int net_spot = -1;
1043         u32 net_clen_bits = net_cat_len * 8;
1044         u32 host_clen_bits = host_cat_len * 8;
1045         u32 net_cat_size = doi_def->map.std->cat.cipso_size;
1046         u32 *net_cat_array = doi_def->map.std->cat.cipso;
1047
1048         switch (doi_def->type) {
1049         case CIPSO_V4_MAP_PASS:
1050                 if (net_cat_len > host_cat_len)
1051                         return -EINVAL;
1052                 memcpy(host_cat, net_cat, net_cat_len);
1053                 return net_cat_len;
1054         case CIPSO_V4_MAP_STD:
1055                 for (;;) {
1056                         net_spot = cipso_v4_bitmap_walk(net_cat,
1057                                                         net_clen_bits,
1058                                                         net_spot + 1,
1059                                                         1);
1060                         if (net_spot < 0)
1061                                 break;
1062                         if (net_spot >= net_cat_size ||
1063                             net_cat_array[net_spot] >= CIPSO_V4_INV_CAT)
1064                                 return -EPERM;
1065
1066                         host_spot = net_cat_array[net_spot];
1067                         if (host_spot >= host_clen_bits)
1068                                 return -ENOSPC;
1069                         cipso_v4_bitmap_setbit(host_cat, host_spot, 1);
1070
1071                         if (host_spot > host_spot_max)
1072                                 host_spot_max = host_spot;
1073                 }
1074
1075                 if (net_spot == -2)
1076                         return -EFAULT;
1077
1078                 if (++host_spot_max % 8)
1079                         return host_spot_max / 8 + 1;
1080                 return host_spot_max / 8;
1081         }
1082
1083         return -EINVAL;
1084 }
1085
1086 /*
1087  * Protocol Handling Functions
1088  */
1089
1090 #define CIPSO_V4_HDR_LEN              6
1091
1092 /**
1093  * cipso_v4_gentag_hdr - Generate a CIPSO option header
1094  * @doi_def: the DOI definition
1095  * @len: the total tag length in bytes
1096  * @buf: the CIPSO option buffer
1097  *
1098  * Description:
1099  * Write a CIPSO header into the beginning of @buffer.  Return zero on success,
1100  * negative values on failure.
1101  *
1102  */
1103 static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
1104                                u32 len,
1105                                unsigned char *buf)
1106 {
1107         if (CIPSO_V4_HDR_LEN + len > 40)
1108                 return -ENOSPC;
1109
1110         buf[0] = IPOPT_CIPSO;
1111         buf[1] = CIPSO_V4_HDR_LEN + len;
1112         *(u32 *)&buf[2] = htonl(doi_def->doi);
1113
1114         return 0;
1115 }
1116
1117 #define CIPSO_V4_TAG1_CAT_LEN         30
1118
1119 /**
1120  * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
1121  * @doi_def: the DOI definition
1122  * @secattr: the security attributes
1123  * @buffer: the option buffer
1124  * @buffer_len: length of buffer in bytes
1125  *
1126  * Description:
1127  * Generate a CIPSO option using the restricted bitmap tag, tag type #1.  The
1128  * actual buffer length may be larger than the indicated size due to
1129  * translation between host and network category bitmaps.  Returns zero on
1130  * success, negative values on failure.
1131  *
1132  */
1133 static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
1134                                const struct netlbl_lsm_secattr *secattr,
1135                                unsigned char **buffer,
1136                                u32 *buffer_len)
1137 {
1138         int ret_val = -EPERM;
1139         unsigned char *buf = NULL;
1140         u32 buf_len;
1141         u32 level;
1142
1143         if (secattr->mls_cat) {
1144                 buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN,
1145                               GFP_ATOMIC);
1146                 if (buf == NULL)
1147                         return -ENOMEM;
1148
1149                 ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
1150                                                     secattr->mls_cat,
1151                                                     secattr->mls_cat_len,
1152                                                     &buf[CIPSO_V4_HDR_LEN + 4],
1153                                                     CIPSO_V4_TAG1_CAT_LEN);
1154                 if (ret_val < 0)
1155                         goto gentag_failure;
1156
1157                 /* This will send packets using the "optimized" format when
1158                  * possibile as specified in  section 3.4.2.6 of the
1159                  * CIPSO draft. */
1160                 if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10))
1161                         ret_val = 10;
1162
1163                 buf_len = 4 + ret_val;
1164         } else {
1165                 buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC);
1166                 if (buf == NULL)
1167                         return -ENOMEM;
1168                 buf_len = 4;
1169         }
1170
1171         ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
1172         if (ret_val != 0)
1173                 goto gentag_failure;
1174
1175         ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf);
1176         if (ret_val != 0)
1177                 goto gentag_failure;
1178
1179         buf[CIPSO_V4_HDR_LEN] = 0x01;
1180         buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
1181         buf[CIPSO_V4_HDR_LEN + 3] = level;
1182
1183         *buffer = buf;
1184         *buffer_len = CIPSO_V4_HDR_LEN + buf_len;
1185
1186         return 0;
1187
1188 gentag_failure:
1189         kfree(buf);
1190         return ret_val;
1191 }
1192
1193 /**
1194  * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
1195  * @doi_def: the DOI definition
1196  * @tag: the CIPSO tag
1197  * @secattr: the security attributes
1198  *
1199  * Description:
1200  * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
1201  * attributes in @secattr.  Return zero on success, negatives values on
1202  * failure.
1203  *
1204  */
1205 static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1206                                  const unsigned char *tag,
1207                                  struct netlbl_lsm_secattr *secattr)
1208 {
1209         int ret_val;
1210         u8 tag_len = tag[1];
1211         u32 level;
1212
1213         ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
1214         if (ret_val != 0)
1215                 return ret_val;
1216         secattr->mls_lvl = level;
1217         secattr->mls_lvl_vld = 1;
1218
1219         if (tag_len > 4) {
1220                 switch (doi_def->type) {
1221                 case CIPSO_V4_MAP_PASS:
1222                         secattr->mls_cat_len = tag_len - 4;
1223                         break;
1224                 case CIPSO_V4_MAP_STD:
1225                         secattr->mls_cat_len =
1226                                 doi_def->map.std->cat.local_size;
1227                         break;
1228                 }
1229                 secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
1230                 if (secattr->mls_cat == NULL)
1231                         return -ENOMEM;
1232
1233                 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
1234                                                     &tag[4],
1235                                                     tag_len - 4,
1236                                                     secattr->mls_cat,
1237                                                     secattr->mls_cat_len);
1238                 if (ret_val < 0) {
1239                         kfree(secattr->mls_cat);
1240                         return ret_val;
1241                 }
1242                 secattr->mls_cat_len = ret_val;
1243         }
1244
1245         return 0;
1246 }
1247
1248 /**
1249  * cipso_v4_validate - Validate a CIPSO option
1250  * @option: the start of the option, on error it is set to point to the error
1251  *
1252  * Description:
1253  * This routine is called to validate a CIPSO option, it checks all of the
1254  * fields to ensure that they are at least valid, see the draft snippet below
1255  * for details.  If the option is valid then a zero value is returned and
1256  * the value of @option is unchanged.  If the option is invalid then a
1257  * non-zero value is returned and @option is adjusted to point to the
1258  * offending portion of the option.  From the IETF draft ...
1259  *
1260  *  "If any field within the CIPSO options, such as the DOI identifier, is not
1261  *   recognized the IP datagram is discarded and an ICMP 'parameter problem'
1262  *   (type 12) is generated and returned.  The ICMP code field is set to 'bad
1263  *   parameter' (code 0) and the pointer is set to the start of the CIPSO field
1264  *   that is unrecognized."
1265  *
1266  */
1267 int cipso_v4_validate(unsigned char **option)
1268 {
1269         unsigned char *opt = *option;
1270         unsigned char *tag;
1271         unsigned char opt_iter;
1272         unsigned char err_offset = 0;
1273         u8 opt_len;
1274         u8 tag_len;
1275         struct cipso_v4_doi *doi_def = NULL;
1276         u32 tag_iter;
1277
1278         /* caller already checks for length values that are too large */
1279         opt_len = opt[1];
1280         if (opt_len < 8) {
1281                 err_offset = 1;
1282                 goto validate_return;
1283         }
1284
1285         rcu_read_lock();
1286         doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2])));
1287         if (doi_def == NULL) {
1288                 err_offset = 2;
1289                 goto validate_return_locked;
1290         }
1291
1292         opt_iter = 6;
1293         tag = opt + opt_iter;
1294         while (opt_iter < opt_len) {
1295                 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
1296                         if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
1297                             ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
1298                                 err_offset = opt_iter;
1299                                 goto validate_return_locked;
1300                         }
1301
1302                 tag_len = tag[1];
1303                 if (tag_len > (opt_len - opt_iter)) {
1304                         err_offset = opt_iter + 1;
1305                         goto validate_return_locked;
1306                 }
1307
1308                 switch (tag[0]) {
1309                 case CIPSO_V4_TAG_RBITMAP:
1310                         if (tag_len < 4) {
1311                                 err_offset = opt_iter + 1;
1312                                 goto validate_return_locked;
1313                         }
1314
1315                         /* We are already going to do all the verification
1316                          * necessary at the socket layer so from our point of
1317                          * view it is safe to turn these checks off (and less
1318                          * work), however, the CIPSO draft says we should do
1319                          * all the CIPSO validations here but it doesn't
1320                          * really specify _exactly_ what we need to validate
1321                          * ... so, just make it a sysctl tunable. */
1322                         if (cipso_v4_rbm_strictvalid) {
1323                                 if (cipso_v4_map_lvl_valid(doi_def,
1324                                                            tag[3]) < 0) {
1325                                         err_offset = opt_iter + 3;
1326                                         goto validate_return_locked;
1327                                 }
1328                                 if (tag_len > 4 &&
1329                                     cipso_v4_map_cat_rbm_valid(doi_def,
1330                                                             &tag[4],
1331                                                             tag_len - 4) < 0) {
1332                                         err_offset = opt_iter + 4;
1333                                         goto validate_return_locked;
1334                                 }
1335                         }
1336                         break;
1337                 default:
1338                         err_offset = opt_iter;
1339                         goto validate_return_locked;
1340                 }
1341
1342                 tag += tag_len;
1343                 opt_iter += tag_len;
1344         }
1345
1346 validate_return_locked:
1347         rcu_read_unlock();
1348 validate_return:
1349         *option = opt + err_offset;
1350         return err_offset;
1351 }
1352
1353 /**
1354  * cipso_v4_error - Send the correct reponse for a bad packet
1355  * @skb: the packet
1356  * @error: the error code
1357  * @gateway: CIPSO gateway flag
1358  *
1359  * Description:
1360  * Based on the error code given in @error, send an ICMP error message back to
1361  * the originating host.  From the IETF draft ...
1362  *
1363  *  "If the contents of the CIPSO [option] are valid but the security label is
1364  *   outside of the configured host or port label range, the datagram is
1365  *   discarded and an ICMP 'destination unreachable' (type 3) is generated and
1366  *   returned.  The code field of the ICMP is set to 'communication with
1367  *   destination network administratively prohibited' (code 9) or to
1368  *   'communication with destination host administratively prohibited'
1369  *   (code 10).  The value of the code is dependent on whether the originator
1370  *   of the ICMP message is acting as a CIPSO host or a CIPSO gateway.  The
1371  *   recipient of the ICMP message MUST be able to handle either value.  The
1372  *   same procedure is performed if a CIPSO [option] can not be added to an
1373  *   IP packet because it is too large to fit in the IP options area."
1374  *
1375  *  "If the error is triggered by receipt of an ICMP message, the message is
1376  *   discarded and no response is permitted (consistent with general ICMP
1377  *   processing rules)."
1378  *
1379  */
1380 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
1381 {
1382         if (skb->nh.iph->protocol == IPPROTO_ICMP || error != -EACCES)
1383                 return;
1384
1385         if (gateway)
1386                 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
1387         else
1388                 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
1389 }
1390
1391 /**
1392  * cipso_v4_socket_setattr - Add a CIPSO option to a socket
1393  * @sock: the socket
1394  * @doi_def: the CIPSO DOI to use
1395  * @secattr: the specific security attributes of the socket
1396  *
1397  * Description:
1398  * Set the CIPSO option on the given socket using the DOI definition and
1399  * security attributes passed to the function.  This function requires
1400  * exclusive access to @sock->sk, which means it either needs to be in the
1401  * process of being created or locked via lock_sock(sock->sk).  Returns zero on
1402  * success and negative values on failure.
1403  *
1404  */
1405 int cipso_v4_socket_setattr(const struct socket *sock,
1406                             const struct cipso_v4_doi *doi_def,
1407                             const struct netlbl_lsm_secattr *secattr)
1408 {
1409         int ret_val = -EPERM;
1410         u32 iter;
1411         unsigned char *buf = NULL;
1412         u32 buf_len = 0;
1413         u32 opt_len;
1414         struct ip_options *opt = NULL;
1415         struct sock *sk;
1416         struct inet_sock *sk_inet;
1417         struct inet_connection_sock *sk_conn;
1418
1419         /* In the case of sock_create_lite(), the sock->sk field is not
1420          * defined yet but it is not a problem as the only users of these
1421          * "lite" PF_INET sockets are functions which do an accept() call
1422          * afterwards so we will label the socket as part of the accept(). */
1423         sk = sock->sk;
1424         if (sk == NULL)
1425                 return 0;
1426
1427         /* XXX - This code assumes only one tag per CIPSO option which isn't
1428          * really a good assumption to make but since we only support the MAC
1429          * tags right now it is a safe assumption. */
1430         iter = 0;
1431         do {
1432                 switch (doi_def->tags[iter]) {
1433                 case CIPSO_V4_TAG_RBITMAP:
1434                         ret_val = cipso_v4_gentag_rbm(doi_def,
1435                                                       secattr,
1436                                                       &buf,
1437                                                       &buf_len);
1438                         break;
1439                 default:
1440                         ret_val = -EPERM;
1441                         goto socket_setattr_failure;
1442                 }
1443
1444                 iter++;
1445         } while (ret_val != 0 &&
1446                  iter < CIPSO_V4_TAG_MAXCNT &&
1447                  doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
1448         if (ret_val != 0)
1449                 goto socket_setattr_failure;
1450
1451         /* We can't use ip_options_get() directly because it makes a call to
1452          * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
1453          * we can't block here. */
1454         opt_len = (buf_len + 3) & ~3;
1455         opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
1456         if (opt == NULL) {
1457                 ret_val = -ENOMEM;
1458                 goto socket_setattr_failure;
1459         }
1460         memcpy(opt->__data, buf, buf_len);
1461         opt->optlen = opt_len;
1462         opt->is_data = 1;
1463         kfree(buf);
1464         buf = NULL;
1465         ret_val = ip_options_compile(opt, NULL);
1466         if (ret_val != 0)
1467                 goto socket_setattr_failure;
1468
1469         sk_inet = inet_sk(sk);
1470         if (sk_inet->is_icsk) {
1471                 sk_conn = inet_csk(sk);
1472                 if (sk_inet->opt)
1473                         sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
1474                 sk_conn->icsk_ext_hdr_len += opt->optlen;
1475                 sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
1476         }
1477         opt = xchg(&sk_inet->opt, opt);
1478         kfree(opt);
1479
1480         return 0;
1481
1482 socket_setattr_failure:
1483         kfree(buf);
1484         kfree(opt);
1485         return ret_val;
1486 }
1487
1488 /**
1489  * cipso_v4_socket_getattr - Get the security attributes from a socket
1490  * @sock: the socket
1491  * @secattr: the security attributes
1492  *
1493  * Description:
1494  * Query @sock to see if there is a CIPSO option attached to the socket and if
1495  * there is return the CIPSO security attributes in @secattr.  Returns zero on
1496  * success and negative values on failure.
1497  *
1498  */
1499 int cipso_v4_socket_getattr(const struct socket *sock,
1500                             struct netlbl_lsm_secattr *secattr)
1501 {
1502         int ret_val = -ENOMSG;
1503         struct sock *sk;
1504         struct inet_sock *sk_inet;
1505         unsigned char *cipso_ptr;
1506         u32 doi;
1507         struct cipso_v4_doi *doi_def;
1508
1509         sk = sock->sk;
1510         lock_sock(sk);
1511         sk_inet = inet_sk(sk);
1512         if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0)
1513                 goto socket_getattr_return;
1514         cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
1515                 sizeof(struct iphdr);
1516         ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr);
1517         if (ret_val == 0)
1518                 goto socket_getattr_return;
1519
1520         doi = ntohl(*(u32 *)&cipso_ptr[2]);
1521         rcu_read_lock();
1522         doi_def = cipso_v4_doi_getdef(doi);
1523         if (doi_def == NULL) {
1524                 rcu_read_unlock();
1525                 goto socket_getattr_return;
1526         }
1527         switch (cipso_ptr[6]) {
1528         case CIPSO_V4_TAG_RBITMAP:
1529                 ret_val = cipso_v4_parsetag_rbm(doi_def,
1530                                                 &cipso_ptr[6],
1531                                                 secattr);
1532                 break;
1533         }
1534         rcu_read_unlock();
1535
1536 socket_getattr_return:
1537         release_sock(sk);
1538         return ret_val;
1539 }
1540
1541 /**
1542  * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
1543  * @skb: the packet
1544  * @secattr: the security attributes
1545  *
1546  * Description:
1547  * Parse the given packet's CIPSO option and return the security attributes.
1548  * Returns zero on success and negative values on failure.
1549  *
1550  */
1551 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
1552                             struct netlbl_lsm_secattr *secattr)
1553 {
1554         int ret_val = -ENOMSG;
1555         unsigned char *cipso_ptr;
1556         u32 doi;
1557         struct cipso_v4_doi *doi_def;
1558
1559         if (!CIPSO_V4_OPTEXIST(skb))
1560                 return -ENOMSG;
1561         cipso_ptr = CIPSO_V4_OPTPTR(skb);
1562         if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
1563                 return 0;
1564
1565         doi = ntohl(*(u32 *)&cipso_ptr[2]);
1566         rcu_read_lock();
1567         doi_def = cipso_v4_doi_getdef(doi);
1568         if (doi_def == NULL)
1569                 goto skbuff_getattr_return;
1570         switch (cipso_ptr[6]) {
1571         case CIPSO_V4_TAG_RBITMAP:
1572                 ret_val = cipso_v4_parsetag_rbm(doi_def,
1573                                                 &cipso_ptr[6],
1574                                                 secattr);
1575                 break;
1576         }
1577
1578 skbuff_getattr_return:
1579         rcu_read_unlock();
1580         return ret_val;
1581 }
1582
1583 /*
1584  * Setup Functions
1585  */
1586
1587 /**
1588  * cipso_v4_init - Initialize the CIPSO module
1589  *
1590  * Description:
1591  * Initialize the CIPSO module and prepare it for use.  Returns zero on success
1592  * and negative values on failure.
1593  *
1594  */
1595 static int __init cipso_v4_init(void)
1596 {
1597         int ret_val;
1598
1599         ret_val = cipso_v4_cache_init();
1600         if (ret_val != 0)
1601                 panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
1602                       ret_val);
1603
1604         return 0;
1605 }
1606
1607 subsys_initcall(cipso_v4_init);