File Index
Files and directories
Sign in
FILE

pkey_base.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/crypto/pkey_base.c C
  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
 19MODULE_LICENSE("GPL");
 20MODULE_AUTHOR("IBM Corporation");
 21MODULE_DESCRIPTION("s390 protected key base and api");
 22
 23/*
 24 * pkey debug feature
 25 */
 26debug_info_t *pkey_dbf_info;
 27EXPORT_SYMBOL(pkey_dbf_info);
 28
 29/*
 30 * pkey handler registry
 31 */
 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				u32 xflags)
155{
156	const struct pkey_handler *h;
157	int rc = -ENODEV;
158
159	h = pkey_handler_get_keybased(key, keylen);
160	if (h && h->key_to_protkey) {
161		rc = h->key_to_protkey(apqns, nr_apqns, key, keylen,
162				       protkey, protkeylen,
163				       protkeytype, xflags);
164	}
165	pkey_handler_put(h);
166
167	return rc;
168}
169EXPORT_SYMBOL(pkey_handler_key_to_protkey);
170
171/*
172 * This handler invocation is special as there may be more than
173 * one handler providing support for the very same key (type).
174 * And the handler may not respond true on is_supported_key(),
175 * so simple try and check return value here.
176 */
177int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
178					 size_t nr_apqns,
179					 const u8 *key, u32 keylen,
180					 u8 *protkey, u32 *protkeylen,
181					 u32 *protkeytype, u32 xflags)
182{
183	const struct pkey_handler *h, *htmp[10];
184	int i, n = 0, rc = -ENODEV;
185
186	rcu_read_lock();
187	list_for_each_entry_rcu(h, &handler_list, list) {
188		if (!try_module_get(h->module))
189			continue;
190		if (h->slowpath_key_to_protkey && n < ARRAY_SIZE(htmp))
191			htmp[n++] = h;
192		else
193			module_put(h->module);
194	}
195	rcu_read_unlock();
196
197	for (i = 0; i < n; i++) {
198		h = htmp[i];
199		if (rc)
200			rc = h->slowpath_key_to_protkey(apqns, nr_apqns,
201							key, keylen,
202							protkey, protkeylen,
203							protkeytype, xflags);
204		module_put(h->module);
205	}
206
207	return rc;
208}
209EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey);
210
211int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
212			 u32 keytype, u32 keysubtype,
213			 u32 keybitsize, u32 flags,
214			 u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags)
215{
216	const struct pkey_handler *h;
217	int rc = -ENODEV;
218
219	h = pkey_handler_get_keytypebased(keysubtype);
220	if (h && h->gen_key) {
221		rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype,
222				keybitsize, flags,
223				keybuf, keybuflen, keyinfo, xflags);
224	}
225	pkey_handler_put(h);
226
227	return rc;
228}
229EXPORT_SYMBOL(pkey_handler_gen_key);
230
231int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
232			    u32 keytype, u32 keysubtype,
233			    u32 keybitsize, u32 flags,
234			    const u8 *clrkey, u32 clrkeylen,
235			    u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
236			    u32 xflags)
237{
238	const struct pkey_handler *h;
239	int rc = -ENODEV;
240
241	h = pkey_handler_get_keytypebased(keysubtype);
242	if (h && h->clr_to_key) {
243		rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype,
244				   keybitsize, flags, clrkey, clrkeylen,
245				   keybuf, keybuflen, keyinfo, xflags);
246	}
247	pkey_handler_put(h);
248
249	return rc;
250}
251EXPORT_SYMBOL(pkey_handler_clr_to_key);
252
253int pkey_handler_verify_key(const u8 *key, u32 keylen,
254			    u16 *card, u16 *dom,
255			    u32 *keytype, u32 *keybitsize, u32 *flags,
256			    u32 xflags)
257{
258	const struct pkey_handler *h;
259	int rc = -ENODEV;
260
261	h = pkey_handler_get_keybased(key, keylen);
262	if (h && h->verify_key) {
263		rc = h->verify_key(key, keylen, card, dom,
264				   keytype, keybitsize, flags, xflags);
265	}
266	pkey_handler_put(h);
267
268	return rc;
269}
270EXPORT_SYMBOL(pkey_handler_verify_key);
271
272int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags,
273			       struct pkey_apqn *apqns, size_t *nr_apqns,
274			       u32 xflags)
275{
276	const struct pkey_handler *h;
277	int rc = -ENODEV;
278
279	h = pkey_handler_get_keybased(key, keylen);
280	if (h && h->apqns_for_key)
281		rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns,
282				      xflags);
283	pkey_handler_put(h);
284
285	return rc;
286}
287EXPORT_SYMBOL(pkey_handler_apqns_for_key);
288
289int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,
290				   u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
291				   struct pkey_apqn *apqns, size_t *nr_apqns,
292				   u32 xflags)
293{
294	const struct pkey_handler *h;
295	int rc = -ENODEV;
296
297	h = pkey_handler_get_keytypebased(keysubtype);
298	if (h && h->apqns_for_keytype) {
299		rc = h->apqns_for_keytype(keysubtype,
300					  cur_mkvp, alt_mkvp, flags,
301					  apqns, nr_apqns, xflags);
302	}
303	pkey_handler_put(h);
304
305	return rc;
306}
307EXPORT_SYMBOL(pkey_handler_apqns_for_keytype);
308
309void pkey_handler_request_modules(void)
310{
311#ifdef CONFIG_MODULES
312	static const char * const pkey_handler_modules[] = {
313#if IS_MODULE(CONFIG_PKEY_CCA)
314		"pkey_cca",
315#endif
316#if IS_MODULE(CONFIG_PKEY_EP11)
317		"pkey_ep11",
318#endif
319#if IS_MODULE(CONFIG_PKEY_PCKMO)
320		"pkey_pckmo",
321#endif
322#if IS_MODULE(CONFIG_PKEY_UV)
323		"pkey_uv",
324#endif
325	};
326	int i;
327
328	for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) {
329		const struct pkey_handler *h;
330		bool found = false;
331
332		rcu_read_lock();
333		list_for_each_entry_rcu(h, &handler_list, list) {
334			if (h->module &&
335			    !strcmp(h->module->name, pkey_handler_modules[i])) {
336				found = true;
337				break;
338			}
339		}
340		rcu_read_unlock();
341		if (!found) {
342			pr_debug("request_module(%s)\n", pkey_handler_modules[i]);
343			request_module(pkey_handler_modules[i]);
344		}
345	}
346#endif
347}
348EXPORT_SYMBOL(pkey_handler_request_modules);
349
350/*
351 * Module init
352 */
353static int __init pkey_init(void)
354{
355	int rc;
356
357	/* init debug feature */
358	pkey_dbf_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
359	debug_register_view(pkey_dbf_info, &debug_sprintf_view);
360	debug_set_level(pkey_dbf_info, 4);
361
362	/* the handler registry does not need any init */
363
364	rc = pkey_api_init();
365	if (rc)
366		debug_unregister(pkey_dbf_info);
367
368	return rc;
369}
370
371/*
372 * Module exit
373 */
374static void __exit pkey_exit(void)
375{
376	pkey_api_exit();
377}
378
379module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_init);
380module_exit(pkey_exit);
~/ Read-only file preview.