root/security/selinux/ibpkey.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sel_ib_pkey_hashfn
  2. sel_ib_pkey_find
  3. sel_ib_pkey_insert
  4. sel_ib_pkey_sid_slow
  5. sel_ib_pkey_sid
  6. sel_ib_pkey_flush
  7. sel_ib_pkey_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Pkey table
   4  *
   5  * SELinux must keep a mapping of Infinband PKEYs to labels/SIDs.  This
   6  * mapping is maintained as part of the normal policy but a fast cache is
   7  * needed to reduce the lookup overhead.
   8  *
   9  * This code is heavily based on the "netif" and "netport" concept originally
  10  * developed by
  11  * James Morris <jmorris@redhat.com> and
  12  * Paul Moore <paul@paul-moore.com>
  13  *   (see security/selinux/netif.c and security/selinux/netport.c for more
  14  *   information)
  15  */
  16 
  17 /*
  18  * (c) Mellanox Technologies, 2016
  19  */
  20 
  21 #include <linux/types.h>
  22 #include <linux/rcupdate.h>
  23 #include <linux/list.h>
  24 #include <linux/spinlock.h>
  25 
  26 #include "ibpkey.h"
  27 #include "objsec.h"
  28 
  29 #define SEL_PKEY_HASH_SIZE       256
  30 #define SEL_PKEY_HASH_BKT_LIMIT   16
  31 
  32 struct sel_ib_pkey_bkt {
  33         int size;
  34         struct list_head list;
  35 };
  36 
  37 struct sel_ib_pkey {
  38         struct pkey_security_struct psec;
  39         struct list_head list;
  40         struct rcu_head rcu;
  41 };
  42 
  43 static LIST_HEAD(sel_ib_pkey_list);
  44 static DEFINE_SPINLOCK(sel_ib_pkey_lock);
  45 static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE];
  46 
  47 /**
  48  * sel_ib_pkey_hashfn - Hashing function for the pkey table
  49  * @pkey: pkey number
  50  *
  51  * Description:
  52  * This is the hashing function for the pkey table, it returns the bucket
  53  * number for the given pkey.
  54  *
  55  */
  56 static unsigned int sel_ib_pkey_hashfn(u16 pkey)
  57 {
  58         return (pkey & (SEL_PKEY_HASH_SIZE - 1));
  59 }
  60 
  61 /**
  62  * sel_ib_pkey_find - Search for a pkey record
  63  * @subnet_prefix: subnet_prefix
  64  * @pkey_num: pkey_num
  65  *
  66  * Description:
  67  * Search the pkey table and return the matching record.  If an entry
  68  * can not be found in the table return NULL.
  69  *
  70  */
  71 static struct sel_ib_pkey *sel_ib_pkey_find(u64 subnet_prefix, u16 pkey_num)
  72 {
  73         unsigned int idx;
  74         struct sel_ib_pkey *pkey;
  75 
  76         idx = sel_ib_pkey_hashfn(pkey_num);
  77         list_for_each_entry_rcu(pkey, &sel_ib_pkey_hash[idx].list, list) {
  78                 if (pkey->psec.pkey == pkey_num &&
  79                     pkey->psec.subnet_prefix == subnet_prefix)
  80                         return pkey;
  81         }
  82 
  83         return NULL;
  84 }
  85 
  86 /**
  87  * sel_ib_pkey_insert - Insert a new pkey into the table
  88  * @pkey: the new pkey record
  89  *
  90  * Description:
  91  * Add a new pkey record to the hash table.
  92  *
  93  */
  94 static void sel_ib_pkey_insert(struct sel_ib_pkey *pkey)
  95 {
  96         unsigned int idx;
  97 
  98         /* we need to impose a limit on the growth of the hash table so check
  99          * this bucket to make sure it is within the specified bounds
 100          */
 101         idx = sel_ib_pkey_hashfn(pkey->psec.pkey);
 102         list_add_rcu(&pkey->list, &sel_ib_pkey_hash[idx].list);
 103         if (sel_ib_pkey_hash[idx].size == SEL_PKEY_HASH_BKT_LIMIT) {
 104                 struct sel_ib_pkey *tail;
 105 
 106                 tail = list_entry(
 107                         rcu_dereference_protected(
 108                                 sel_ib_pkey_hash[idx].list.prev,
 109                                 lockdep_is_held(&sel_ib_pkey_lock)),
 110                         struct sel_ib_pkey, list);
 111                 list_del_rcu(&tail->list);
 112                 kfree_rcu(tail, rcu);
 113         } else {
 114                 sel_ib_pkey_hash[idx].size++;
 115         }
 116 }
 117 
 118 /**
 119  * sel_ib_pkey_sid_slow - Lookup the SID of a pkey using the policy
 120  * @subnet_prefix: subnet prefix
 121  * @pkey_num: pkey number
 122  * @sid: pkey SID
 123  *
 124  * Description:
 125  * This function determines the SID of a pkey by querying the security
 126  * policy.  The result is added to the pkey table to speedup future
 127  * queries.  Returns zero on success, negative values on failure.
 128  *
 129  */
 130 static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
 131 {
 132         int ret;
 133         struct sel_ib_pkey *pkey;
 134         struct sel_ib_pkey *new = NULL;
 135         unsigned long flags;
 136 
 137         spin_lock_irqsave(&sel_ib_pkey_lock, flags);
 138         pkey = sel_ib_pkey_find(subnet_prefix, pkey_num);
 139         if (pkey) {
 140                 *sid = pkey->psec.sid;
 141                 spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
 142                 return 0;
 143         }
 144 
 145         ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
 146                                    sid);
 147         if (ret)
 148                 goto out;
 149 
 150         /* If this memory allocation fails still return 0. The SID
 151          * is valid, it just won't be added to the cache.
 152          */
 153         new = kzalloc(sizeof(*new), GFP_ATOMIC);
 154         if (!new)
 155                 goto out;
 156 
 157         new->psec.subnet_prefix = subnet_prefix;
 158         new->psec.pkey = pkey_num;
 159         new->psec.sid = *sid;
 160         sel_ib_pkey_insert(new);
 161 
 162 out:
 163         spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
 164         return ret;
 165 }
 166 
 167 /**
 168  * sel_ib_pkey_sid - Lookup the SID of a PKEY
 169  * @subnet_prefix: subnet_prefix
 170  * @pkey_num: pkey number
 171  * @sid: pkey SID
 172  *
 173  * Description:
 174  * This function determines the SID of a PKEY using the fastest method
 175  * possible.  First the pkey table is queried, but if an entry can't be found
 176  * then the policy is queried and the result is added to the table to speedup
 177  * future queries.  Returns zero on success, negative values on failure.
 178  *
 179  */
 180 int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *sid)
 181 {
 182         struct sel_ib_pkey *pkey;
 183 
 184         rcu_read_lock();
 185         pkey = sel_ib_pkey_find(subnet_prefix, pkey_num);
 186         if (pkey) {
 187                 *sid = pkey->psec.sid;
 188                 rcu_read_unlock();
 189                 return 0;
 190         }
 191         rcu_read_unlock();
 192 
 193         return sel_ib_pkey_sid_slow(subnet_prefix, pkey_num, sid);
 194 }
 195 
 196 /**
 197  * sel_ib_pkey_flush - Flush the entire pkey table
 198  *
 199  * Description:
 200  * Remove all entries from the pkey table
 201  *
 202  */
 203 void sel_ib_pkey_flush(void)
 204 {
 205         unsigned int idx;
 206         struct sel_ib_pkey *pkey, *pkey_tmp;
 207         unsigned long flags;
 208 
 209         spin_lock_irqsave(&sel_ib_pkey_lock, flags);
 210         for (idx = 0; idx < SEL_PKEY_HASH_SIZE; idx++) {
 211                 list_for_each_entry_safe(pkey, pkey_tmp,
 212                                          &sel_ib_pkey_hash[idx].list, list) {
 213                         list_del_rcu(&pkey->list);
 214                         kfree_rcu(pkey, rcu);
 215                 }
 216                 sel_ib_pkey_hash[idx].size = 0;
 217         }
 218         spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
 219 }
 220 
 221 static __init int sel_ib_pkey_init(void)
 222 {
 223         int iter;
 224 
 225         if (!selinux_enabled)
 226                 return 0;
 227 
 228         for (iter = 0; iter < SEL_PKEY_HASH_SIZE; iter++) {
 229                 INIT_LIST_HEAD(&sel_ib_pkey_hash[iter].list);
 230                 sel_ib_pkey_hash[iter].size = 0;
 231         }
 232 
 233         return 0;
 234 }
 235 
 236 subsys_initcall(sel_ib_pkey_init);

/* [<][>][^][v][top][bottom][index][help] */