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