LCOV - code coverage report
Current view: top level - net/ipv6 - calipso.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 14 508 2.8 %
Date: 2022-04-01 13:59:58 Functions: 2 31 6.5 %
Branches: 4 246 1.6 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * CALIPSO - Common Architecture Label IPv6 Security Option
       4                 :            :  *
       5                 :            :  * This is an implementation of the CALIPSO protocol as specified in
       6                 :            :  * RFC 5570.
       7                 :            :  *
       8                 :            :  * Authors: Paul Moore <paul.moore@hp.com>
       9                 :            :  *          Huw Davies <huw@codeweavers.com>
      10                 :            :  */
      11                 :            : 
      12                 :            : /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
      13                 :            :  * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <linux/init.h>
      17                 :            : #include <linux/types.h>
      18                 :            : #include <linux/rcupdate.h>
      19                 :            : #include <linux/list.h>
      20                 :            : #include <linux/spinlock.h>
      21                 :            : #include <linux/string.h>
      22                 :            : #include <linux/jhash.h>
      23                 :            : #include <linux/audit.h>
      24                 :            : #include <linux/slab.h>
      25                 :            : #include <net/ip.h>
      26                 :            : #include <net/icmp.h>
      27                 :            : #include <net/tcp.h>
      28                 :            : #include <net/netlabel.h>
      29                 :            : #include <net/calipso.h>
      30                 :            : #include <linux/atomic.h>
      31                 :            : #include <linux/bug.h>
      32                 :            : #include <asm/unaligned.h>
      33                 :            : #include <linux/crc-ccitt.h>
      34                 :            : 
      35                 :            : /* Maximium size of the calipso option including
      36                 :            :  * the two-byte TLV header.
      37                 :            :  */
      38                 :            : #define CALIPSO_OPT_LEN_MAX (2 + 252)
      39                 :            : 
      40                 :            : /* Size of the minimum calipso option including
      41                 :            :  * the two-byte TLV header.
      42                 :            :  */
      43                 :            : #define CALIPSO_HDR_LEN (2 + 8)
      44                 :            : 
      45                 :            : /* Maximium size of the calipso option including
      46                 :            :  * the two-byte TLV header and upto 3 bytes of
      47                 :            :  * leading pad and 7 bytes of trailing pad.
      48                 :            :  */
      49                 :            : #define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7)
      50                 :            : 
      51                 :            :  /* Maximium size of u32 aligned buffer required to hold calipso
      52                 :            :   * option.  Max of 3 initial pad bytes starting from buffer + 3.
      53                 :            :   * i.e. the worst case is when the previous tlv finishes on 4n + 3.
      54                 :            :   */
      55                 :            : #define CALIPSO_MAX_BUFFER (6 + CALIPSO_OPT_LEN_MAX)
      56                 :            : 
      57                 :            : /* List of available DOI definitions */
      58                 :            : static DEFINE_SPINLOCK(calipso_doi_list_lock);
      59                 :            : static LIST_HEAD(calipso_doi_list);
      60                 :            : 
      61                 :            : /* Label mapping cache */
      62                 :            : int calipso_cache_enabled = 1;
      63                 :            : int calipso_cache_bucketsize = 10;
      64                 :            : #define CALIPSO_CACHE_BUCKETBITS     7
      65                 :            : #define CALIPSO_CACHE_BUCKETS        BIT(CALIPSO_CACHE_BUCKETBITS)
      66                 :            : #define CALIPSO_CACHE_REORDERLIMIT   10
      67                 :            : struct calipso_map_cache_bkt {
      68                 :            :         spinlock_t lock;
      69                 :            :         u32 size;
      70                 :            :         struct list_head list;
      71                 :            : };
      72                 :            : 
      73                 :            : struct calipso_map_cache_entry {
      74                 :            :         u32 hash;
      75                 :            :         unsigned char *key;
      76                 :            :         size_t key_len;
      77                 :            : 
      78                 :            :         struct netlbl_lsm_cache *lsm_data;
      79                 :            : 
      80                 :            :         u32 activity;
      81                 :            :         struct list_head list;
      82                 :            : };
      83                 :            : 
      84                 :            : static struct calipso_map_cache_bkt *calipso_cache;
      85                 :            : 
      86                 :            : /* Label Mapping Cache Functions
      87                 :            :  */
      88                 :            : 
      89                 :            : /**
      90                 :            :  * calipso_cache_entry_free - Frees a cache entry
      91                 :            :  * @entry: the entry to free
      92                 :            :  *
      93                 :            :  * Description:
      94                 :            :  * This function frees the memory associated with a cache entry including the
      95                 :            :  * LSM cache data if there are no longer any users, i.e. reference count == 0.
      96                 :            :  *
      97                 :            :  */
      98                 :          0 : static void calipso_cache_entry_free(struct calipso_map_cache_entry *entry)
      99                 :            : {
     100         [ #  # ]:          0 :         if (entry->lsm_data)
     101                 :          0 :                 netlbl_secattr_cache_free(entry->lsm_data);
     102                 :          0 :         kfree(entry->key);
     103                 :          0 :         kfree(entry);
     104                 :          0 : }
     105                 :            : 
     106                 :            : /**
     107                 :            :  * calipso_map_cache_hash - Hashing function for the CALIPSO cache
     108                 :            :  * @key: the hash key
     109                 :            :  * @key_len: the length of the key in bytes
     110                 :            :  *
     111                 :            :  * Description:
     112                 :            :  * The CALIPSO tag hashing function.  Returns a 32-bit hash value.
     113                 :            :  *
     114                 :            :  */
     115                 :          0 : static u32 calipso_map_cache_hash(const unsigned char *key, u32 key_len)
     116                 :            : {
     117                 :          0 :         return jhash(key, key_len, 0);
     118                 :            : }
     119                 :            : 
     120                 :            : /**
     121                 :            :  * calipso_cache_init - Initialize the CALIPSO cache
     122                 :            :  *
     123                 :            :  * Description:
     124                 :            :  * Initializes the CALIPSO label mapping cache, this function should be called
     125                 :            :  * before any of the other functions defined in this file.  Returns zero on
     126                 :            :  * success, negative values on error.
     127                 :            :  *
     128                 :            :  */
     129                 :         78 : static int __init calipso_cache_init(void)
     130                 :            : {
     131                 :         78 :         u32 iter;
     132                 :            : 
     133                 :         78 :         calipso_cache = kcalloc(CALIPSO_CACHE_BUCKETS,
     134                 :            :                                 sizeof(struct calipso_map_cache_bkt),
     135                 :            :                                 GFP_KERNEL);
     136         [ +  - ]:         78 :         if (!calipso_cache)
     137                 :            :                 return -ENOMEM;
     138                 :            : 
     139         [ +  + ]:      10062 :         for (iter = 0; iter < CALIPSO_CACHE_BUCKETS; iter++) {
     140                 :       9984 :                 spin_lock_init(&calipso_cache[iter].lock);
     141                 :       9984 :                 calipso_cache[iter].size = 0;
     142                 :       9984 :                 INIT_LIST_HEAD(&calipso_cache[iter].list);
     143                 :            :         }
     144                 :            : 
     145                 :            :         return 0;
     146                 :            : }
     147                 :            : 
     148                 :            : /**
     149                 :            :  * calipso_cache_invalidate - Invalidates the current CALIPSO cache
     150                 :            :  *
     151                 :            :  * Description:
     152                 :            :  * Invalidates and frees any entries in the CALIPSO cache.  Returns zero on
     153                 :            :  * success and negative values on failure.
     154                 :            :  *
     155                 :            :  */
     156                 :          0 : static void calipso_cache_invalidate(void)
     157                 :            : {
     158                 :          0 :         struct calipso_map_cache_entry *entry, *tmp_entry;
     159                 :          0 :         u32 iter;
     160                 :            : 
     161         [ #  # ]:          0 :         for (iter = 0; iter < CALIPSO_CACHE_BUCKETS; iter++) {
     162                 :          0 :                 spin_lock_bh(&calipso_cache[iter].lock);
     163         [ #  # ]:          0 :                 list_for_each_entry_safe(entry,
     164                 :            :                                          tmp_entry,
     165                 :            :                                          &calipso_cache[iter].list, list) {
     166                 :          0 :                         list_del(&entry->list);
     167                 :          0 :                         calipso_cache_entry_free(entry);
     168                 :            :                 }
     169                 :          0 :                 calipso_cache[iter].size = 0;
     170                 :          0 :                 spin_unlock_bh(&calipso_cache[iter].lock);
     171                 :            :         }
     172                 :          0 : }
     173                 :            : 
     174                 :            : /**
     175                 :            :  * calipso_cache_check - Check the CALIPSO cache for a label mapping
     176                 :            :  * @key: the buffer to check
     177                 :            :  * @key_len: buffer length in bytes
     178                 :            :  * @secattr: the security attribute struct to use
     179                 :            :  *
     180                 :            :  * Description:
     181                 :            :  * This function checks the cache to see if a label mapping already exists for
     182                 :            :  * the given key.  If there is a match then the cache is adjusted and the
     183                 :            :  * @secattr struct is populated with the correct LSM security attributes.  The
     184                 :            :  * cache is adjusted in the following manner if the entry is not already the
     185                 :            :  * first in the cache bucket:
     186                 :            :  *
     187                 :            :  *  1. The cache entry's activity counter is incremented
     188                 :            :  *  2. The previous (higher ranking) entry's activity counter is decremented
     189                 :            :  *  3. If the difference between the two activity counters is geater than
     190                 :            :  *     CALIPSO_CACHE_REORDERLIMIT the two entries are swapped
     191                 :            :  *
     192                 :            :  * Returns zero on success, -ENOENT for a cache miss, and other negative values
     193                 :            :  * on error.
     194                 :            :  *
     195                 :            :  */
     196                 :          0 : static int calipso_cache_check(const unsigned char *key,
     197                 :            :                                u32 key_len,
     198                 :            :                                struct netlbl_lsm_secattr *secattr)
     199                 :            : {
     200                 :          0 :         u32 bkt;
     201                 :          0 :         struct calipso_map_cache_entry *entry;
     202                 :          0 :         struct calipso_map_cache_entry *prev_entry = NULL;
     203                 :          0 :         u32 hash;
     204                 :            : 
     205         [ #  # ]:          0 :         if (!calipso_cache_enabled)
     206                 :            :                 return -ENOENT;
     207                 :            : 
     208                 :          0 :         hash = calipso_map_cache_hash(key, key_len);
     209                 :          0 :         bkt = hash & (CALIPSO_CACHE_BUCKETS - 1);
     210                 :          0 :         spin_lock_bh(&calipso_cache[bkt].lock);
     211         [ #  # ]:          0 :         list_for_each_entry(entry, &calipso_cache[bkt].list, list) {
     212         [ #  # ]:          0 :                 if (entry->hash == hash &&
     213         [ #  # ]:          0 :                     entry->key_len == key_len &&
     214         [ #  # ]:          0 :                     memcmp(entry->key, key, key_len) == 0) {
     215                 :          0 :                         entry->activity += 1;
     216                 :          0 :                         refcount_inc(&entry->lsm_data->refcount);
     217                 :          0 :                         secattr->cache = entry->lsm_data;
     218                 :          0 :                         secattr->flags |= NETLBL_SECATTR_CACHE;
     219                 :          0 :                         secattr->type = NETLBL_NLTYPE_CALIPSO;
     220         [ #  # ]:          0 :                         if (!prev_entry) {
     221                 :          0 :                                 spin_unlock_bh(&calipso_cache[bkt].lock);
     222                 :          0 :                                 return 0;
     223                 :            :                         }
     224                 :            : 
     225         [ #  # ]:          0 :                         if (prev_entry->activity > 0)
     226                 :          0 :                                 prev_entry->activity -= 1;
     227         [ #  # ]:          0 :                         if (entry->activity > prev_entry->activity &&
     228         [ #  # ]:          0 :                             entry->activity - prev_entry->activity >
     229                 :            :                             CALIPSO_CACHE_REORDERLIMIT) {
     230                 :          0 :                                 __list_del(entry->list.prev, entry->list.next);
     231                 :          0 :                                 __list_add(&entry->list,
     232                 :            :                                            prev_entry->list.prev,
     233                 :            :                                            &prev_entry->list);
     234                 :            :                         }
     235                 :            : 
     236                 :          0 :                         spin_unlock_bh(&calipso_cache[bkt].lock);
     237                 :          0 :                         return 0;
     238                 :            :                 }
     239                 :          0 :                 prev_entry = entry;
     240                 :            :         }
     241                 :          0 :         spin_unlock_bh(&calipso_cache[bkt].lock);
     242                 :            : 
     243                 :          0 :         return -ENOENT;
     244                 :            : }
     245                 :            : 
     246                 :            : /**
     247                 :            :  * calipso_cache_add - Add an entry to the CALIPSO cache
     248                 :            :  * @calipso_ptr: the CALIPSO option
     249                 :            :  * @secattr: the packet's security attributes
     250                 :            :  *
     251                 :            :  * Description:
     252                 :            :  * Add a new entry into the CALIPSO label mapping cache.  Add the new entry to
     253                 :            :  * head of the cache bucket's list, if the cache bucket is out of room remove
     254                 :            :  * the last entry in the list first.  It is important to note that there is
     255                 :            :  * currently no checking for duplicate keys.  Returns zero on success,
     256                 :            :  * negative values on failure.  The key stored starts at calipso_ptr + 2,
     257                 :            :  * i.e. the type and length bytes are not stored, this corresponds to
     258                 :            :  * calipso_ptr[1] bytes of data.
     259                 :            :  *
     260                 :            :  */
     261                 :          0 : static int calipso_cache_add(const unsigned char *calipso_ptr,
     262                 :            :                              const struct netlbl_lsm_secattr *secattr)
     263                 :            : {
     264                 :          0 :         int ret_val = -EPERM;
     265                 :          0 :         u32 bkt;
     266                 :          0 :         struct calipso_map_cache_entry *entry = NULL;
     267                 :          0 :         struct calipso_map_cache_entry *old_entry = NULL;
     268                 :          0 :         u32 calipso_ptr_len;
     269                 :            : 
     270   [ #  #  #  # ]:          0 :         if (!calipso_cache_enabled || calipso_cache_bucketsize <= 0)
     271                 :            :                 return 0;
     272                 :            : 
     273                 :          0 :         calipso_ptr_len = calipso_ptr[1];
     274                 :            : 
     275                 :          0 :         entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
     276         [ #  # ]:          0 :         if (!entry)
     277                 :            :                 return -ENOMEM;
     278                 :          0 :         entry->key = kmemdup(calipso_ptr + 2, calipso_ptr_len, GFP_ATOMIC);
     279         [ #  # ]:          0 :         if (!entry->key) {
     280                 :          0 :                 ret_val = -ENOMEM;
     281                 :          0 :                 goto cache_add_failure;
     282                 :            :         }
     283                 :          0 :         entry->key_len = calipso_ptr_len;
     284                 :          0 :         entry->hash = calipso_map_cache_hash(calipso_ptr, calipso_ptr_len);
     285                 :          0 :         refcount_inc(&secattr->cache->refcount);
     286                 :          0 :         entry->lsm_data = secattr->cache;
     287                 :            : 
     288                 :          0 :         bkt = entry->hash & (CALIPSO_CACHE_BUCKETS - 1);
     289                 :          0 :         spin_lock_bh(&calipso_cache[bkt].lock);
     290         [ #  # ]:          0 :         if (calipso_cache[bkt].size < calipso_cache_bucketsize) {
     291                 :          0 :                 list_add(&entry->list, &calipso_cache[bkt].list);
     292                 :          0 :                 calipso_cache[bkt].size += 1;
     293                 :            :         } else {
     294                 :          0 :                 old_entry = list_entry(calipso_cache[bkt].list.prev,
     295                 :            :                                        struct calipso_map_cache_entry, list);
     296                 :          0 :                 list_del(&old_entry->list);
     297                 :          0 :                 list_add(&entry->list, &calipso_cache[bkt].list);
     298                 :          0 :                 calipso_cache_entry_free(old_entry);
     299                 :            :         }
     300                 :          0 :         spin_unlock_bh(&calipso_cache[bkt].lock);
     301                 :            : 
     302                 :          0 :         return 0;
     303                 :            : 
     304                 :            : cache_add_failure:
     305                 :          0 :         if (entry)
     306                 :          0 :                 calipso_cache_entry_free(entry);
     307                 :          0 :         return ret_val;
     308                 :            : }
     309                 :            : 
     310                 :            : /* DOI List Functions
     311                 :            :  */
     312                 :            : 
     313                 :            : /**
     314                 :            :  * calipso_doi_search - Searches for a DOI definition
     315                 :            :  * @doi: the DOI to search for
     316                 :            :  *
     317                 :            :  * Description:
     318                 :            :  * Search the DOI definition list for a DOI definition with a DOI value that
     319                 :            :  * matches @doi.  The caller is responsible for calling rcu_read_[un]lock().
     320                 :            :  * Returns a pointer to the DOI definition on success and NULL on failure.
     321                 :            :  */
     322                 :          0 : static struct calipso_doi *calipso_doi_search(u32 doi)
     323                 :            : {
     324                 :          0 :         struct calipso_doi *iter;
     325                 :            : 
     326         [ #  # ]:          0 :         list_for_each_entry_rcu(iter, &calipso_doi_list, list)
     327   [ #  #  #  # ]:          0 :                 if (iter->doi == doi && refcount_read(&iter->refcount))
     328                 :          0 :                         return iter;
     329                 :            :         return NULL;
     330                 :            : }
     331                 :            : 
     332                 :            : /**
     333                 :            :  * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
     334                 :            :  * @doi_def: the DOI structure
     335                 :            :  * @audit_info: NetLabel audit information
     336                 :            :  *
     337                 :            :  * Description:
     338                 :            :  * The caller defines a new DOI for use by the CALIPSO engine and calls this
     339                 :            :  * function to add it to the list of acceptable domains.  The caller must
     340                 :            :  * ensure that the mapping table specified in @doi_def->map meets all of the
     341                 :            :  * requirements of the mapping type (see calipso.h for details).  Returns
     342                 :            :  * zero on success and non-zero on failure.
     343                 :            :  *
     344                 :            :  */
     345                 :          0 : static int calipso_doi_add(struct calipso_doi *doi_def,
     346                 :            :                            struct netlbl_audit *audit_info)
     347                 :            : {
     348                 :          0 :         int ret_val = -EINVAL;
     349                 :          0 :         u32 doi;
     350                 :          0 :         u32 doi_type;
     351                 :          0 :         struct audit_buffer *audit_buf;
     352                 :            : 
     353                 :          0 :         doi = doi_def->doi;
     354                 :          0 :         doi_type = doi_def->type;
     355                 :            : 
     356         [ #  # ]:          0 :         if (doi_def->doi == CALIPSO_DOI_UNKNOWN)
     357                 :          0 :                 goto doi_add_return;
     358                 :            : 
     359                 :          0 :         refcount_set(&doi_def->refcount, 1);
     360                 :            : 
     361                 :          0 :         spin_lock(&calipso_doi_list_lock);
     362         [ #  # ]:          0 :         if (calipso_doi_search(doi_def->doi)) {
     363                 :          0 :                 spin_unlock(&calipso_doi_list_lock);
     364                 :          0 :                 ret_val = -EEXIST;
     365                 :          0 :                 goto doi_add_return;
     366                 :            :         }
     367                 :          0 :         list_add_tail_rcu(&doi_def->list, &calipso_doi_list);
     368                 :          0 :         spin_unlock(&calipso_doi_list_lock);
     369                 :          0 :         ret_val = 0;
     370                 :            : 
     371                 :          0 : doi_add_return:
     372                 :          0 :         audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_ADD, audit_info);
     373         [ #  # ]:          0 :         if (audit_buf) {
     374                 :          0 :                 const char *type_str;
     375                 :            : 
     376         [ #  # ]:          0 :                 switch (doi_type) {
     377                 :            :                 case CALIPSO_MAP_PASS:
     378                 :            :                         type_str = "pass";
     379                 :            :                         break;
     380                 :          0 :                 default:
     381                 :          0 :                         type_str = "(unknown)";
     382                 :            :                 }
     383                 :          0 :                 audit_log_format(audit_buf,
     384                 :            :                                  " calipso_doi=%u calipso_type=%s res=%u",
     385                 :            :                                  doi, type_str, ret_val == 0 ? 1 : 0);
     386                 :          0 :                 audit_log_end(audit_buf);
     387                 :            :         }
     388                 :            : 
     389                 :          0 :         return ret_val;
     390                 :            : }
     391                 :            : 
     392                 :            : /**
     393                 :            :  * calipso_doi_free - Frees a DOI definition
     394                 :            :  * @doi_def: the DOI definition
     395                 :            :  *
     396                 :            :  * Description:
     397                 :            :  * This function frees all of the memory associated with a DOI definition.
     398                 :            :  *
     399                 :            :  */
     400                 :          0 : static void calipso_doi_free(struct calipso_doi *doi_def)
     401                 :            : {
     402                 :          0 :         kfree(doi_def);
     403                 :          0 : }
     404                 :            : 
     405                 :            : /**
     406                 :            :  * calipso_doi_free_rcu - Frees a DOI definition via the RCU pointer
     407                 :            :  * @entry: the entry's RCU field
     408                 :            :  *
     409                 :            :  * Description:
     410                 :            :  * This function is designed to be used as a callback to the call_rcu()
     411                 :            :  * function so that the memory allocated to the DOI definition can be released
     412                 :            :  * safely.
     413                 :            :  *
     414                 :            :  */
     415                 :          0 : static void calipso_doi_free_rcu(struct rcu_head *entry)
     416                 :            : {
     417                 :          0 :         struct calipso_doi *doi_def;
     418                 :            : 
     419                 :          0 :         doi_def = container_of(entry, struct calipso_doi, rcu);
     420                 :          0 :         calipso_doi_free(doi_def);
     421                 :          0 : }
     422                 :            : 
     423                 :            : /**
     424                 :            :  * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
     425                 :            :  * @doi: the DOI value
     426                 :            :  * @audit_secid: the LSM secid to use in the audit message
     427                 :            :  *
     428                 :            :  * Description:
     429                 :            :  * Removes a DOI definition from the CALIPSO engine.  The NetLabel routines will
     430                 :            :  * be called to release their own LSM domain mappings as well as our own
     431                 :            :  * domain list.  Returns zero on success and negative values on failure.
     432                 :            :  *
     433                 :            :  */
     434                 :          0 : static int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
     435                 :            : {
     436                 :          0 :         int ret_val;
     437                 :          0 :         struct calipso_doi *doi_def;
     438                 :          0 :         struct audit_buffer *audit_buf;
     439                 :            : 
     440                 :          0 :         spin_lock(&calipso_doi_list_lock);
     441                 :          0 :         doi_def = calipso_doi_search(doi);
     442         [ #  # ]:          0 :         if (!doi_def) {
     443                 :          0 :                 spin_unlock(&calipso_doi_list_lock);
     444                 :          0 :                 ret_val = -ENOENT;
     445                 :          0 :                 goto doi_remove_return;
     446                 :            :         }
     447         [ #  # ]:          0 :         if (!refcount_dec_and_test(&doi_def->refcount)) {
     448                 :          0 :                 spin_unlock(&calipso_doi_list_lock);
     449                 :          0 :                 ret_val = -EBUSY;
     450                 :          0 :                 goto doi_remove_return;
     451                 :            :         }
     452                 :          0 :         list_del_rcu(&doi_def->list);
     453                 :          0 :         spin_unlock(&calipso_doi_list_lock);
     454                 :            : 
     455                 :          0 :         call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
     456                 :          0 :         ret_val = 0;
     457                 :            : 
     458                 :          0 : doi_remove_return:
     459                 :          0 :         audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_DEL, audit_info);
     460         [ #  # ]:          0 :         if (audit_buf) {
     461                 :          0 :                 audit_log_format(audit_buf,
     462                 :            :                                  " calipso_doi=%u res=%u",
     463                 :            :                                  doi, ret_val == 0 ? 1 : 0);
     464                 :          0 :                 audit_log_end(audit_buf);
     465                 :            :         }
     466                 :            : 
     467                 :          0 :         return ret_val;
     468                 :            : }
     469                 :            : 
     470                 :            : /**
     471                 :            :  * calipso_doi_getdef - Returns a reference to a valid DOI definition
     472                 :            :  * @doi: the DOI value
     473                 :            :  *
     474                 :            :  * Description:
     475                 :            :  * Searches for a valid DOI definition and if one is found it is returned to
     476                 :            :  * the caller.  Otherwise NULL is returned.  The caller must ensure that
     477                 :            :  * calipso_doi_putdef() is called when the caller is done.
     478                 :            :  *
     479                 :            :  */
     480                 :          0 : static struct calipso_doi *calipso_doi_getdef(u32 doi)
     481                 :            : {
     482                 :          0 :         struct calipso_doi *doi_def;
     483                 :            : 
     484                 :          0 :         rcu_read_lock();
     485                 :          0 :         doi_def = calipso_doi_search(doi);
     486         [ #  # ]:          0 :         if (!doi_def)
     487                 :          0 :                 goto doi_getdef_return;
     488         [ #  # ]:          0 :         if (!refcount_inc_not_zero(&doi_def->refcount))
     489                 :          0 :                 doi_def = NULL;
     490                 :            : 
     491                 :          0 : doi_getdef_return:
     492                 :          0 :         rcu_read_unlock();
     493                 :          0 :         return doi_def;
     494                 :            : }
     495                 :            : 
     496                 :            : /**
     497                 :            :  * calipso_doi_putdef - Releases a reference for the given DOI definition
     498                 :            :  * @doi_def: the DOI definition
     499                 :            :  *
     500                 :            :  * Description:
     501                 :            :  * Releases a DOI definition reference obtained from calipso_doi_getdef().
     502                 :            :  *
     503                 :            :  */
     504                 :          0 : static void calipso_doi_putdef(struct calipso_doi *doi_def)
     505                 :            : {
     506         [ #  # ]:          0 :         if (!doi_def)
     507                 :            :                 return;
     508                 :            : 
     509         [ #  # ]:          0 :         if (!refcount_dec_and_test(&doi_def->refcount))
     510                 :            :                 return;
     511                 :          0 :         spin_lock(&calipso_doi_list_lock);
     512                 :          0 :         list_del_rcu(&doi_def->list);
     513                 :          0 :         spin_unlock(&calipso_doi_list_lock);
     514                 :            : 
     515                 :          0 :         call_rcu(&doi_def->rcu, calipso_doi_free_rcu);
     516                 :            : }
     517                 :            : 
     518                 :            : /**
     519                 :            :  * calipso_doi_walk - Iterate through the DOI definitions
     520                 :            :  * @skip_cnt: skip past this number of DOI definitions, updated
     521                 :            :  * @callback: callback for each DOI definition
     522                 :            :  * @cb_arg: argument for the callback function
     523                 :            :  *
     524                 :            :  * Description:
     525                 :            :  * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
     526                 :            :  * For each entry call @callback, if @callback returns a negative value stop
     527                 :            :  * 'walking' through the list and return.  Updates the value in @skip_cnt upon
     528                 :            :  * return.  Returns zero on success, negative values on failure.
     529                 :            :  *
     530                 :            :  */
     531                 :          0 : static int calipso_doi_walk(u32 *skip_cnt,
     532                 :            :                             int (*callback)(struct calipso_doi *doi_def,
     533                 :            :                                             void *arg),
     534                 :            :                             void *cb_arg)
     535                 :            : {
     536                 :          0 :         int ret_val = -ENOENT;
     537                 :          0 :         u32 doi_cnt = 0;
     538                 :          0 :         struct calipso_doi *iter_doi;
     539                 :            : 
     540                 :          0 :         rcu_read_lock();
     541         [ #  # ]:          0 :         list_for_each_entry_rcu(iter_doi, &calipso_doi_list, list)
     542         [ #  # ]:          0 :                 if (refcount_read(&iter_doi->refcount) > 0) {
     543         [ #  # ]:          0 :                         if (doi_cnt++ < *skip_cnt)
     544                 :          0 :                                 continue;
     545                 :          0 :                         ret_val = callback(iter_doi, cb_arg);
     546         [ #  # ]:          0 :                         if (ret_val < 0) {
     547                 :          0 :                                 doi_cnt--;
     548                 :          0 :                                 goto doi_walk_return;
     549                 :            :                         }
     550                 :            :                 }
     551                 :            : 
     552                 :          0 : doi_walk_return:
     553                 :          0 :         rcu_read_unlock();
     554                 :          0 :         *skip_cnt = doi_cnt;
     555                 :          0 :         return ret_val;
     556                 :            : }
     557                 :            : 
     558                 :            : /**
     559                 :            :  * calipso_validate - Validate a CALIPSO option
     560                 :            :  * @skb: the packet
     561                 :            :  * @option: the start of the option
     562                 :            :  *
     563                 :            :  * Description:
     564                 :            :  * This routine is called to validate a CALIPSO option.
     565                 :            :  * If the option is valid then %true is returned, otherwise
     566                 :            :  * %false is returned.
     567                 :            :  *
     568                 :            :  * The caller should have already checked that the length of the
     569                 :            :  * option (including the TLV header) is >= 10 and that the catmap
     570                 :            :  * length is consistent with the option length.
     571                 :            :  *
     572                 :            :  * We leave checks on the level and categories to the socket layer.
     573                 :            :  */
     574                 :          0 : bool calipso_validate(const struct sk_buff *skb, const unsigned char *option)
     575                 :            : {
     576                 :          0 :         struct calipso_doi *doi_def;
     577                 :          0 :         bool ret_val;
     578                 :          0 :         u16 crc, len = option[1] + 2;
     579                 :          0 :         static const u8 zero[2];
     580                 :            : 
     581                 :            :         /* The original CRC runs over the option including the TLV header
     582                 :            :          * with the CRC-16 field (at offset 8) zeroed out. */
     583                 :          0 :         crc = crc_ccitt(0xffff, option, 8);
     584                 :          0 :         crc = crc_ccitt(crc, zero, sizeof(zero));
     585         [ #  # ]:          0 :         if (len > 10)
     586                 :          0 :                 crc = crc_ccitt(crc, option + 10, len - 10);
     587                 :          0 :         crc = ~crc;
     588   [ #  #  #  # ]:          0 :         if (option[8] != (crc & 0xff) || option[9] != ((crc >> 8) & 0xff))
     589                 :            :                 return false;
     590                 :            : 
     591                 :          0 :         rcu_read_lock();
     592                 :          0 :         doi_def = calipso_doi_search(get_unaligned_be32(option + 2));
     593                 :          0 :         ret_val = !!doi_def;
     594                 :          0 :         rcu_read_unlock();
     595                 :            : 
     596                 :          0 :         return ret_val;
     597                 :            : }
     598                 :            : 
     599                 :            : /**
     600                 :            :  * calipso_map_cat_hton - Perform a category mapping from host to network
     601                 :            :  * @doi_def: the DOI definition
     602                 :            :  * @secattr: the security attributes
     603                 :            :  * @net_cat: the zero'd out category bitmap in network/CALIPSO format
     604                 :            :  * @net_cat_len: the length of the CALIPSO bitmap in bytes
     605                 :            :  *
     606                 :            :  * Description:
     607                 :            :  * Perform a label mapping to translate a local MLS category bitmap to the
     608                 :            :  * correct CALIPSO bitmap using the given DOI definition.  Returns the minimum
     609                 :            :  * size in bytes of the network bitmap on success, negative values otherwise.
     610                 :            :  *
     611                 :            :  */
     612                 :            : static int calipso_map_cat_hton(const struct calipso_doi *doi_def,
     613                 :            :                                 const struct netlbl_lsm_secattr *secattr,
     614                 :            :                                 unsigned char *net_cat,
     615                 :            :                                 u32 net_cat_len)
     616                 :            : {
     617                 :            :         int spot = -1;
     618                 :            :         u32 net_spot_max = 0;
     619                 :            :         u32 net_clen_bits = net_cat_len * 8;
     620                 :            : 
     621                 :            :         for (;;) {
     622                 :            :                 spot = netlbl_catmap_walk(secattr->attr.mls.cat,
     623                 :            :                                           spot + 1);
     624                 :            :                 if (spot < 0)
     625                 :            :                         break;
     626                 :            :                 if (spot >= net_clen_bits)
     627                 :            :                         return -ENOSPC;
     628                 :            :                 netlbl_bitmap_setbit(net_cat, spot, 1);
     629                 :            : 
     630                 :            :                 if (spot > net_spot_max)
     631                 :            :                         net_spot_max = spot;
     632                 :            :         }
     633                 :            : 
     634                 :            :         return (net_spot_max / 32 + 1) * 4;
     635                 :            : }
     636                 :            : 
     637                 :            : /**
     638                 :            :  * calipso_map_cat_ntoh - Perform a category mapping from network to host
     639                 :            :  * @doi_def: the DOI definition
     640                 :            :  * @net_cat: the category bitmap in network/CALIPSO format
     641                 :            :  * @net_cat_len: the length of the CALIPSO bitmap in bytes
     642                 :            :  * @secattr: the security attributes
     643                 :            :  *
     644                 :            :  * Description:
     645                 :            :  * Perform a label mapping to translate a CALIPSO bitmap to the correct local
     646                 :            :  * MLS category bitmap using the given DOI definition.  Returns zero on
     647                 :            :  * success, negative values on failure.
     648                 :            :  *
     649                 :            :  */
     650                 :            : static int calipso_map_cat_ntoh(const struct calipso_doi *doi_def,
     651                 :            :                                 const unsigned char *net_cat,
     652                 :            :                                 u32 net_cat_len,
     653                 :            :                                 struct netlbl_lsm_secattr *secattr)
     654                 :            : {
     655                 :            :         int ret_val;
     656                 :            :         int spot = -1;
     657                 :            :         u32 net_clen_bits = net_cat_len * 8;
     658                 :            : 
     659                 :            :         for (;;) {
     660                 :            :                 spot = netlbl_bitmap_walk(net_cat,
     661                 :            :                                           net_clen_bits,
     662                 :            :                                           spot + 1,
     663                 :            :                                           1);
     664                 :            :                 if (spot < 0) {
     665                 :            :                         if (spot == -2)
     666                 :            :                                 return -EFAULT;
     667                 :            :                         return 0;
     668                 :            :                 }
     669                 :            : 
     670                 :            :                 ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
     671                 :            :                                                spot,
     672                 :            :                                                GFP_ATOMIC);
     673                 :            :                 if (ret_val != 0)
     674                 :            :                         return ret_val;
     675                 :            :         }
     676                 :            : 
     677                 :            :         return -EINVAL;
     678                 :            : }
     679                 :            : 
     680                 :            : /**
     681                 :            :  * calipso_pad_write - Writes pad bytes in TLV format
     682                 :            :  * @buf: the buffer
     683                 :            :  * @offset: offset from start of buffer to write padding
     684                 :            :  * @count: number of pad bytes to write
     685                 :            :  *
     686                 :            :  * Description:
     687                 :            :  * Write @count bytes of TLV padding into @buffer starting at offset @offset.
     688                 :            :  * @count should be less than 8 - see RFC 4942.
     689                 :            :  *
     690                 :            :  */
     691                 :          0 : static int calipso_pad_write(unsigned char *buf, unsigned int offset,
     692                 :            :                              unsigned int count)
     693                 :            : {
     694   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(count >= 8))
     695                 :            :                 return -EINVAL;
     696                 :            : 
     697      [ #  #  # ]:          0 :         switch (count) {
     698                 :            :         case 0:
     699                 :            :                 break;
     700                 :          0 :         case 1:
     701                 :          0 :                 buf[offset] = IPV6_TLV_PAD1;
     702                 :          0 :                 break;
     703                 :          0 :         default:
     704                 :          0 :                 buf[offset] = IPV6_TLV_PADN;
     705                 :          0 :                 buf[offset + 1] = count - 2;
     706         [ #  # ]:          0 :                 if (count > 2)
     707                 :          0 :                         memset(buf + offset + 2, 0, count - 2);
     708                 :            :                 break;
     709                 :            :         }
     710                 :            :         return 0;
     711                 :            : }
     712                 :            : 
     713                 :            : /**
     714                 :            :  * calipso_genopt - Generate a CALIPSO option
     715                 :            :  * @buf: the option buffer
     716                 :            :  * @start: offset from which to write
     717                 :            :  * @buf_len: the size of opt_buf
     718                 :            :  * @doi_def: the CALIPSO DOI to use
     719                 :            :  * @secattr: the security attributes
     720                 :            :  *
     721                 :            :  * Description:
     722                 :            :  * Generate a CALIPSO option using the DOI definition and security attributes
     723                 :            :  * passed to the function. This also generates upto three bytes of leading
     724                 :            :  * padding that ensures that the option is 4n + 2 aligned.  It returns the
     725                 :            :  * number of bytes written (including any initial padding).
     726                 :            :  */
     727                 :            : static int calipso_genopt(unsigned char *buf, u32 start, u32 buf_len,
     728                 :            :                           const struct calipso_doi *doi_def,
     729                 :            :                           const struct netlbl_lsm_secattr *secattr)
     730                 :            : {
     731                 :            :         int ret_val;
     732                 :            :         u32 len, pad;
     733                 :            :         u16 crc;
     734                 :            :         static const unsigned char padding[4] = {2, 1, 0, 3};
     735                 :            :         unsigned char *calipso;
     736                 :            : 
     737                 :            :         /* CALIPSO has 4n + 2 alignment */
     738                 :            :         pad = padding[start & 3];
     739                 :            :         if (buf_len <= start + pad + CALIPSO_HDR_LEN)
     740                 :            :                 return -ENOSPC;
     741                 :            : 
     742                 :            :         if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
     743                 :            :                 return -EPERM;
     744                 :            : 
     745                 :            :         len = CALIPSO_HDR_LEN;
     746                 :            : 
     747                 :            :         if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
     748                 :            :                 ret_val = calipso_map_cat_hton(doi_def,
     749                 :            :                                                secattr,
     750                 :            :                                                buf + start + pad + len,
     751                 :            :                                                buf_len - start - pad - len);
     752                 :            :                 if (ret_val < 0)
     753                 :            :                         return ret_val;
     754                 :            :                 len += ret_val;
     755                 :            :         }
     756                 :            : 
     757                 :            :         calipso_pad_write(buf, start, pad);
     758                 :            :         calipso = buf + start + pad;
     759                 :            : 
     760                 :            :         calipso[0] = IPV6_TLV_CALIPSO;
     761                 :            :         calipso[1] = len - 2;
     762                 :            :         *(__be32 *)(calipso + 2) = htonl(doi_def->doi);
     763                 :            :         calipso[6] = (len - CALIPSO_HDR_LEN) / 4;
     764                 :            :         calipso[7] = secattr->attr.mls.lvl,
     765                 :            :         crc = ~crc_ccitt(0xffff, calipso, len);
     766                 :            :         calipso[8] = crc & 0xff;
     767                 :            :         calipso[9] = (crc >> 8) & 0xff;
     768                 :            :         return pad + len;
     769                 :            : }
     770                 :            : 
     771                 :            : /* Hop-by-hop hdr helper functions
     772                 :            :  */
     773                 :            : 
     774                 :            : /**
     775                 :            :  * calipso_opt_update - Replaces socket's hop options with a new set
     776                 :            :  * @sk: the socket
     777                 :            :  * @hop: new hop options
     778                 :            :  *
     779                 :            :  * Description:
     780                 :            :  * Replaces @sk's hop options with @hop.  @hop may be NULL to leave
     781                 :            :  * the socket with no hop options.
     782                 :            :  *
     783                 :            :  */
     784                 :          0 : static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
     785                 :            : {
     786         [ #  # ]:          0 :         struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
     787                 :            : 
     788                 :          0 :         txopts = ipv6_renew_options(sk, old, IPV6_HOPOPTS, hop);
     789                 :          0 :         txopt_put(old);
     790         [ #  # ]:          0 :         if (IS_ERR(txopts))
     791                 :          0 :                 return PTR_ERR(txopts);
     792                 :            : 
     793                 :          0 :         txopts = ipv6_update_options(sk, txopts);
     794         [ #  # ]:          0 :         if (txopts) {
     795                 :          0 :                 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
     796                 :          0 :                 txopt_put(txopts);
     797                 :            :         }
     798                 :            : 
     799                 :            :         return 0;
     800                 :            : }
     801                 :            : 
     802                 :            : /**
     803                 :            :  * calipso_tlv_len - Returns the length of the TLV
     804                 :            :  * @opt: the option header
     805                 :            :  * @offset: offset of the TLV within the header
     806                 :            :  *
     807                 :            :  * Description:
     808                 :            :  * Returns the length of the TLV option at offset @offset within
     809                 :            :  * the option header @opt.  Checks that the entire TLV fits inside
     810                 :            :  * the option header, returns a negative value if this is not the case.
     811                 :            :  */
     812                 :          0 : static int calipso_tlv_len(struct ipv6_opt_hdr *opt, unsigned int offset)
     813                 :            : {
     814                 :          0 :         unsigned char *tlv = (unsigned char *)opt;
     815                 :          0 :         unsigned int opt_len = ipv6_optlen(opt), tlv_len;
     816                 :            : 
     817         [ #  # ]:          0 :         if (offset < sizeof(*opt) || offset >= opt_len)
     818                 :            :                 return -EINVAL;
     819         [ #  # ]:          0 :         if (tlv[offset] == IPV6_TLV_PAD1)
     820                 :            :                 return 1;
     821         [ #  # ]:          0 :         if (offset + 1 >= opt_len)
     822                 :            :                 return -EINVAL;
     823                 :          0 :         tlv_len = tlv[offset + 1] + 2;
     824         [ #  # ]:          0 :         if (offset + tlv_len > opt_len)
     825                 :          0 :                 return -EINVAL;
     826                 :            :         return tlv_len;
     827                 :            : }
     828                 :            : 
     829                 :            : /**
     830                 :            :  * calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
     831                 :            :  * @hop: the hop options header
     832                 :            :  * @start: on return holds the offset of any leading padding
     833                 :            :  * @end: on return holds the offset of the first non-pad TLV after CALIPSO
     834                 :            :  *
     835                 :            :  * Description:
     836                 :            :  * Finds the space occupied by a CALIPSO option (including any leading and
     837                 :            :  * trailing padding).
     838                 :            :  *
     839                 :            :  * If a CALIPSO option exists set @start and @end to the
     840                 :            :  * offsets within @hop of the start of padding before the first
     841                 :            :  * CALIPSO option and the end of padding after the first CALIPSO
     842                 :            :  * option.  In this case the function returns 0.
     843                 :            :  *
     844                 :            :  * In the absence of a CALIPSO option, @start and @end will be
     845                 :            :  * set to the start and end of any trailing padding in the header.
     846                 :            :  * This is useful when appending a new option, as the caller may want
     847                 :            :  * to overwrite some of this padding.  In this case the function will
     848                 :            :  * return -ENOENT.
     849                 :            :  */
     850                 :          0 : static int calipso_opt_find(struct ipv6_opt_hdr *hop, unsigned int *start,
     851                 :            :                             unsigned int *end)
     852                 :            : {
     853                 :          0 :         int ret_val = -ENOENT, tlv_len;
     854                 :          0 :         unsigned int opt_len, offset, offset_s = 0, offset_e = 0;
     855                 :          0 :         unsigned char *opt = (unsigned char *)hop;
     856                 :            : 
     857                 :          0 :         opt_len = ipv6_optlen(hop);
     858                 :          0 :         offset = sizeof(*hop);
     859                 :            : 
     860         [ #  # ]:          0 :         while (offset < opt_len) {
     861                 :          0 :                 tlv_len = calipso_tlv_len(hop, offset);
     862         [ #  # ]:          0 :                 if (tlv_len < 0)
     863                 :          0 :                         return tlv_len;
     864                 :            : 
     865      [ #  #  # ]:          0 :                 switch (opt[offset]) {
     866                 :          0 :                 case IPV6_TLV_PAD1:
     867                 :            :                 case IPV6_TLV_PADN:
     868         [ #  # ]:          0 :                         if (offset_e)
     869                 :          0 :                                 offset_e = offset;
     870                 :            :                         break;
     871                 :            :                 case IPV6_TLV_CALIPSO:
     872                 :            :                         ret_val = 0;
     873                 :            :                         offset_e = offset;
     874                 :            :                         break;
     875                 :          0 :                 default:
     876         [ #  # ]:          0 :                         if (offset_e == 0)
     877                 :            :                                 offset_s = offset;
     878                 :            :                         else
     879                 :          0 :                                 goto out;
     880                 :            :                 }
     881                 :          0 :                 offset += tlv_len;
     882                 :            :         }
     883                 :            : 
     884                 :          0 : out:
     885         [ #  # ]:          0 :         if (offset_s)
     886                 :          0 :                 *start = offset_s + calipso_tlv_len(hop, offset_s);
     887                 :            :         else
     888                 :          0 :                 *start = sizeof(*hop);
     889         [ #  # ]:          0 :         if (offset_e)
     890                 :          0 :                 *end = offset_e + calipso_tlv_len(hop, offset_e);
     891                 :            :         else
     892                 :          0 :                 *end = opt_len;
     893                 :            : 
     894                 :            :         return ret_val;
     895                 :            : }
     896                 :            : 
     897                 :            : /**
     898                 :            :  * calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
     899                 :            :  * @hop: the original hop options header
     900                 :            :  * @doi_def: the CALIPSO DOI to use
     901                 :            :  * @secattr: the specific security attributes of the socket
     902                 :            :  *
     903                 :            :  * Description:
     904                 :            :  * Creates a new hop options header based on @hop with a
     905                 :            :  * CALIPSO option added to it.  If @hop already contains a CALIPSO
     906                 :            :  * option this is overwritten, otherwise the new option is appended
     907                 :            :  * after any existing options.  If @hop is NULL then the new header
     908                 :            :  * will contain just the CALIPSO option and any needed padding.
     909                 :            :  *
     910                 :            :  */
     911                 :            : static struct ipv6_opt_hdr *
     912                 :          0 : calipso_opt_insert(struct ipv6_opt_hdr *hop,
     913                 :            :                    const struct calipso_doi *doi_def,
     914                 :            :                    const struct netlbl_lsm_secattr *secattr)
     915                 :            : {
     916                 :          0 :         unsigned int start, end, buf_len, pad, hop_len;
     917                 :          0 :         struct ipv6_opt_hdr *new;
     918                 :          0 :         int ret_val;
     919                 :            : 
     920         [ #  # ]:          0 :         if (hop) {
     921                 :          0 :                 hop_len = ipv6_optlen(hop);
     922                 :          0 :                 ret_val = calipso_opt_find(hop, &start, &end);
     923         [ #  # ]:          0 :                 if (ret_val && ret_val != -ENOENT)
     924                 :          0 :                         return ERR_PTR(ret_val);
     925                 :            :         } else {
     926                 :          0 :                 hop_len = 0;
     927                 :          0 :                 start = sizeof(*hop);
     928                 :          0 :                 end = 0;
     929                 :            :         }
     930                 :            : 
     931                 :          0 :         buf_len = hop_len + start - end + CALIPSO_OPT_LEN_MAX_WITH_PAD;
     932                 :          0 :         new = kzalloc(buf_len, GFP_ATOMIC);
     933         [ #  # ]:          0 :         if (!new)
     934                 :            :                 return ERR_PTR(-ENOMEM);
     935                 :            : 
     936         [ #  # ]:          0 :         if (start > sizeof(*hop))
     937                 :          0 :                 memcpy(new, hop, start);
     938                 :          0 :         ret_val = calipso_genopt((unsigned char *)new, start, buf_len, doi_def,
     939                 :            :                                  secattr);
     940         [ #  # ]:          0 :         if (ret_val < 0) {
     941                 :          0 :                 kfree(new);
     942                 :          0 :                 return ERR_PTR(ret_val);
     943                 :            :         }
     944                 :            : 
     945                 :          0 :         buf_len = start + ret_val;
     946                 :            :         /* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
     947                 :          0 :         pad = ((buf_len & 4) + (end & 7)) & 7;
     948                 :          0 :         calipso_pad_write((unsigned char *)new, buf_len, pad);
     949                 :          0 :         buf_len += pad;
     950                 :            : 
     951         [ #  # ]:          0 :         if (end != hop_len) {
     952                 :          0 :                 memcpy((char *)new + buf_len, (char *)hop + end, hop_len - end);
     953                 :          0 :                 buf_len += hop_len - end;
     954                 :            :         }
     955                 :          0 :         new->nexthdr = 0;
     956                 :          0 :         new->hdrlen = buf_len / 8 - 1;
     957                 :            : 
     958                 :          0 :         return new;
     959                 :            : }
     960                 :            : 
     961                 :            : /**
     962                 :            :  * calipso_opt_del - Removes the CALIPSO option from an option header
     963                 :            :  * @hop: the original header
     964                 :            :  * @new: the new header
     965                 :            :  *
     966                 :            :  * Description:
     967                 :            :  * Creates a new header based on @hop without any CALIPSO option.  If @hop
     968                 :            :  * doesn't contain a CALIPSO option it returns -ENOENT.  If @hop contains
     969                 :            :  * no other non-padding options, it returns zero with @new set to NULL.
     970                 :            :  * Otherwise it returns zero, creates a new header without the CALIPSO
     971                 :            :  * option (and removing as much padding as possible) and returns with
     972                 :            :  * @new set to that header.
     973                 :            :  *
     974                 :            :  */
     975                 :          0 : static int calipso_opt_del(struct ipv6_opt_hdr *hop,
     976                 :            :                            struct ipv6_opt_hdr **new)
     977                 :            : {
     978                 :          0 :         int ret_val;
     979                 :          0 :         unsigned int start, end, delta, pad, hop_len;
     980                 :            : 
     981                 :          0 :         ret_val = calipso_opt_find(hop, &start, &end);
     982         [ #  # ]:          0 :         if (ret_val)
     983                 :            :                 return ret_val;
     984                 :            : 
     985                 :          0 :         hop_len = ipv6_optlen(hop);
     986   [ #  #  #  # ]:          0 :         if (start == sizeof(*hop) && end == hop_len) {
     987                 :            :                 /* There's no other option in the header so return NULL */
     988                 :          0 :                 *new = NULL;
     989                 :          0 :                 return 0;
     990                 :            :         }
     991                 :            : 
     992                 :          0 :         delta = (end - start) & ~7;
     993                 :          0 :         *new = kzalloc(hop_len - delta, GFP_ATOMIC);
     994         [ #  # ]:          0 :         if (!*new)
     995                 :            :                 return -ENOMEM;
     996                 :            : 
     997                 :          0 :         memcpy(*new, hop, start);
     998                 :          0 :         (*new)->hdrlen -= delta / 8;
     999                 :          0 :         pad = (end - start) & 7;
    1000                 :          0 :         calipso_pad_write((unsigned char *)*new, start, pad);
    1001         [ #  # ]:          0 :         if (end != hop_len)
    1002                 :          0 :                 memcpy((char *)*new + start + pad, (char *)hop + end,
    1003                 :          0 :                        hop_len - end);
    1004                 :            : 
    1005                 :            :         return 0;
    1006                 :            : }
    1007                 :            : 
    1008                 :            : /**
    1009                 :            :  * calipso_opt_getattr - Get the security attributes from a memory block
    1010                 :            :  * @calipso: the CALIPSO option
    1011                 :            :  * @secattr: the security attributes
    1012                 :            :  *
    1013                 :            :  * Description:
    1014                 :            :  * Inspect @calipso and return the security attributes in @secattr.
    1015                 :            :  * Returns zero on success and negative values on failure.
    1016                 :            :  *
    1017                 :            :  */
    1018                 :          0 : static int calipso_opt_getattr(const unsigned char *calipso,
    1019                 :            :                                struct netlbl_lsm_secattr *secattr)
    1020                 :            : {
    1021                 :          0 :         int ret_val = -ENOMSG;
    1022                 :          0 :         u32 doi, len = calipso[1], cat_len = calipso[6] * 4;
    1023                 :          0 :         struct calipso_doi *doi_def;
    1024                 :            : 
    1025         [ #  # ]:          0 :         if (cat_len + 8 > len)
    1026                 :            :                 return -EINVAL;
    1027                 :            : 
    1028         [ #  # ]:          0 :         if (calipso_cache_check(calipso + 2, calipso[1], secattr) == 0)
    1029                 :            :                 return 0;
    1030                 :            : 
    1031                 :          0 :         doi = get_unaligned_be32(calipso + 2);
    1032                 :          0 :         rcu_read_lock();
    1033                 :          0 :         doi_def = calipso_doi_search(doi);
    1034         [ #  # ]:          0 :         if (!doi_def)
    1035                 :          0 :                 goto getattr_return;
    1036                 :            : 
    1037                 :          0 :         secattr->attr.mls.lvl = calipso[7];
    1038                 :          0 :         secattr->flags |= NETLBL_SECATTR_MLS_LVL;
    1039                 :            : 
    1040         [ #  # ]:          0 :         if (cat_len) {
    1041                 :          0 :                 ret_val = calipso_map_cat_ntoh(doi_def,
    1042                 :            :                                                calipso + 10,
    1043                 :            :                                                cat_len,
    1044                 :            :                                                secattr);
    1045         [ #  # ]:          0 :                 if (ret_val != 0) {
    1046                 :          0 :                         netlbl_catmap_free(secattr->attr.mls.cat);
    1047                 :          0 :                         goto getattr_return;
    1048                 :            :                 }
    1049                 :            : 
    1050                 :          0 :                 secattr->flags |= NETLBL_SECATTR_MLS_CAT;
    1051                 :            :         }
    1052                 :            : 
    1053                 :          0 :         secattr->type = NETLBL_NLTYPE_CALIPSO;
    1054                 :            : 
    1055                 :          0 : getattr_return:
    1056                 :          0 :         rcu_read_unlock();
    1057                 :          0 :         return ret_val;
    1058                 :            : }
    1059                 :            : 
    1060                 :            : /* sock functions.
    1061                 :            :  */
    1062                 :            : 
    1063                 :            : /**
    1064                 :            :  * calipso_sock_getattr - Get the security attributes from a sock
    1065                 :            :  * @sk: the sock
    1066                 :            :  * @secattr: the security attributes
    1067                 :            :  *
    1068                 :            :  * Description:
    1069                 :            :  * Query @sk to see if there is a CALIPSO option attached to the sock and if
    1070                 :            :  * there is return the CALIPSO security attributes in @secattr.  This function
    1071                 :            :  * requires that @sk be locked, or privately held, but it does not do any
    1072                 :            :  * locking itself.  Returns zero on success and negative values on failure.
    1073                 :            :  *
    1074                 :            :  */
    1075                 :          0 : static int calipso_sock_getattr(struct sock *sk,
    1076                 :            :                                 struct netlbl_lsm_secattr *secattr)
    1077                 :            : {
    1078                 :          0 :         struct ipv6_opt_hdr *hop;
    1079                 :          0 :         int opt_len, len, ret_val = -ENOMSG, offset;
    1080                 :          0 :         unsigned char *opt;
    1081         [ #  # ]:          0 :         struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
    1082                 :            : 
    1083   [ #  #  #  # ]:          0 :         if (!txopts || !txopts->hopopt)
    1084                 :          0 :                 goto done;
    1085                 :            : 
    1086                 :          0 :         hop = txopts->hopopt;
    1087                 :          0 :         opt = (unsigned char *)hop;
    1088                 :          0 :         opt_len = ipv6_optlen(hop);
    1089                 :          0 :         offset = sizeof(*hop);
    1090         [ #  # ]:          0 :         while (offset < opt_len) {
    1091                 :          0 :                 len = calipso_tlv_len(hop, offset);
    1092         [ #  # ]:          0 :                 if (len < 0) {
    1093                 :          0 :                         ret_val = len;
    1094                 :          0 :                         goto done;
    1095                 :            :                 }
    1096         [ #  # ]:          0 :                 switch (opt[offset]) {
    1097                 :          0 :                 case IPV6_TLV_CALIPSO:
    1098         [ #  # ]:          0 :                         if (len < CALIPSO_HDR_LEN)
    1099                 :            :                                 ret_val = -EINVAL;
    1100                 :            :                         else
    1101                 :          0 :                                 ret_val = calipso_opt_getattr(&opt[offset],
    1102                 :            :                                                               secattr);
    1103                 :          0 :                         goto done;
    1104                 :          0 :                 default:
    1105                 :          0 :                         offset += len;
    1106                 :          0 :                         break;
    1107                 :            :                 }
    1108                 :            :         }
    1109                 :          0 : done:
    1110                 :          0 :         txopt_put(txopts);
    1111                 :          0 :         return ret_val;
    1112                 :            : }
    1113                 :            : 
    1114                 :            : /**
    1115                 :            :  * calipso_sock_setattr - Add a CALIPSO option to a socket
    1116                 :            :  * @sk: the socket
    1117                 :            :  * @doi_def: the CALIPSO DOI to use
    1118                 :            :  * @secattr: the specific security attributes of the socket
    1119                 :            :  *
    1120                 :            :  * Description:
    1121                 :            :  * Set the CALIPSO option on the given socket using the DOI definition and
    1122                 :            :  * security attributes passed to the function.  This function requires
    1123                 :            :  * exclusive access to @sk, which means it either needs to be in the
    1124                 :            :  * process of being created or locked.  Returns zero on success and negative
    1125                 :            :  * values on failure.
    1126                 :            :  *
    1127                 :            :  */
    1128                 :          0 : static int calipso_sock_setattr(struct sock *sk,
    1129                 :            :                                 const struct calipso_doi *doi_def,
    1130                 :            :                                 const struct netlbl_lsm_secattr *secattr)
    1131                 :            : {
    1132                 :          0 :         int ret_val;
    1133                 :          0 :         struct ipv6_opt_hdr *old, *new;
    1134         [ #  # ]:          0 :         struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
    1135                 :            : 
    1136                 :          0 :         old = NULL;
    1137         [ #  # ]:          0 :         if (txopts)
    1138                 :          0 :                 old = txopts->hopopt;
    1139                 :            : 
    1140                 :          0 :         new = calipso_opt_insert(old, doi_def, secattr);
    1141                 :          0 :         txopt_put(txopts);
    1142         [ #  # ]:          0 :         if (IS_ERR(new))
    1143                 :          0 :                 return PTR_ERR(new);
    1144                 :            : 
    1145                 :          0 :         ret_val = calipso_opt_update(sk, new);
    1146                 :            : 
    1147                 :          0 :         kfree(new);
    1148                 :          0 :         return ret_val;
    1149                 :            : }
    1150                 :            : 
    1151                 :            : /**
    1152                 :            :  * calipso_sock_delattr - Delete the CALIPSO option from a socket
    1153                 :            :  * @sk: the socket
    1154                 :            :  *
    1155                 :            :  * Description:
    1156                 :            :  * Removes the CALIPSO option from a socket, if present.
    1157                 :            :  *
    1158                 :            :  */
    1159                 :          0 : static void calipso_sock_delattr(struct sock *sk)
    1160                 :            : {
    1161                 :          0 :         struct ipv6_opt_hdr *new_hop;
    1162         [ #  # ]:          0 :         struct ipv6_txoptions *txopts = txopt_get(inet6_sk(sk));
    1163                 :            : 
    1164   [ #  #  #  # ]:          0 :         if (!txopts || !txopts->hopopt)
    1165                 :          0 :                 goto done;
    1166                 :            : 
    1167         [ #  # ]:          0 :         if (calipso_opt_del(txopts->hopopt, &new_hop))
    1168                 :          0 :                 goto done;
    1169                 :            : 
    1170                 :          0 :         calipso_opt_update(sk, new_hop);
    1171                 :          0 :         kfree(new_hop);
    1172                 :            : 
    1173                 :          0 : done:
    1174                 :          0 :         txopt_put(txopts);
    1175                 :          0 : }
    1176                 :            : 
    1177                 :            : /* request sock functions.
    1178                 :            :  */
    1179                 :            : 
    1180                 :            : /**
    1181                 :            :  * calipso_req_setattr - Add a CALIPSO option to a connection request socket
    1182                 :            :  * @req: the connection request socket
    1183                 :            :  * @doi_def: the CALIPSO DOI to use
    1184                 :            :  * @secattr: the specific security attributes of the socket
    1185                 :            :  *
    1186                 :            :  * Description:
    1187                 :            :  * Set the CALIPSO option on the given socket using the DOI definition and
    1188                 :            :  * security attributes passed to the function.  Returns zero on success and
    1189                 :            :  * negative values on failure.
    1190                 :            :  *
    1191                 :            :  */
    1192                 :          0 : static int calipso_req_setattr(struct request_sock *req,
    1193                 :            :                                const struct calipso_doi *doi_def,
    1194                 :            :                                const struct netlbl_lsm_secattr *secattr)
    1195                 :            : {
    1196                 :          0 :         struct ipv6_txoptions *txopts;
    1197         [ #  # ]:          0 :         struct inet_request_sock *req_inet = inet_rsk(req);
    1198                 :          0 :         struct ipv6_opt_hdr *old, *new;
    1199         [ #  # ]:          0 :         struct sock *sk = sk_to_full_sk(req_to_sk(req));
    1200                 :            : 
    1201   [ #  #  #  # ]:          0 :         if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
    1202                 :          0 :                 old = req_inet->ipv6_opt->hopopt;
    1203                 :            :         else
    1204                 :            :                 old = NULL;
    1205                 :            : 
    1206                 :          0 :         new = calipso_opt_insert(old, doi_def, secattr);
    1207         [ #  # ]:          0 :         if (IS_ERR(new))
    1208                 :          0 :                 return PTR_ERR(new);
    1209                 :            : 
    1210                 :          0 :         txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
    1211                 :            : 
    1212                 :          0 :         kfree(new);
    1213                 :            : 
    1214         [ #  # ]:          0 :         if (IS_ERR(txopts))
    1215                 :          0 :                 return PTR_ERR(txopts);
    1216                 :            : 
    1217                 :          0 :         txopts = xchg(&req_inet->ipv6_opt, txopts);
    1218         [ #  # ]:          0 :         if (txopts) {
    1219                 :          0 :                 atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
    1220                 :          0 :                 txopt_put(txopts);
    1221                 :            :         }
    1222                 :            : 
    1223                 :            :         return 0;
    1224                 :            : }
    1225                 :            : 
    1226                 :            : /**
    1227                 :            :  * calipso_req_delattr - Delete the CALIPSO option from a request socket
    1228                 :            :  * @reg: the request socket
    1229                 :            :  *
    1230                 :            :  * Description:
    1231                 :            :  * Removes the CALIPSO option from a request socket, if present.
    1232                 :            :  *
    1233                 :            :  */
    1234                 :          0 : static void calipso_req_delattr(struct request_sock *req)
    1235                 :            : {
    1236         [ #  # ]:          0 :         struct inet_request_sock *req_inet = inet_rsk(req);
    1237                 :          0 :         struct ipv6_opt_hdr *new;
    1238                 :          0 :         struct ipv6_txoptions *txopts;
    1239         [ #  # ]:          0 :         struct sock *sk = sk_to_full_sk(req_to_sk(req));
    1240                 :            : 
    1241   [ #  #  #  # ]:          0 :         if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
    1242                 :          0 :                 return;
    1243                 :            : 
    1244         [ #  # ]:          0 :         if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
    1245                 :            :                 return; /* Nothing to do */
    1246                 :            : 
    1247                 :          0 :         txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
    1248                 :            : 
    1249         [ #  # ]:          0 :         if (!IS_ERR(txopts)) {
    1250                 :          0 :                 txopts = xchg(&req_inet->ipv6_opt, txopts);
    1251         [ #  # ]:          0 :                 if (txopts) {
    1252                 :          0 :                         atomic_sub(txopts->tot_len, &sk->sk_omem_alloc);
    1253                 :          0 :                         txopt_put(txopts);
    1254                 :            :                 }
    1255                 :            :         }
    1256                 :          0 :         kfree(new);
    1257                 :            : }
    1258                 :            : 
    1259                 :            : /* skbuff functions.
    1260                 :            :  */
    1261                 :            : 
    1262                 :            : /**
    1263                 :            :  * calipso_skbuff_optptr - Find the CALIPSO option in the packet
    1264                 :            :  * @skb: the packet
    1265                 :            :  *
    1266                 :            :  * Description:
    1267                 :            :  * Parse the packet's IP header looking for a CALIPSO option.  Returns a pointer
    1268                 :            :  * to the start of the CALIPSO option on success, NULL if one if not found.
    1269                 :            :  *
    1270                 :            :  */
    1271                 :          0 : static unsigned char *calipso_skbuff_optptr(const struct sk_buff *skb)
    1272                 :            : {
    1273         [ #  # ]:          0 :         const struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);
    1274                 :          0 :         int offset;
    1275                 :            : 
    1276         [ #  # ]:          0 :         if (ip6_hdr->nexthdr != NEXTHDR_HOP)
    1277                 :            :                 return NULL;
    1278                 :            : 
    1279                 :          0 :         offset = ipv6_find_tlv(skb, sizeof(*ip6_hdr), IPV6_TLV_CALIPSO);
    1280         [ #  # ]:          0 :         if (offset >= 0)
    1281                 :          0 :                 return (unsigned char *)ip6_hdr + offset;
    1282                 :            : 
    1283                 :            :         return NULL;
    1284                 :            : }
    1285                 :            : 
    1286                 :            : /**
    1287                 :            :  * calipso_skbuff_setattr - Set the CALIPSO option on a packet
    1288                 :            :  * @skb: the packet
    1289                 :            :  * @doi_def: the CALIPSO DOI to use
    1290                 :            :  * @secattr: the security attributes
    1291                 :            :  *
    1292                 :            :  * Description:
    1293                 :            :  * Set the CALIPSO option on the given packet based on the security attributes.
    1294                 :            :  * Returns a pointer to the IP header on success and NULL on failure.
    1295                 :            :  *
    1296                 :            :  */
    1297                 :          0 : static int calipso_skbuff_setattr(struct sk_buff *skb,
    1298                 :            :                                   const struct calipso_doi *doi_def,
    1299                 :            :                                   const struct netlbl_lsm_secattr *secattr)
    1300                 :            : {
    1301                 :          0 :         int ret_val;
    1302                 :          0 :         struct ipv6hdr *ip6_hdr;
    1303                 :          0 :         struct ipv6_opt_hdr *hop;
    1304                 :          0 :         unsigned char buf[CALIPSO_MAX_BUFFER];
    1305                 :          0 :         int len_delta, new_end, pad, payload;
    1306                 :          0 :         unsigned int start, end;
    1307                 :            : 
    1308         [ #  # ]:          0 :         ip6_hdr = ipv6_hdr(skb);
    1309         [ #  # ]:          0 :         if (ip6_hdr->nexthdr == NEXTHDR_HOP) {
    1310                 :          0 :                 hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
    1311                 :          0 :                 ret_val = calipso_opt_find(hop, &start, &end);
    1312         [ #  # ]:          0 :                 if (ret_val && ret_val != -ENOENT)
    1313                 :            :                         return ret_val;
    1314                 :            :         } else {
    1315                 :          0 :                 start = 0;
    1316                 :          0 :                 end = 0;
    1317                 :            :         }
    1318                 :            : 
    1319                 :          0 :         memset(buf, 0, sizeof(buf));
    1320                 :          0 :         ret_val = calipso_genopt(buf, start & 3, sizeof(buf), doi_def, secattr);
    1321         [ #  # ]:          0 :         if (ret_val < 0)
    1322                 :            :                 return ret_val;
    1323                 :            : 
    1324                 :          0 :         new_end = start + ret_val;
    1325                 :            :         /* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */
    1326                 :          0 :         pad = ((new_end & 4) + (end & 7)) & 7;
    1327                 :          0 :         len_delta = new_end - (int)end + pad;
    1328                 :          0 :         ret_val = skb_cow(skb, skb_headroom(skb) + len_delta);
    1329         [ #  # ]:          0 :         if (ret_val < 0)
    1330                 :            :                 return ret_val;
    1331                 :            : 
    1332         [ #  # ]:          0 :         ip6_hdr = ipv6_hdr(skb); /* Reset as skb_cow() may have moved it */
    1333                 :            : 
    1334         [ #  # ]:          0 :         if (len_delta) {
    1335         [ #  # ]:          0 :                 if (len_delta > 0)
    1336                 :          0 :                         skb_push(skb, len_delta);
    1337                 :            :                 else
    1338                 :          0 :                         skb_pull(skb, -len_delta);
    1339                 :          0 :                 memmove((char *)ip6_hdr - len_delta, ip6_hdr,
    1340                 :            :                         sizeof(*ip6_hdr) + start);
    1341                 :          0 :                 skb_reset_network_header(skb);
    1342                 :          0 :                 ip6_hdr = ipv6_hdr(skb);
    1343                 :          0 :                 payload = ntohs(ip6_hdr->payload_len);
    1344                 :          0 :                 ip6_hdr->payload_len = htons(payload + len_delta);
    1345                 :            :         }
    1346                 :            : 
    1347                 :          0 :         hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
    1348         [ #  # ]:          0 :         if (start == 0) {
    1349                 :          0 :                 struct ipv6_opt_hdr *new_hop = (struct ipv6_opt_hdr *)buf;
    1350                 :            : 
    1351                 :          0 :                 new_hop->nexthdr = ip6_hdr->nexthdr;
    1352                 :          0 :                 new_hop->hdrlen = len_delta / 8 - 1;
    1353                 :          0 :                 ip6_hdr->nexthdr = NEXTHDR_HOP;
    1354                 :            :         } else {
    1355                 :          0 :                 hop->hdrlen += len_delta / 8;
    1356                 :            :         }
    1357                 :          0 :         memcpy((char *)hop + start, buf + (start & 3), new_end - start);
    1358                 :          0 :         calipso_pad_write((unsigned char *)hop, new_end, pad);
    1359                 :            : 
    1360                 :          0 :         return 0;
    1361                 :            : }
    1362                 :            : 
    1363                 :            : /**
    1364                 :            :  * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
    1365                 :            :  * @skb: the packet
    1366                 :            :  *
    1367                 :            :  * Description:
    1368                 :            :  * Removes any and all CALIPSO options from the given packet.  Returns zero on
    1369                 :            :  * success, negative values on failure.
    1370                 :            :  *
    1371                 :            :  */
    1372                 :          0 : static int calipso_skbuff_delattr(struct sk_buff *skb)
    1373                 :            : {
    1374                 :          0 :         int ret_val;
    1375                 :          0 :         struct ipv6hdr *ip6_hdr;
    1376                 :          0 :         struct ipv6_opt_hdr *old_hop;
    1377                 :          0 :         u32 old_hop_len, start = 0, end = 0, delta, size, pad;
    1378                 :            : 
    1379         [ #  # ]:          0 :         if (!calipso_skbuff_optptr(skb))
    1380                 :            :                 return 0;
    1381                 :            : 
    1382                 :            :         /* since we are changing the packet we should make a copy */
    1383                 :          0 :         ret_val = skb_cow(skb, skb_headroom(skb));
    1384         [ #  # ]:          0 :         if (ret_val < 0)
    1385                 :            :                 return ret_val;
    1386                 :            : 
    1387                 :          0 :         ip6_hdr = ipv6_hdr(skb);
    1388                 :          0 :         old_hop = (struct ipv6_opt_hdr *)(ip6_hdr + 1);
    1389                 :          0 :         old_hop_len = ipv6_optlen(old_hop);
    1390                 :            : 
    1391                 :          0 :         ret_val = calipso_opt_find(old_hop, &start, &end);
    1392         [ #  # ]:          0 :         if (ret_val)
    1393                 :            :                 return ret_val;
    1394                 :            : 
    1395   [ #  #  #  # ]:          0 :         if (start == sizeof(*old_hop) && end == old_hop_len) {
    1396                 :            :                 /* There's no other option in the header so we delete
    1397                 :            :                  * the whole thing. */
    1398                 :          0 :                 delta = old_hop_len;
    1399                 :          0 :                 size = sizeof(*ip6_hdr);
    1400                 :          0 :                 ip6_hdr->nexthdr = old_hop->nexthdr;
    1401                 :            :         } else {
    1402                 :          0 :                 delta = (end - start) & ~7;
    1403         [ #  # ]:          0 :                 if (delta)
    1404                 :          0 :                         old_hop->hdrlen -= delta / 8;
    1405                 :          0 :                 pad = (end - start) & 7;
    1406                 :          0 :                 size = sizeof(*ip6_hdr) + start + pad;
    1407                 :          0 :                 calipso_pad_write((unsigned char *)old_hop, start, pad);
    1408                 :            :         }
    1409                 :            : 
    1410         [ #  # ]:          0 :         if (delta) {
    1411                 :          0 :                 skb_pull(skb, delta);
    1412                 :          0 :                 memmove((char *)ip6_hdr + delta, ip6_hdr, size);
    1413                 :          0 :                 skb_reset_network_header(skb);
    1414                 :            :         }
    1415                 :            : 
    1416                 :            :         return 0;
    1417                 :            : }
    1418                 :            : 
    1419                 :            : static const struct netlbl_calipso_ops ops = {
    1420                 :            :         .doi_add          = calipso_doi_add,
    1421                 :            :         .doi_free         = calipso_doi_free,
    1422                 :            :         .doi_remove       = calipso_doi_remove,
    1423                 :            :         .doi_getdef       = calipso_doi_getdef,
    1424                 :            :         .doi_putdef       = calipso_doi_putdef,
    1425                 :            :         .doi_walk         = calipso_doi_walk,
    1426                 :            :         .sock_getattr     = calipso_sock_getattr,
    1427                 :            :         .sock_setattr     = calipso_sock_setattr,
    1428                 :            :         .sock_delattr     = calipso_sock_delattr,
    1429                 :            :         .req_setattr      = calipso_req_setattr,
    1430                 :            :         .req_delattr      = calipso_req_delattr,
    1431                 :            :         .opt_getattr      = calipso_opt_getattr,
    1432                 :            :         .skbuff_optptr    = calipso_skbuff_optptr,
    1433                 :            :         .skbuff_setattr   = calipso_skbuff_setattr,
    1434                 :            :         .skbuff_delattr   = calipso_skbuff_delattr,
    1435                 :            :         .cache_invalidate = calipso_cache_invalidate,
    1436                 :            :         .cache_add        = calipso_cache_add
    1437                 :            : };
    1438                 :            : 
    1439                 :            : /**
    1440                 :            :  * calipso_init - Initialize the CALIPSO module
    1441                 :            :  *
    1442                 :            :  * Description:
    1443                 :            :  * Initialize the CALIPSO module and prepare it for use.  Returns zero on
    1444                 :            :  * success and negative values on failure.
    1445                 :            :  *
    1446                 :            :  */
    1447                 :         78 : int __init calipso_init(void)
    1448                 :            : {
    1449                 :         78 :         int ret_val;
    1450                 :            : 
    1451                 :         78 :         ret_val = calipso_cache_init();
    1452         [ +  - ]:         78 :         if (!ret_val)
    1453                 :         78 :                 netlbl_calipso_ops_register(&ops);
    1454                 :         78 :         return ret_val;
    1455                 :            : }
    1456                 :            : 
    1457                 :          0 : void calipso_exit(void)
    1458                 :            : {
    1459                 :          0 :         netlbl_calipso_ops_register(NULL);
    1460                 :          0 :         calipso_cache_invalidate();
    1461                 :          0 :         kfree(calipso_cache);
    1462                 :          0 : }

Generated by: LCOV version 1.14