1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * pkey base: debug feature, pkey handler registry 4 * 5 * Copyright IBM Corp. 2024 6 */ 7 8 #define pr_fmt(fmt) "pkey: " fmt 9 10 #include <linux/cpufeature.h> 11 #include <linux/export.h> 12 #include <linux/init.h> 13 #include <linux/list.h> 14 #include <linux/module.h> 15 #include <linux/rculist.h> 16 17 #include "pkey_base.h" 18 19 MODULE_LICENSE("GPL"); 20 MODULE_AUTHOR("IBM Corporation"); 21 MODULE_DESCRIPTION("s390 protected key base and api"); 22 23 /* 24 * pkey debug feature 25 */ 26 debug_info_t *pkey_dbf_info; 27 EXPORT_SYMBOL(pkey_dbf_info); 28 29 /* 30 * pkey handler registry 31 */ 32 33 static DEFINE_SPINLOCK(handler_list_write_lock); 34 static LIST_HEAD(handler_list); 35 36 int pkey_handler_register(struct pkey_handler *handler) 37 { 38 const struct pkey_handler *h; 39 40 if (!handler || 41 !handler->is_supported_key || 42 !handler->is_supported_keytype) 43 return -EINVAL; 44 45 if (!try_module_get(handler->module)) 46 return -ENXIO; 47 48 spin_lock(&handler_list_write_lock); 49 50 rcu_read_lock(); 51 list_for_each_entry_rcu(h, &handler_list, list) { 52 if (h == handler) { 53 rcu_read_unlock(); 54 spin_unlock(&handler_list_write_lock); 55 module_put(handler->module); 56 return -EEXIST; 57 } 58 } 59 rcu_read_unlock(); 60 61 list_add_rcu(&handler->list, &handler_list); 62 spin_unlock(&handler_list_write_lock); 63 /* 64 * Fast path to push the info about the updated list to the other 65 * CPUs. If removed, the other CPUs may get the updated list when the 66 * RCU context is synched. As this code is in general not performance 67 * critical and the list update mostly only occurs at the early time in 68 * system startup the focus is on concurrency versus performance. 69 */ 70 synchronize_rcu(); 71 72 module_put(handler->module); 73 74 PKEY_DBF_INFO("%s pkey handler '%s' registered\n", __func__, 75 handler->name ?: "<no name>"); 76 77 return 0; 78 } 79 EXPORT_SYMBOL(pkey_handler_register); 80 81 int pkey_handler_unregister(struct pkey_handler *handler) 82 { 83 spin_lock(&handler_list_write_lock); 84 list_del_rcu(&handler->list); 85 INIT_LIST_HEAD_RCU(&handler->list); 86 spin_unlock(&handler_list_write_lock); 87 synchronize_rcu(); 88 89 PKEY_DBF_INFO("%s pkey handler '%s' unregistered\n", __func__, 90 handler->name ?: "<no name>"); 91 92 return 0; 93 } 94 EXPORT_SYMBOL(pkey_handler_unregister); 95 96 /* 97 * Handler invocation functions. 98 */ 99 100 const struct pkey_handler *pkey_handler_get_keybased(const u8 *key, u32 keylen) 101 { 102 const struct pkey_handler *h; 103 104 rcu_read_lock(); 105 list_for_each_entry_rcu(h, &handler_list, list) { 106 if (!try_module_get(h->module)) 107 continue; 108 if (h->is_supported_key(key, keylen)) { 109 rcu_read_unlock(); 110 return h; 111 } 112 module_put(h->module); 113 } 114 rcu_read_unlock(); 115 116 return NULL; 117 } 118 EXPORT_SYMBOL(pkey_handler_get_keybased); 119 120 const struct pkey_handler *pkey_handler_get_keytypebased(enum pkey_key_type kt) 121 { 122 const struct pkey_handler *h; 123 124 rcu_read_lock(); 125 list_for_each_entry_rcu(h, &handler_list, list) { 126 if (!try_module_get(h->module)) 127 continue; 128 if (h->is_supported_keytype(kt)) { 129 rcu_read_unlock(); 130 return h; 131 } 132 module_put(h->module); 133 } 134 rcu_read_unlock(); 135 136 return NULL; 137 } 138 EXPORT_SYMBOL(pkey_handler_get_keytypebased); 139 140 void pkey_handler_put(const struct pkey_handler *handler) 141 { 142 const struct pkey_handler *h; 143 144 if (!handler) 145 return; 146 147 rcu_read_lock(); 148 list_for_each_entry_rcu(h, &handler_list, list) { 149 if (h == handler) { 150 module_put(h->module); 151 break; 152 } 153 } 154 rcu_read_unlock(); 155 } 156 EXPORT_SYMBOL(pkey_handler_put); 157 158 int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns, 159 const u8 *key, u32 keylen, 160 u8 *protkey, u32 *protkeylen, u32 *protkeytype, 161 u32 xflags) 162 { 163 const struct pkey_handler *h; 164 int rc = -ENODEV; 165 166 h = pkey_handler_get_keybased(key, keylen); 167 if (h && h->key_to_protkey) { 168 rc = h->key_to_protkey(apqns, nr_apqns, key, keylen, 169 protkey, protkeylen, 170 protkeytype, xflags); 171 } 172 pkey_handler_put(h); 173 174 return rc; 175 } 176 EXPORT_SYMBOL(pkey_handler_key_to_protkey); 177 178 /* 179 * This handler invocation is special as there may be more than 180 * one handler providing support for the very same key (type). 181 * And the handler may not respond true on is_supported_key(), 182 * so simple try and check return value here. 183 */ 184 int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns, 185 size_t nr_apqns, 186 const u8 *key, u32 keylen, 187 u8 *protkey, u32 *protkeylen, 188 u32 *protkeytype, u32 xflags) 189 { 190 const struct pkey_handler *h, *htmp[10]; 191 int i, n = 0, rc = -ENODEV; 192 193 rcu_read_lock(); 194 list_for_each_entry_rcu(h, &handler_list, list) { 195 if (!try_module_get(h->module)) 196 continue; 197 if (h->slowpath_key_to_protkey && n < ARRAY_SIZE(htmp)) 198 htmp[n++] = h; 199 else 200 module_put(h->module); 201 } 202 rcu_read_unlock(); 203 204 for (i = 0; i < n; i++) { 205 h = htmp[i]; 206 if (rc) 207 rc = h->slowpath_key_to_protkey(apqns, nr_apqns, 208 key, keylen, 209 protkey, protkeylen, 210 protkeytype, xflags); 211 module_put(h->module); 212 } 213 214 return rc; 215 } 216 EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey); 217 218 int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns, 219 u32 keytype, u32 keysubtype, 220 u32 keybitsize, u32 flags, 221 u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags) 222 { 223 const struct pkey_handler *h; 224 int rc = -ENODEV; 225 226 h = pkey_handler_get_keytypebased(keysubtype); 227 if (h && h->gen_key) { 228 rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype, 229 keybitsize, flags, 230 keybuf, keybuflen, keyinfo, xflags); 231 } 232 pkey_handler_put(h); 233 234 return rc; 235 } 236 EXPORT_SYMBOL(pkey_handler_gen_key); 237 238 int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns, 239 u32 keytype, u32 keysubtype, 240 u32 keybitsize, u32 flags, 241 const u8 *clrkey, u32 clrkeylen, 242 u8 *keybuf, u32 *keybuflen, u32 *keyinfo, 243 u32 xflags) 244 { 245 const struct pkey_handler *h; 246 int rc = -ENODEV; 247 248 h = pkey_handler_get_keytypebased(keysubtype); 249 if (h && h->clr_to_key) { 250 rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype, 251 keybitsize, flags, clrkey, clrkeylen, 252 keybuf, keybuflen, keyinfo, xflags); 253 } 254 pkey_handler_put(h); 255 256 return rc; 257 } 258 EXPORT_SYMBOL(pkey_handler_clr_to_key); 259 260 int pkey_handler_verify_key(const u8 *key, u32 keylen, 261 u16 *card, u16 *dom, 262 u32 *keytype, u32 *keybitsize, u32 *flags, 263 u32 xflags) 264 { 265 const struct pkey_handler *h; 266 int rc = -ENODEV; 267 268 h = pkey_handler_get_keybased(key, keylen); 269 if (h && h->verify_key) { 270 rc = h->verify_key(key, keylen, card, dom, 271 keytype, keybitsize, flags, xflags); 272 } 273 pkey_handler_put(h); 274 275 return rc; 276 } 277 EXPORT_SYMBOL(pkey_handler_verify_key); 278 279 int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags, 280 struct pkey_apqn *apqns, size_t *nr_apqns, 281 u32 xflags) 282 { 283 const struct pkey_handler *h; 284 int rc = -ENODEV; 285 286 h = pkey_handler_get_keybased(key, keylen); 287 if (h && h->apqns_for_key) 288 rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns, 289 xflags); 290 pkey_handler_put(h); 291 292 return rc; 293 } 294 EXPORT_SYMBOL(pkey_handler_apqns_for_key); 295 296 int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype, 297 u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, 298 struct pkey_apqn *apqns, size_t *nr_apqns, 299 u32 xflags) 300 { 301 const struct pkey_handler *h; 302 int rc = -ENODEV; 303 304 h = pkey_handler_get_keytypebased(keysubtype); 305 if (h && h->apqns_for_keytype) { 306 rc = h->apqns_for_keytype(keysubtype, 307 cur_mkvp, alt_mkvp, flags, 308 apqns, nr_apqns, xflags); 309 } 310 pkey_handler_put(h); 311 312 return rc; 313 } 314 EXPORT_SYMBOL(pkey_handler_apqns_for_keytype); 315 316 void pkey_handler_request_modules(void) 317 { 318 #ifdef CONFIG_MODULES 319 static const char * const pkey_handler_modules[] = { 320 #if IS_MODULE(CONFIG_PKEY_CCA) 321 "pkey_cca", 322 #endif 323 #if IS_MODULE(CONFIG_PKEY_EP11) 324 "pkey_ep11", 325 #endif 326 #if IS_MODULE(CONFIG_PKEY_PCKMO) 327 "pkey_pckmo", 328 #endif 329 #if IS_MODULE(CONFIG_PKEY_UV) 330 "pkey_uv", 331 #endif 332 }; 333 int i; 334 335 for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) { 336 const struct pkey_handler *h; 337 bool found = false; 338 339 rcu_read_lock(); 340 list_for_each_entry_rcu(h, &handler_list, list) { 341 if (h->module && 342 !strcmp(h->module->name, pkey_handler_modules[i])) { 343 found = true; 344 break; 345 } 346 } 347 rcu_read_unlock(); 348 if (!found) { 349 pr_debug("request_module(%s)\n", pkey_handler_modules[i]); 350 request_module(pkey_handler_modules[i]); 351 } 352 } 353 #endif 354 } 355 EXPORT_SYMBOL(pkey_handler_request_modules); 356 357 /* 358 * Module init 359 */ 360 static int __init pkey_init(void) 361 { 362 int rc; 363 364 /* init debug feature */ 365 pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long)); 366 debug_register_view(pkey_dbf_info, &debug_sprintf_view); 367 debug_set_level(pkey_dbf_info, 4); 368 369 /* the handler registry does not need any init */ 370 371 rc = pkey_api_init(); 372 if (rc) 373 debug_unregister(pkey_dbf_info); 374 375 return rc; 376 } 377 378 /* 379 * Module exit 380 */ 381 static void __exit pkey_exit(void) 382 { 383 pkey_api_exit(); 384 } 385 386 module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init); 387 module_exit(pkey_exit); 388