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