brintos

brintos / linux-shallow public Read only

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