xref: /linux/drivers/s390/crypto/pkey_base.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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 
pkey_handler_register(struct pkey_handler * handler)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 
pkey_handler_unregister(struct pkey_handler * handler)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 
pkey_handler_get_keybased(const u8 * key,u32 keylen)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 
pkey_handler_get_keytypebased(enum pkey_key_type kt)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 
pkey_handler_put(const struct pkey_handler * handler)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 
pkey_handler_key_to_protkey(const struct pkey_apqn * apqns,size_t nr_apqns,const u8 * key,u32 keylen,u8 * protkey,u32 * protkeylen,u32 * protkeytype,u32 xflags)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  */
pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn * apqns,size_t nr_apqns,const u8 * key,u32 keylen,u8 * protkey,u32 * protkeylen,u32 * protkeytype,u32 xflags)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 
pkey_handler_gen_key(const struct pkey_apqn * apqns,size_t nr_apqns,u32 keytype,u32 keysubtype,u32 keybitsize,u32 flags,u8 * keybuf,u32 * keybuflen,u32 * keyinfo,u32 xflags)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 
pkey_handler_clr_to_key(const struct pkey_apqn * apqns,size_t nr_apqns,u32 keytype,u32 keysubtype,u32 keybitsize,u32 flags,const u8 * clrkey,u32 clrkeylen,u8 * keybuf,u32 * keybuflen,u32 * keyinfo,u32 xflags)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 
pkey_handler_verify_key(const u8 * key,u32 keylen,u16 * card,u16 * dom,u32 * keytype,u32 * keybitsize,u32 * flags,u32 xflags)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 
pkey_handler_apqns_for_key(const u8 * key,u32 keylen,u32 flags,struct pkey_apqn * apqns,size_t * nr_apqns,u32 xflags)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 
pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,u8 cur_mkvp[32],u8 alt_mkvp[32],u32 flags,struct pkey_apqn * apqns,size_t * nr_apqns,u32 xflags)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 
pkey_handler_request_modules(void)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  */
pkey_init(void)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  */
pkey_exit(void)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