0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/types.h>
0022 #include <linux/rcupdate.h>
0023 #include <linux/list.h>
0024 #include <linux/spinlock.h>
0025
0026 #include "ibpkey.h"
0027 #include "objsec.h"
0028
0029 #define SEL_PKEY_HASH_SIZE 256
0030 #define SEL_PKEY_HASH_BKT_LIMIT 16
0031
0032 struct sel_ib_pkey_bkt {
0033 int size;
0034 struct list_head list;
0035 };
0036
0037 struct sel_ib_pkey {
0038 struct pkey_security_struct psec;
0039 struct list_head list;
0040 struct rcu_head rcu;
0041 };
0042
0043 static DEFINE_SPINLOCK(sel_ib_pkey_lock);
0044 static struct sel_ib_pkey_bkt sel_ib_pkey_hash[SEL_PKEY_HASH_SIZE];
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 static unsigned int sel_ib_pkey_hashfn(u16 pkey)
0056 {
0057 return (pkey & (SEL_PKEY_HASH_SIZE - 1));
0058 }
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 static struct sel_ib_pkey *sel_ib_pkey_find(u64 subnet_prefix, u16 pkey_num)
0071 {
0072 unsigned int idx;
0073 struct sel_ib_pkey *pkey;
0074
0075 idx = sel_ib_pkey_hashfn(pkey_num);
0076 list_for_each_entry_rcu(pkey, &sel_ib_pkey_hash[idx].list, list) {
0077 if (pkey->psec.pkey == pkey_num &&
0078 pkey->psec.subnet_prefix == subnet_prefix)
0079 return pkey;
0080 }
0081
0082 return NULL;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 static void sel_ib_pkey_insert(struct sel_ib_pkey *pkey)
0094 {
0095 unsigned int idx;
0096
0097
0098
0099
0100 idx = sel_ib_pkey_hashfn(pkey->psec.pkey);
0101 list_add_rcu(&pkey->list, &sel_ib_pkey_hash[idx].list);
0102 if (sel_ib_pkey_hash[idx].size == SEL_PKEY_HASH_BKT_LIMIT) {
0103 struct sel_ib_pkey *tail;
0104
0105 tail = list_entry(
0106 rcu_dereference_protected(
0107 list_tail_rcu(&sel_ib_pkey_hash[idx].list),
0108 lockdep_is_held(&sel_ib_pkey_lock)),
0109 struct sel_ib_pkey, list);
0110 list_del_rcu(&tail->list);
0111 kfree_rcu(tail, rcu);
0112 } else {
0113 sel_ib_pkey_hash[idx].size++;
0114 }
0115 }
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
0130 {
0131 int ret;
0132 struct sel_ib_pkey *pkey;
0133 struct sel_ib_pkey *new = NULL;
0134 unsigned long flags;
0135
0136 spin_lock_irqsave(&sel_ib_pkey_lock, flags);
0137 pkey = sel_ib_pkey_find(subnet_prefix, pkey_num);
0138 if (pkey) {
0139 *sid = pkey->psec.sid;
0140 spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
0141 return 0;
0142 }
0143
0144 ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
0145 sid);
0146 if (ret)
0147 goto out;
0148
0149
0150
0151
0152 new = kzalloc(sizeof(*new), GFP_ATOMIC);
0153 if (!new) {
0154 ret = -ENOMEM;
0155 goto out;
0156 }
0157
0158 new->psec.subnet_prefix = subnet_prefix;
0159 new->psec.pkey = pkey_num;
0160 new->psec.sid = *sid;
0161 sel_ib_pkey_insert(new);
0162
0163 out:
0164 spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
0165 return ret;
0166 }
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *sid)
0182 {
0183 struct sel_ib_pkey *pkey;
0184
0185 rcu_read_lock();
0186 pkey = sel_ib_pkey_find(subnet_prefix, pkey_num);
0187 if (pkey) {
0188 *sid = pkey->psec.sid;
0189 rcu_read_unlock();
0190 return 0;
0191 }
0192 rcu_read_unlock();
0193
0194 return sel_ib_pkey_sid_slow(subnet_prefix, pkey_num, sid);
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204 void sel_ib_pkey_flush(void)
0205 {
0206 unsigned int idx;
0207 struct sel_ib_pkey *pkey, *pkey_tmp;
0208 unsigned long flags;
0209
0210 spin_lock_irqsave(&sel_ib_pkey_lock, flags);
0211 for (idx = 0; idx < SEL_PKEY_HASH_SIZE; idx++) {
0212 list_for_each_entry_safe(pkey, pkey_tmp,
0213 &sel_ib_pkey_hash[idx].list, list) {
0214 list_del_rcu(&pkey->list);
0215 kfree_rcu(pkey, rcu);
0216 }
0217 sel_ib_pkey_hash[idx].size = 0;
0218 }
0219 spin_unlock_irqrestore(&sel_ib_pkey_lock, flags);
0220 }
0221
0222 static __init int sel_ib_pkey_init(void)
0223 {
0224 int iter;
0225
0226 if (!selinux_enabled_boot)
0227 return 0;
0228
0229 for (iter = 0; iter < SEL_PKEY_HASH_SIZE; iter++) {
0230 INIT_LIST_HEAD(&sel_ib_pkey_hash[iter].list);
0231 sel_ib_pkey_hash[iter].size = 0;
0232 }
0233
0234 return 0;
0235 }
0236
0237 subsys_initcall(sel_ib_pkey_init);