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