xref: /linux/crypto/crypto_user.c (revision d639d9fa162aadec1ae9980c4dcf6e50bd2f8290)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Crypto user configuration API.
4  *
5  * Copyright (C) 2011 secunet Security Networks AG
6  * Copyright (C) 2011 Steffen Klassert <steffen.klassert@secunet.com>
7  */
8 
9 #include <linux/module.h>
10 #include <linux/crypto.h>
11 #include <linux/cryptouser.h>
12 #include <linux/sched.h>
13 #include <linux/security.h>
14 #include <net/netlink.h>
15 #include <net/net_namespace.h>
16 #include <net/sock.h>
17 #include <crypto/internal/skcipher.h>
18 #include <crypto/internal/rng.h>
19 #include <crypto/akcipher.h>
20 #include <crypto/kpp.h>
21 
22 #include "internal.h"
23 
24 #define null_terminated(x)	(strnlen(x, sizeof(x)) < sizeof(x))
25 
26 static DEFINE_MUTEX(crypto_cfg_mutex);
27 
28 struct crypto_dump_info {
29 	struct sk_buff *in_skb;
30 	struct sk_buff *out_skb;
31 	u32 nlmsg_seq;
32 	u16 nlmsg_flags;
33 };
34 
35 static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
36 {
37 	struct crypto_alg *q, *alg = NULL;
38 
39 	down_read(&crypto_alg_sem);
40 
41 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
42 		int match = 0;
43 
44 		if (crypto_is_larval(q))
45 			continue;
46 
47 		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
48 			continue;
49 
50 		if (strlen(p->cru_driver_name))
51 			match = !strcmp(q->cra_driver_name,
52 					p->cru_driver_name);
53 		else if (!exact)
54 			match = !strcmp(q->cra_name, p->cru_name);
55 
56 		if (!match)
57 			continue;
58 
59 		if (unlikely(!crypto_mod_get(q)))
60 			continue;
61 
62 		alg = q;
63 		break;
64 	}
65 
66 	up_read(&crypto_alg_sem);
67 
68 	return alg;
69 }
70 
71 static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
72 {
73 	struct crypto_report_cipher rcipher = {
74 		.type = "cipher",
75 	};
76 
77 	rcipher.blocksize = alg->cra_blocksize;
78 	rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
79 	rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
80 
81 	return nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
82 		       sizeof(rcipher), &rcipher);
83 }
84 
85 static int crypto_report_one(struct crypto_alg *alg,
86 			     struct crypto_user_alg *ualg, struct sk_buff *skb)
87 {
88 	memset(ualg, 0, sizeof(*ualg));
89 
90 	strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
91 	strscpy(ualg->cru_driver_name, alg->cra_driver_name,
92 		sizeof(ualg->cru_driver_name));
93 	strscpy(ualg->cru_module_name, module_name(alg->cra_module),
94 		sizeof(ualg->cru_module_name));
95 
96 	ualg->cru_type = 0;
97 	ualg->cru_mask = 0;
98 	ualg->cru_flags = alg->cra_flags;
99 	ualg->cru_refcnt = refcount_read(&alg->cra_refcnt);
100 
101 	if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
102 		goto nla_put_failure;
103 	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
104 		struct crypto_report_larval rl = {
105 			.type = "larval",
106 		};
107 
108 		if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL, sizeof(rl), &rl))
109 			goto nla_put_failure;
110 		goto out;
111 	}
112 
113 	if (alg->cra_type && alg->cra_type->report) {
114 		if (alg->cra_type->report(skb, alg))
115 			goto nla_put_failure;
116 
117 		goto out;
118 	}
119 
120 	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
121 	case CRYPTO_ALG_TYPE_CIPHER:
122 		if (crypto_report_cipher(skb, alg))
123 			goto nla_put_failure;
124 
125 		break;
126 	}
127 
128 out:
129 	return 0;
130 
131 nla_put_failure:
132 	return -EMSGSIZE;
133 }
134 
135 static int crypto_report_alg(struct crypto_alg *alg,
136 			     struct crypto_dump_info *info)
137 {
138 	struct sk_buff *in_skb = info->in_skb;
139 	struct sk_buff *skb = info->out_skb;
140 	struct nlmsghdr *nlh;
141 	struct crypto_user_alg *ualg;
142 	int err = 0;
143 
144 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
145 			CRYPTO_MSG_GETALG, sizeof(*ualg), info->nlmsg_flags);
146 	if (!nlh) {
147 		err = -EMSGSIZE;
148 		goto out;
149 	}
150 
151 	ualg = nlmsg_data(nlh);
152 
153 	err = crypto_report_one(alg, ualg, skb);
154 	if (err) {
155 		nlmsg_cancel(skb, nlh);
156 		goto out;
157 	}
158 
159 	nlmsg_end(skb, nlh);
160 
161 out:
162 	return err;
163 }
164 
165 static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
166 			 struct nlattr **attrs)
167 {
168 	struct net *net = sock_net(in_skb->sk);
169 	struct crypto_user_alg *p = nlmsg_data(in_nlh);
170 	struct crypto_alg *alg;
171 	struct sk_buff *skb;
172 	struct crypto_dump_info info;
173 	int err;
174 
175 	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
176 		return -EINVAL;
177 
178 	alg = crypto_alg_match(p, 0);
179 	if (!alg)
180 		return -ENOENT;
181 
182 	err = -ENOMEM;
183 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
184 	if (!skb)
185 		goto drop_alg;
186 
187 	info.in_skb = in_skb;
188 	info.out_skb = skb;
189 	info.nlmsg_seq = in_nlh->nlmsg_seq;
190 	info.nlmsg_flags = 0;
191 
192 	err = crypto_report_alg(alg, &info);
193 
194 drop_alg:
195 	crypto_mod_put(alg);
196 
197 	if (err) {
198 		kfree_skb(skb);
199 		return err;
200 	}
201 
202 	return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
203 }
204 
205 static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
206 {
207 	const size_t start_pos = cb->args[0];
208 	size_t pos = 0;
209 	struct crypto_dump_info info;
210 	struct crypto_alg *alg;
211 	int res;
212 
213 	info.in_skb = cb->skb;
214 	info.out_skb = skb;
215 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
216 	info.nlmsg_flags = NLM_F_MULTI;
217 
218 	down_read(&crypto_alg_sem);
219 	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
220 		if (pos >= start_pos) {
221 			res = crypto_report_alg(alg, &info);
222 			if (res == -EMSGSIZE)
223 				break;
224 			if (res)
225 				goto out;
226 		}
227 		pos++;
228 	}
229 	cb->args[0] = pos;
230 	res = skb->len;
231 out:
232 	up_read(&crypto_alg_sem);
233 	return res;
234 }
235 
236 static int crypto_dump_report_done(struct netlink_callback *cb)
237 {
238 	return 0;
239 }
240 
241 static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
242 			     struct nlattr **attrs)
243 {
244 	struct crypto_alg *alg;
245 	struct crypto_user_alg *p = nlmsg_data(nlh);
246 	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
247 	LIST_HEAD(list);
248 
249 	if (!netlink_capable(skb, CAP_NET_ADMIN))
250 		return -EPERM;
251 
252 	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
253 		return -EINVAL;
254 
255 	if (priority && !strlen(p->cru_driver_name))
256 		return -EINVAL;
257 
258 	alg = crypto_alg_match(p, 1);
259 	if (!alg)
260 		return -ENOENT;
261 
262 	down_write(&crypto_alg_sem);
263 
264 	crypto_remove_spawns(alg, &list, NULL);
265 
266 	if (priority)
267 		alg->cra_priority = nla_get_u32(priority);
268 
269 	up_write(&crypto_alg_sem);
270 
271 	crypto_mod_put(alg);
272 	crypto_remove_final(&list);
273 
274 	return 0;
275 }
276 
277 static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
278 			  struct nlattr **attrs)
279 {
280 	struct crypto_alg *alg;
281 	struct crypto_user_alg *p = nlmsg_data(nlh);
282 	int err;
283 
284 	if (!netlink_capable(skb, CAP_NET_ADMIN))
285 		return -EPERM;
286 
287 	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
288 		return -EINVAL;
289 
290 	alg = crypto_alg_match(p, 1);
291 	if (!alg)
292 		return -ENOENT;
293 
294 	/* We can not unregister core algorithms such as aes.
295 	 * We would loose the reference in the crypto_alg_list to this algorithm
296 	 * if we try to unregister. Unregistering such an algorithm without
297 	 * removing the module is not possible, so we restrict to crypto
298 	 * instances that are build from templates. */
299 	err = -EINVAL;
300 	if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
301 		goto drop_alg;
302 
303 	err = -EBUSY;
304 	if (refcount_read(&alg->cra_refcnt) > 2)
305 		goto drop_alg;
306 
307 	crypto_unregister_instance((struct crypto_instance *)alg);
308 	err = 0;
309 
310 drop_alg:
311 	crypto_mod_put(alg);
312 	return err;
313 }
314 
315 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
316 			  struct nlattr **attrs)
317 {
318 	int exact = 0;
319 	const char *name;
320 	struct crypto_alg *alg;
321 	struct crypto_user_alg *p = nlmsg_data(nlh);
322 	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
323 
324 	if (!netlink_capable(skb, CAP_NET_ADMIN))
325 		return -EPERM;
326 
327 	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
328 		return -EINVAL;
329 
330 	if (strlen(p->cru_driver_name))
331 		exact = 1;
332 
333 	if (priority && !exact)
334 		return -EINVAL;
335 
336 	alg = crypto_alg_match(p, exact);
337 	if (alg) {
338 		crypto_mod_put(alg);
339 		return -EEXIST;
340 	}
341 
342 	if (strlen(p->cru_driver_name))
343 		name = p->cru_driver_name;
344 	else
345 		name = p->cru_name;
346 
347 	alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
348 	if (IS_ERR(alg))
349 		return PTR_ERR(alg);
350 
351 	down_write(&crypto_alg_sem);
352 
353 	if (priority)
354 		alg->cra_priority = nla_get_u32(priority);
355 
356 	up_write(&crypto_alg_sem);
357 
358 	crypto_mod_put(alg);
359 
360 	return 0;
361 }
362 
363 static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh,
364 			  struct nlattr **attrs)
365 {
366 	if (!netlink_capable(skb, CAP_NET_ADMIN))
367 		return -EPERM;
368 	return crypto_del_default_rng();
369 }
370 
371 static int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
372 			     struct nlattr **attrs)
373 {
374 	/* No longer supported */
375 	return -ENOTSUPP;
376 }
377 
378 #define MSGSIZE(type) sizeof(struct type)
379 
380 static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
381 	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
382 	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
383 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
384 	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
385 	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = 0,
386 	[CRYPTO_MSG_GETSTAT	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
387 };
388 
389 static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
390 	[CRYPTOCFGA_PRIORITY_VAL]   = { .type = NLA_U32},
391 };
392 
393 #undef MSGSIZE
394 
395 static const struct crypto_link {
396 	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
397 	int (*dump)(struct sk_buff *, struct netlink_callback *);
398 	int (*done)(struct netlink_callback *);
399 } crypto_dispatch[CRYPTO_NR_MSGTYPES] = {
400 	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = { .doit = crypto_add_alg},
401 	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_alg},
402 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = { .doit = crypto_update_alg},
403 	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = { .doit = crypto_report,
404 						       .dump = crypto_dump_report,
405 						       .done = crypto_dump_report_done},
406 	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
407 	[CRYPTO_MSG_GETSTAT	- CRYPTO_MSG_BASE] = { .doit = crypto_reportstat},
408 };
409 
410 static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
411 			       struct netlink_ext_ack *extack)
412 {
413 	struct net *net = sock_net(skb->sk);
414 	struct nlattr *attrs[CRYPTOCFGA_MAX+1];
415 	const struct crypto_link *link;
416 	int type, err;
417 
418 	type = nlh->nlmsg_type;
419 	if (type > CRYPTO_MSG_MAX)
420 		return -EINVAL;
421 
422 	type -= CRYPTO_MSG_BASE;
423 	link = &crypto_dispatch[type];
424 
425 	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
426 	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
427 		struct crypto_alg *alg;
428 		unsigned long dump_alloc = 0;
429 
430 		if (link->dump == NULL)
431 			return -EINVAL;
432 
433 		down_read(&crypto_alg_sem);
434 		list_for_each_entry(alg, &crypto_alg_list, cra_list)
435 			dump_alloc += CRYPTO_REPORT_MAXSIZE;
436 		up_read(&crypto_alg_sem);
437 
438 		{
439 			struct netlink_dump_control c = {
440 				.dump = link->dump,
441 				.done = link->done,
442 				.min_dump_alloc = min(dump_alloc, 65535UL),
443 			};
444 			err = netlink_dump_start(net->crypto_nlsk, skb, nlh, &c);
445 		}
446 
447 		return err;
448 	}
449 
450 	err = nlmsg_parse_deprecated(nlh, crypto_msg_min[type], attrs,
451 				     CRYPTOCFGA_MAX, crypto_policy, extack);
452 	if (err < 0)
453 		return err;
454 
455 	if (link->doit == NULL)
456 		return -EINVAL;
457 
458 	return link->doit(skb, nlh, attrs);
459 }
460 
461 static void crypto_netlink_rcv(struct sk_buff *skb)
462 {
463 	mutex_lock(&crypto_cfg_mutex);
464 	netlink_rcv_skb(skb, &crypto_user_rcv_msg);
465 	mutex_unlock(&crypto_cfg_mutex);
466 }
467 
468 static int __net_init crypto_netlink_init(struct net *net)
469 {
470 	struct netlink_kernel_cfg cfg = {
471 		.input	= crypto_netlink_rcv,
472 	};
473 
474 	net->crypto_nlsk = netlink_kernel_create(net, NETLINK_CRYPTO, &cfg);
475 	return net->crypto_nlsk == NULL ? -ENOMEM : 0;
476 }
477 
478 static void __net_exit crypto_netlink_exit(struct net *net)
479 {
480 	netlink_kernel_release(net->crypto_nlsk);
481 	net->crypto_nlsk = NULL;
482 }
483 
484 static struct pernet_operations crypto_netlink_net_ops = {
485 	.init = crypto_netlink_init,
486 	.exit = crypto_netlink_exit,
487 };
488 
489 static int __init crypto_user_init(void)
490 {
491 	return register_pernet_subsys(&crypto_netlink_net_ops);
492 }
493 
494 static void __exit crypto_user_exit(void)
495 {
496 	unregister_pernet_subsys(&crypto_netlink_net_ops);
497 }
498 
499 module_init(crypto_user_init);
500 module_exit(crypto_user_exit);
501 MODULE_LICENSE("GPL");
502 MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
503 MODULE_DESCRIPTION("Crypto userspace configuration API");
504 MODULE_ALIAS("net-pf-16-proto-21");
505