Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc2 381 lines 8.6 kB view raw
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 20MODULE_LICENSE("GPL"); 21MODULE_AUTHOR("IBM Corporation"); 22MODULE_DESCRIPTION("s390 protected key base and api"); 23 24/* 25 * pkey debug feature 26 */ 27debug_info_t *pkey_dbf_info; 28EXPORT_SYMBOL(pkey_dbf_info); 29 30/* 31 * pkey handler registry 32 */ 33 34static DEFINE_SPINLOCK(handler_list_write_lock); 35static LIST_HEAD(handler_list); 36 37int 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} 73EXPORT_SYMBOL(pkey_handler_register); 74 75int 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} 88EXPORT_SYMBOL(pkey_handler_unregister); 89 90/* 91 * Handler invocation functions. 92 */ 93 94const 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} 112EXPORT_SYMBOL(pkey_handler_get_keybased); 113 114const 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} 132EXPORT_SYMBOL(pkey_handler_get_keytypebased); 133 134void 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} 150EXPORT_SYMBOL(pkey_handler_put); 151 152int 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} 170EXPORT_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 */ 178int 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} 210EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey); 211 212int 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} 230EXPORT_SYMBOL(pkey_handler_gen_key); 231 232int 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} 252EXPORT_SYMBOL(pkey_handler_clr_to_key); 253 254int 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} 271EXPORT_SYMBOL(pkey_handler_verify_key); 272 273int 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} 288EXPORT_SYMBOL(pkey_handler_apqns_for_key); 289 290int 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} 308EXPORT_SYMBOL(pkey_handler_apqns_for_keytype); 309 310void 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} 349EXPORT_SYMBOL(pkey_handler_request_modules); 350 351/* 352 * Module init 353 */ 354static 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 */ 375static void __exit pkey_exit(void) 376{ 377 pkey_api_exit(); 378} 379 380module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init); 381module_exit(pkey_exit);