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