xref: /linux/crypto/crypto_user.c (revision f2ee442115c9b6219083c019939a9cc0c9abb2f8)
1 /*
2  * Crypto user configuration API.
3  *
4  * Copyright (C) 2011 secunet Security Networks AG
5  * Copyright (C) 2011 Steffen Klassert <steffen.klassert@secunet.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <linux/module.h>
22 #include <linux/crypto.h>
23 #include <linux/cryptouser.h>
24 #include <net/netlink.h>
25 #include <linux/security.h>
26 #include <net/net_namespace.h>
27 #include "internal.h"
28 
29 DEFINE_MUTEX(crypto_cfg_mutex);
30 
31 /* The crypto netlink socket */
32 static struct sock *crypto_nlsk;
33 
34 struct crypto_dump_info {
35 	struct sk_buff *in_skb;
36 	struct sk_buff *out_skb;
37 	u32 nlmsg_seq;
38 	u16 nlmsg_flags;
39 };
40 
41 static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
42 {
43 	struct crypto_alg *q, *alg = NULL;
44 
45 	down_read(&crypto_alg_sem);
46 
47 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
48 		int match = 0;
49 
50 		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
51 			continue;
52 
53 		if (strlen(p->cru_driver_name))
54 			match = !strcmp(q->cra_driver_name,
55 					p->cru_driver_name);
56 		else if (!exact)
57 			match = !strcmp(q->cra_name, p->cru_name);
58 
59 		if (match) {
60 			alg = q;
61 			break;
62 		}
63 	}
64 
65 	up_read(&crypto_alg_sem);
66 
67 	return alg;
68 }
69 
70 static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
71 {
72 	struct crypto_report_cipher rcipher;
73 
74 	snprintf(rcipher.type, CRYPTO_MAX_ALG_NAME, "%s", "cipher");
75 
76 	rcipher.blocksize = alg->cra_blocksize;
77 	rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
78 	rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;
79 
80 	NLA_PUT(skb, CRYPTOCFGA_REPORT_CIPHER,
81 		sizeof(struct crypto_report_cipher), &rcipher);
82 
83 	return 0;
84 
85 nla_put_failure:
86 	return -EMSGSIZE;
87 }
88 
89 static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
90 {
91 	struct crypto_report_comp rcomp;
92 
93 	snprintf(rcomp.type, CRYPTO_MAX_ALG_NAME, "%s", "compression");
94 
95 	NLA_PUT(skb, CRYPTOCFGA_REPORT_COMPRESS,
96 		sizeof(struct crypto_report_comp), &rcomp);
97 
98 	return 0;
99 
100 nla_put_failure:
101 	return -EMSGSIZE;
102 }
103 
104 static int crypto_report_one(struct crypto_alg *alg,
105 			     struct crypto_user_alg *ualg, struct sk_buff *skb)
106 {
107 	memcpy(&ualg->cru_name, &alg->cra_name, sizeof(ualg->cru_name));
108 	memcpy(&ualg->cru_driver_name, &alg->cra_driver_name,
109 	       sizeof(ualg->cru_driver_name));
110 	memcpy(&ualg->cru_module_name, module_name(alg->cra_module),
111 	       CRYPTO_MAX_ALG_NAME);
112 
113 	ualg->cru_flags = alg->cra_flags;
114 	ualg->cru_refcnt = atomic_read(&alg->cra_refcnt);
115 
116 	NLA_PUT_U32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority);
117 
118 	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
119 		struct crypto_report_larval rl;
120 
121 		snprintf(rl.type, CRYPTO_MAX_ALG_NAME, "%s", "larval");
122 
123 		NLA_PUT(skb, CRYPTOCFGA_REPORT_LARVAL,
124 			sizeof(struct crypto_report_larval), &rl);
125 
126 		goto out;
127 	}
128 
129 	if (alg->cra_type && alg->cra_type->report) {
130 		if (alg->cra_type->report(skb, alg))
131 			goto nla_put_failure;
132 
133 		goto out;
134 	}
135 
136 	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
137 	case CRYPTO_ALG_TYPE_CIPHER:
138 		if (crypto_report_cipher(skb, alg))
139 			goto nla_put_failure;
140 
141 		break;
142 	case CRYPTO_ALG_TYPE_COMPRESS:
143 		if (crypto_report_comp(skb, alg))
144 			goto nla_put_failure;
145 
146 		break;
147 	}
148 
149 out:
150 	return 0;
151 
152 nla_put_failure:
153 	return -EMSGSIZE;
154 }
155 
156 static int crypto_report_alg(struct crypto_alg *alg,
157 			     struct crypto_dump_info *info)
158 {
159 	struct sk_buff *in_skb = info->in_skb;
160 	struct sk_buff *skb = info->out_skb;
161 	struct nlmsghdr *nlh;
162 	struct crypto_user_alg *ualg;
163 	int err = 0;
164 
165 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, info->nlmsg_seq,
166 			CRYPTO_MSG_GETALG, sizeof(*ualg), info->nlmsg_flags);
167 	if (!nlh) {
168 		err = -EMSGSIZE;
169 		goto out;
170 	}
171 
172 	ualg = nlmsg_data(nlh);
173 
174 	err = crypto_report_one(alg, ualg, skb);
175 	if (err) {
176 		nlmsg_cancel(skb, nlh);
177 		goto out;
178 	}
179 
180 	nlmsg_end(skb, nlh);
181 
182 out:
183 	return err;
184 }
185 
186 static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
187 			 struct nlattr **attrs)
188 {
189 	struct crypto_user_alg *p = nlmsg_data(in_nlh);
190 	struct crypto_alg *alg;
191 	struct sk_buff *skb;
192 	struct crypto_dump_info info;
193 	int err;
194 
195 	if (!p->cru_driver_name)
196 		return -EINVAL;
197 
198 	alg = crypto_alg_match(p, 1);
199 	if (!alg)
200 		return -ENOENT;
201 
202 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
203 	if (!skb)
204 		return -ENOMEM;
205 
206 	info.in_skb = in_skb;
207 	info.out_skb = skb;
208 	info.nlmsg_seq = in_nlh->nlmsg_seq;
209 	info.nlmsg_flags = 0;
210 
211 	err = crypto_report_alg(alg, &info);
212 	if (err)
213 		return err;
214 
215 	return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).pid);
216 }
217 
218 static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
219 {
220 	struct crypto_alg *alg;
221 	struct crypto_dump_info info;
222 	int err;
223 
224 	if (cb->args[0])
225 		goto out;
226 
227 	cb->args[0] = 1;
228 
229 	info.in_skb = cb->skb;
230 	info.out_skb = skb;
231 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
232 	info.nlmsg_flags = NLM_F_MULTI;
233 
234 	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
235 		err = crypto_report_alg(alg, &info);
236 		if (err)
237 			goto out_err;
238 	}
239 
240 out:
241 	return skb->len;
242 out_err:
243 	return err;
244 }
245 
246 static int crypto_dump_report_done(struct netlink_callback *cb)
247 {
248 	return 0;
249 }
250 
251 static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
252 			     struct nlattr **attrs)
253 {
254 	struct crypto_alg *alg;
255 	struct crypto_user_alg *p = nlmsg_data(nlh);
256 	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
257 	LIST_HEAD(list);
258 
259 	if (priority && !strlen(p->cru_driver_name))
260 		return -EINVAL;
261 
262 	alg = crypto_alg_match(p, 1);
263 	if (!alg)
264 		return -ENOENT;
265 
266 	down_write(&crypto_alg_sem);
267 
268 	crypto_remove_spawns(alg, &list, NULL);
269 
270 	if (priority)
271 		alg->cra_priority = nla_get_u32(priority);
272 
273 	up_write(&crypto_alg_sem);
274 
275 	crypto_remove_final(&list);
276 
277 	return 0;
278 }
279 
280 static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
281 			  struct nlattr **attrs)
282 {
283 	struct crypto_alg *alg;
284 	struct crypto_user_alg *p = nlmsg_data(nlh);
285 
286 	alg = crypto_alg_match(p, 1);
287 	if (!alg)
288 		return -ENOENT;
289 
290 	/* We can not unregister core algorithms such as aes-generic.
291 	 * We would loose the reference in the crypto_alg_list to this algorithm
292 	 * if we try to unregister. Unregistering such an algorithm without
293 	 * removing the module is not possible, so we restrict to crypto
294 	 * instances that are build from templates. */
295 	if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
296 		return -EINVAL;
297 
298 	if (atomic_read(&alg->cra_refcnt) != 1)
299 		return -EBUSY;
300 
301 	return crypto_unregister_alg(alg);
302 }
303 
304 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
305 			  struct nlattr **attrs)
306 {
307 	int exact;
308 	const char *name;
309 	struct crypto_alg *alg;
310 	struct crypto_user_alg *p = nlmsg_data(nlh);
311 	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
312 
313 	if (strlen(p->cru_driver_name))
314 		exact = 1;
315 
316 	if (priority && !exact)
317 		return -EINVAL;
318 
319 	alg = crypto_alg_match(p, exact);
320 	if (alg)
321 		return -EEXIST;
322 
323 	if (strlen(p->cru_driver_name))
324 		name = p->cru_driver_name;
325 	else
326 		name = p->cru_name;
327 
328 	alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
329 	if (IS_ERR(alg))
330 		return PTR_ERR(alg);
331 
332 	down_write(&crypto_alg_sem);
333 
334 	if (priority)
335 		alg->cra_priority = nla_get_u32(priority);
336 
337 	up_write(&crypto_alg_sem);
338 
339 	crypto_mod_put(alg);
340 
341 	return 0;
342 }
343 
344 #define MSGSIZE(type) sizeof(struct type)
345 
346 static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
347 	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
348 	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
349 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
350 	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
351 };
352 
353 static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
354 	[CRYPTOCFGA_PRIORITY_VAL]   = { .type = NLA_U32},
355 };
356 
357 #undef MSGSIZE
358 
359 static struct crypto_link {
360 	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
361 	int (*dump)(struct sk_buff *, struct netlink_callback *);
362 	int (*done)(struct netlink_callback *);
363 } crypto_dispatch[CRYPTO_NR_MSGTYPES] = {
364 	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = { .doit = crypto_add_alg},
365 	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_alg},
366 	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = { .doit = crypto_update_alg},
367 	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = { .doit = crypto_report,
368 						       .dump = crypto_dump_report,
369 						       .done = crypto_dump_report_done},
370 };
371 
372 static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
373 {
374 	struct nlattr *attrs[CRYPTOCFGA_MAX+1];
375 	struct crypto_link *link;
376 	int type, err;
377 
378 	type = nlh->nlmsg_type;
379 	if (type > CRYPTO_MSG_MAX)
380 		return -EINVAL;
381 
382 	type -= CRYPTO_MSG_BASE;
383 	link = &crypto_dispatch[type];
384 
385 	if (security_netlink_recv(skb, CAP_NET_ADMIN))
386 		return -EPERM;
387 
388 	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
389 	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
390 		if (link->dump == NULL)
391 			return -EINVAL;
392 
393 		return netlink_dump_start(crypto_nlsk, skb, nlh,
394 					  link->dump, link->done, 0);
395 	}
396 
397 	err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
398 			  crypto_policy);
399 	if (err < 0)
400 		return err;
401 
402 	if (link->doit == NULL)
403 		return -EINVAL;
404 
405 	return link->doit(skb, nlh, attrs);
406 }
407 
408 static void crypto_netlink_rcv(struct sk_buff *skb)
409 {
410 	mutex_lock(&crypto_cfg_mutex);
411 	netlink_rcv_skb(skb, &crypto_user_rcv_msg);
412 	mutex_unlock(&crypto_cfg_mutex);
413 }
414 
415 static int __init crypto_user_init(void)
416 {
417 	crypto_nlsk = netlink_kernel_create(&init_net, NETLINK_CRYPTO,
418 					    0, crypto_netlink_rcv,
419 					    NULL, THIS_MODULE);
420 	if (!crypto_nlsk)
421 		return -ENOMEM;
422 
423 	return 0;
424 }
425 
426 static void __exit crypto_user_exit(void)
427 {
428 	netlink_kernel_release(crypto_nlsk);
429 }
430 
431 module_init(crypto_user_init);
432 module_exit(crypto_user_exit);
433 MODULE_LICENSE("GPL");
434 MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
435 MODULE_DESCRIPTION("Crypto userspace configuration API");
436