crypto: user - Fix invalid stat reporting
[linux-2.6-microblaze.git] / crypto / crypto_user_stat.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Crypto user configuration API.
4  *
5  * Copyright (C) 2017-2018 Corentin Labbe <clabbe@baylibre.com>
6  *
7  */
8
9 #include <linux/crypto.h>
10 #include <linux/cryptouser.h>
11 #include <linux/sched.h>
12 #include <net/netlink.h>
13 #include <crypto/internal/skcipher.h>
14 #include <crypto/internal/rng.h>
15 #include <crypto/akcipher.h>
16 #include <crypto/kpp.h>
17 #include <crypto/internal/cryptouser.h>
18
19 #include "internal.h"
20
21 #define null_terminated(x)      (strnlen(x, sizeof(x)) < sizeof(x))
22
23 static DEFINE_MUTEX(crypto_cfg_mutex);
24
25 extern struct sock *crypto_nlsk;
26
27 struct crypto_dump_info {
28         struct sk_buff *in_skb;
29         struct sk_buff *out_skb;
30         u32 nlmsg_seq;
31         u16 nlmsg_flags;
32 };
33
34 static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg)
35 {
36         struct crypto_stat_aead raead;
37         u64 v64;
38
39         memset(&raead, 0, sizeof(raead));
40
41         strscpy(raead.type, "aead", sizeof(raead.type));
42
43         v64 = atomic64_read(&alg->encrypt_cnt);
44         raead.stat_encrypt_cnt = v64;
45         v64 = atomic64_read(&alg->encrypt_tlen);
46         raead.stat_encrypt_tlen = v64;
47         v64 = atomic64_read(&alg->decrypt_cnt);
48         raead.stat_decrypt_cnt = v64;
49         v64 = atomic64_read(&alg->decrypt_tlen);
50         raead.stat_decrypt_tlen = v64;
51         v64 = atomic64_read(&alg->aead_err_cnt);
52         raead.stat_aead_err_cnt = v64;
53
54         return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead);
55 }
56
57 static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
58 {
59         struct crypto_stat_cipher rcipher;
60         u64 v64;
61
62         memset(&rcipher, 0, sizeof(rcipher));
63
64         strscpy(rcipher.type, "cipher", sizeof(rcipher.type));
65
66         v64 = atomic64_read(&alg->encrypt_cnt);
67         rcipher.stat_encrypt_cnt = v64;
68         v64 = atomic64_read(&alg->encrypt_tlen);
69         rcipher.stat_encrypt_tlen = v64;
70         v64 = atomic64_read(&alg->decrypt_cnt);
71         rcipher.stat_decrypt_cnt = v64;
72         v64 = atomic64_read(&alg->decrypt_tlen);
73         rcipher.stat_decrypt_tlen = v64;
74         v64 = atomic64_read(&alg->cipher_err_cnt);
75         rcipher.stat_cipher_err_cnt = v64;
76
77         return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher);
78 }
79
80 static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
81 {
82         struct crypto_stat_compress rcomp;
83         u64 v64;
84
85         memset(&rcomp, 0, sizeof(rcomp));
86
87         strscpy(rcomp.type, "compression", sizeof(rcomp.type));
88         v64 = atomic64_read(&alg->compress_cnt);
89         rcomp.stat_compress_cnt = v64;
90         v64 = atomic64_read(&alg->compress_tlen);
91         rcomp.stat_compress_tlen = v64;
92         v64 = atomic64_read(&alg->decompress_cnt);
93         rcomp.stat_decompress_cnt = v64;
94         v64 = atomic64_read(&alg->decompress_tlen);
95         rcomp.stat_decompress_tlen = v64;
96         v64 = atomic64_read(&alg->compress_err_cnt);
97         rcomp.stat_compress_err_cnt = v64;
98
99         return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp);
100 }
101
102 static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
103 {
104         struct crypto_stat_compress racomp;
105         u64 v64;
106
107         memset(&racomp, 0, sizeof(racomp));
108
109         strscpy(racomp.type, "acomp", sizeof(racomp.type));
110         v64 = atomic64_read(&alg->compress_cnt);
111         racomp.stat_compress_cnt = v64;
112         v64 = atomic64_read(&alg->compress_tlen);
113         racomp.stat_compress_tlen = v64;
114         v64 = atomic64_read(&alg->decompress_cnt);
115         racomp.stat_decompress_cnt = v64;
116         v64 = atomic64_read(&alg->decompress_tlen);
117         racomp.stat_decompress_tlen = v64;
118         v64 = atomic64_read(&alg->compress_err_cnt);
119         racomp.stat_compress_err_cnt = v64;
120
121         return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp);
122 }
123
124 static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
125 {
126         struct crypto_stat_akcipher rakcipher;
127         u64 v64;
128
129         memset(&rakcipher, 0, sizeof(rakcipher));
130
131         strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
132         v64 = atomic64_read(&alg->encrypt_cnt);
133         rakcipher.stat_encrypt_cnt = v64;
134         v64 = atomic64_read(&alg->encrypt_tlen);
135         rakcipher.stat_encrypt_tlen = v64;
136         v64 = atomic64_read(&alg->decrypt_cnt);
137         rakcipher.stat_decrypt_cnt = v64;
138         v64 = atomic64_read(&alg->decrypt_tlen);
139         rakcipher.stat_decrypt_tlen = v64;
140         v64 = atomic64_read(&alg->sign_cnt);
141         rakcipher.stat_sign_cnt = v64;
142         v64 = atomic64_read(&alg->verify_cnt);
143         rakcipher.stat_verify_cnt = v64;
144         v64 = atomic64_read(&alg->akcipher_err_cnt);
145         rakcipher.stat_akcipher_err_cnt = v64;
146
147         return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
148                        sizeof(rakcipher), &rakcipher);
149 }
150
151 static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
152 {
153         struct crypto_stat_kpp rkpp;
154         u64 v;
155
156         memset(&rkpp, 0, sizeof(rkpp));
157
158         strscpy(rkpp.type, "kpp", sizeof(rkpp.type));
159
160         v = atomic64_read(&alg->setsecret_cnt);
161         rkpp.stat_setsecret_cnt = v;
162         v = atomic64_read(&alg->generate_public_key_cnt);
163         rkpp.stat_generate_public_key_cnt = v;
164         v = atomic64_read(&alg->compute_shared_secret_cnt);
165         rkpp.stat_compute_shared_secret_cnt = v;
166         v = atomic64_read(&alg->kpp_err_cnt);
167         rkpp.stat_kpp_err_cnt = v;
168
169         return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp);
170 }
171
172 static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
173 {
174         struct crypto_stat_hash rhash;
175         u64 v64;
176
177         memset(&rhash, 0, sizeof(rhash));
178
179         strscpy(rhash.type, "ahash", sizeof(rhash.type));
180
181         v64 = atomic64_read(&alg->hash_cnt);
182         rhash.stat_hash_cnt = v64;
183         v64 = atomic64_read(&alg->hash_tlen);
184         rhash.stat_hash_tlen = v64;
185         v64 = atomic64_read(&alg->hash_err_cnt);
186         rhash.stat_hash_err_cnt = v64;
187
188         return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
189 }
190
191 static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
192 {
193         struct crypto_stat_hash rhash;
194         u64 v64;
195
196         memset(&rhash, 0, sizeof(rhash));
197
198         strscpy(rhash.type, "shash", sizeof(rhash.type));
199
200         v64 = atomic64_read(&alg->hash_cnt);
201         rhash.stat_hash_cnt = v64;
202         v64 = atomic64_read(&alg->hash_tlen);
203         rhash.stat_hash_tlen = v64;
204         v64 = atomic64_read(&alg->hash_err_cnt);
205         rhash.stat_hash_err_cnt = v64;
206
207         return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
208 }
209
210 static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
211 {
212         struct crypto_stat_rng rrng;
213         u64 v64;
214
215         memset(&rrng, 0, sizeof(rrng));
216
217         strscpy(rrng.type, "rng", sizeof(rrng.type));
218
219         v64 = atomic64_read(&alg->generate_cnt);
220         rrng.stat_generate_cnt = v64;
221         v64 = atomic64_read(&alg->generate_tlen);
222         rrng.stat_generate_tlen = v64;
223         v64 = atomic64_read(&alg->seed_cnt);
224         rrng.stat_seed_cnt = v64;
225         v64 = atomic64_read(&alg->rng_err_cnt);
226         rrng.stat_rng_err_cnt = v64;
227
228         return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng);
229 }
230
231 static int crypto_reportstat_one(struct crypto_alg *alg,
232                                  struct crypto_user_alg *ualg,
233                                  struct sk_buff *skb)
234 {
235         memset(ualg, 0, sizeof(*ualg));
236
237         strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
238         strscpy(ualg->cru_driver_name, alg->cra_driver_name,
239                 sizeof(ualg->cru_driver_name));
240         strscpy(ualg->cru_module_name, module_name(alg->cra_module),
241                 sizeof(ualg->cru_module_name));
242
243         ualg->cru_type = 0;
244         ualg->cru_mask = 0;
245         ualg->cru_flags = alg->cra_flags;
246         ualg->cru_refcnt = refcount_read(&alg->cra_refcnt);
247
248         if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
249                 goto nla_put_failure;
250         if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
251                 struct crypto_stat_larval rl;
252
253                 memset(&rl, 0, sizeof(rl));
254                 strscpy(rl.type, "larval", sizeof(rl.type));
255                 if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl))
256                         goto nla_put_failure;
257                 goto out;
258         }
259
260         switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
261         case CRYPTO_ALG_TYPE_AEAD:
262                 if (crypto_report_aead(skb, alg))
263                         goto nla_put_failure;
264                 break;
265         case CRYPTO_ALG_TYPE_SKCIPHER:
266                 if (crypto_report_cipher(skb, alg))
267                         goto nla_put_failure;
268                 break;
269         case CRYPTO_ALG_TYPE_BLKCIPHER:
270                 if (crypto_report_cipher(skb, alg))
271                         goto nla_put_failure;
272                 break;
273         case CRYPTO_ALG_TYPE_CIPHER:
274                 if (crypto_report_cipher(skb, alg))
275                         goto nla_put_failure;
276                 break;
277         case CRYPTO_ALG_TYPE_COMPRESS:
278                 if (crypto_report_comp(skb, alg))
279                         goto nla_put_failure;
280                 break;
281         case CRYPTO_ALG_TYPE_ACOMPRESS:
282                 if (crypto_report_acomp(skb, alg))
283                         goto nla_put_failure;
284                 break;
285         case CRYPTO_ALG_TYPE_SCOMPRESS:
286                 if (crypto_report_acomp(skb, alg))
287                         goto nla_put_failure;
288                 break;
289         case CRYPTO_ALG_TYPE_AKCIPHER:
290                 if (crypto_report_akcipher(skb, alg))
291                         goto nla_put_failure;
292                 break;
293         case CRYPTO_ALG_TYPE_KPP:
294                 if (crypto_report_kpp(skb, alg))
295                         goto nla_put_failure;
296                 break;
297         case CRYPTO_ALG_TYPE_AHASH:
298                 if (crypto_report_ahash(skb, alg))
299                         goto nla_put_failure;
300                 break;
301         case CRYPTO_ALG_TYPE_HASH:
302                 if (crypto_report_shash(skb, alg))
303                         goto nla_put_failure;
304                 break;
305         case CRYPTO_ALG_TYPE_RNG:
306                 if (crypto_report_rng(skb, alg))
307                         goto nla_put_failure;
308                 break;
309         default:
310                 pr_err("ERROR: Unhandled alg %d in %s\n",
311                        alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL),
312                        __func__);
313         }
314
315 out:
316         return 0;
317
318 nla_put_failure:
319         return -EMSGSIZE;
320 }
321
322 static int crypto_reportstat_alg(struct crypto_alg *alg,
323                                  struct crypto_dump_info *info)
324 {
325         struct sk_buff *in_skb = info->in_skb;
326         struct sk_buff *skb = info->out_skb;
327         struct nlmsghdr *nlh;
328         struct crypto_user_alg *ualg;
329         int err = 0;
330
331         nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
332                         CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags);
333         if (!nlh) {
334                 err = -EMSGSIZE;
335                 goto out;
336         }
337
338         ualg = nlmsg_data(nlh);
339
340         err = crypto_reportstat_one(alg, ualg, skb);
341         if (err) {
342                 nlmsg_cancel(skb, nlh);
343                 goto out;
344         }
345
346         nlmsg_end(skb, nlh);
347
348 out:
349         return err;
350 }
351
352 int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
353                       struct nlattr **attrs)
354 {
355         struct crypto_user_alg *p = nlmsg_data(in_nlh);
356         struct crypto_alg *alg;
357         struct sk_buff *skb;
358         struct crypto_dump_info info;
359         int err;
360
361         if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
362                 return -EINVAL;
363
364         alg = crypto_alg_match(p, 0);
365         if (!alg)
366                 return -ENOENT;
367
368         err = -ENOMEM;
369         skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
370         if (!skb)
371                 goto drop_alg;
372
373         info.in_skb = in_skb;
374         info.out_skb = skb;
375         info.nlmsg_seq = in_nlh->nlmsg_seq;
376         info.nlmsg_flags = 0;
377
378         err = crypto_reportstat_alg(alg, &info);
379
380 drop_alg:
381         crypto_mod_put(alg);
382
383         if (err)
384                 return err;
385
386         return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
387 }
388
389 int crypto_dump_reportstat(struct sk_buff *skb, struct netlink_callback *cb)
390 {
391         struct crypto_alg *alg;
392         struct crypto_dump_info info;
393         int err;
394
395         if (cb->args[0])
396                 goto out;
397
398         cb->args[0] = 1;
399
400         info.in_skb = cb->skb;
401         info.out_skb = skb;
402         info.nlmsg_seq = cb->nlh->nlmsg_seq;
403         info.nlmsg_flags = NLM_F_MULTI;
404
405         list_for_each_entry(alg, &crypto_alg_list, cra_list) {
406                 err = crypto_reportstat_alg(alg, &info);
407                 if (err)
408                         goto out_err;
409         }
410
411 out:
412         return skb->len;
413 out_err:
414         return err;
415 }
416
417 int crypto_dump_reportstat_done(struct netlink_callback *cb)
418 {
419         return 0;
420 }
421
422 MODULE_LICENSE("GPL");