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 <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 | ||
cac5818c CL |
23 | struct crypto_dump_info { |
24 | struct sk_buff *in_skb; | |
25 | struct sk_buff *out_skb; | |
26 | u32 nlmsg_seq; | |
27 | u16 nlmsg_flags; | |
28 | }; | |
29 | ||
30 | static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg) | |
31 | { | |
7f0a9d5c | 32 | struct crypto_stat_aead raead; |
cac5818c | 33 | |
9f4debe3 CL |
34 | memset(&raead, 0, sizeof(raead)); |
35 | ||
37db69e0 | 36 | strscpy(raead.type, "aead", sizeof(raead.type)); |
cac5818c | 37 | |
17c18f9e CL |
38 | raead.stat_encrypt_cnt = atomic64_read(&alg->stats.aead.encrypt_cnt); |
39 | raead.stat_encrypt_tlen = atomic64_read(&alg->stats.aead.encrypt_tlen); | |
40 | raead.stat_decrypt_cnt = atomic64_read(&alg->stats.aead.decrypt_cnt); | |
41 | raead.stat_decrypt_tlen = atomic64_read(&alg->stats.aead.decrypt_tlen); | |
44f13133 | 42 | raead.stat_err_cnt = atomic64_read(&alg->stats.aead.err_cnt); |
cac5818c | 43 | |
37db69e0 | 44 | return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead); |
cac5818c CL |
45 | } |
46 | ||
47 | static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg) | |
48 | { | |
7f0a9d5c | 49 | struct crypto_stat_cipher rcipher; |
cac5818c | 50 | |
9f4debe3 CL |
51 | memset(&rcipher, 0, sizeof(rcipher)); |
52 | ||
37db69e0 | 53 | strscpy(rcipher.type, "cipher", sizeof(rcipher.type)); |
cac5818c | 54 | |
17c18f9e CL |
55 | rcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.cipher.encrypt_cnt); |
56 | rcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.cipher.encrypt_tlen); | |
57 | rcipher.stat_decrypt_cnt = atomic64_read(&alg->stats.cipher.decrypt_cnt); | |
58 | rcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.cipher.decrypt_tlen); | |
44f13133 | 59 | rcipher.stat_err_cnt = atomic64_read(&alg->stats.cipher.err_cnt); |
cac5818c | 60 | |
37db69e0 | 61 | return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher); |
cac5818c CL |
62 | } |
63 | ||
64 | static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg) | |
65 | { | |
7f0a9d5c | 66 | struct crypto_stat_compress rcomp; |
cac5818c | 67 | |
9f4debe3 CL |
68 | memset(&rcomp, 0, sizeof(rcomp)); |
69 | ||
37db69e0 | 70 | strscpy(rcomp.type, "compression", sizeof(rcomp.type)); |
17c18f9e CL |
71 | rcomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt); |
72 | rcomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen); | |
73 | rcomp.stat_decompress_cnt = atomic64_read(&alg->stats.compress.decompress_cnt); | |
74 | rcomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen); | |
44f13133 | 75 | rcomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt); |
cac5818c | 76 | |
37db69e0 | 77 | return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp); |
cac5818c CL |
78 | } |
79 | ||
80 | static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg) | |
81 | { | |
7f0a9d5c | 82 | struct crypto_stat_compress racomp; |
cac5818c | 83 | |
9f4debe3 CL |
84 | memset(&racomp, 0, sizeof(racomp)); |
85 | ||
37db69e0 | 86 | strscpy(racomp.type, "acomp", sizeof(racomp.type)); |
17c18f9e CL |
87 | racomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt); |
88 | racomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen); | |
89 | racomp.stat_decompress_cnt = atomic64_read(&alg->stats.compress.decompress_cnt); | |
90 | racomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen); | |
44f13133 | 91 | racomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt); |
cac5818c | 92 | |
37db69e0 | 93 | return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp); |
cac5818c CL |
94 | } |
95 | ||
96 | static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg) | |
97 | { | |
7f0a9d5c | 98 | struct crypto_stat_akcipher rakcipher; |
cac5818c | 99 | |
9f4debe3 CL |
100 | memset(&rakcipher, 0, sizeof(rakcipher)); |
101 | ||
37db69e0 | 102 | strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); |
17c18f9e CL |
103 | rakcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.akcipher.encrypt_cnt); |
104 | rakcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.akcipher.encrypt_tlen); | |
105 | rakcipher.stat_decrypt_cnt = atomic64_read(&alg->stats.akcipher.decrypt_cnt); | |
106 | rakcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.akcipher.decrypt_tlen); | |
107 | rakcipher.stat_sign_cnt = atomic64_read(&alg->stats.akcipher.sign_cnt); | |
108 | rakcipher.stat_verify_cnt = atomic64_read(&alg->stats.akcipher.verify_cnt); | |
44f13133 | 109 | rakcipher.stat_err_cnt = atomic64_read(&alg->stats.akcipher.err_cnt); |
cac5818c | 110 | |
37db69e0 EB |
111 | return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, |
112 | sizeof(rakcipher), &rakcipher); | |
cac5818c CL |
113 | } |
114 | ||
115 | static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg) | |
116 | { | |
7f0a9d5c | 117 | struct crypto_stat_kpp rkpp; |
cac5818c | 118 | |
9f4debe3 CL |
119 | memset(&rkpp, 0, sizeof(rkpp)); |
120 | ||
37db69e0 | 121 | strscpy(rkpp.type, "kpp", sizeof(rkpp.type)); |
cac5818c | 122 | |
17c18f9e CL |
123 | rkpp.stat_setsecret_cnt = atomic64_read(&alg->stats.kpp.setsecret_cnt); |
124 | rkpp.stat_generate_public_key_cnt = atomic64_read(&alg->stats.kpp.generate_public_key_cnt); | |
125 | rkpp.stat_compute_shared_secret_cnt = atomic64_read(&alg->stats.kpp.compute_shared_secret_cnt); | |
44f13133 | 126 | rkpp.stat_err_cnt = atomic64_read(&alg->stats.kpp.err_cnt); |
cac5818c | 127 | |
37db69e0 | 128 | return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp); |
cac5818c CL |
129 | } |
130 | ||
131 | static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg) | |
132 | { | |
7f0a9d5c | 133 | struct crypto_stat_hash rhash; |
cac5818c | 134 | |
9f4debe3 CL |
135 | memset(&rhash, 0, sizeof(rhash)); |
136 | ||
37db69e0 | 137 | strscpy(rhash.type, "ahash", sizeof(rhash.type)); |
cac5818c | 138 | |
17c18f9e CL |
139 | rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt); |
140 | rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen); | |
44f13133 | 141 | rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt); |
cac5818c | 142 | |
37db69e0 | 143 | return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash); |
cac5818c CL |
144 | } |
145 | ||
146 | static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg) | |
147 | { | |
7f0a9d5c | 148 | struct crypto_stat_hash rhash; |
cac5818c | 149 | |
9f4debe3 CL |
150 | memset(&rhash, 0, sizeof(rhash)); |
151 | ||
37db69e0 | 152 | strscpy(rhash.type, "shash", sizeof(rhash.type)); |
cac5818c | 153 | |
17c18f9e CL |
154 | rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt); |
155 | rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen); | |
44f13133 | 156 | rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt); |
cac5818c | 157 | |
37db69e0 | 158 | return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash); |
cac5818c CL |
159 | } |
160 | ||
161 | static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg) | |
162 | { | |
7f0a9d5c | 163 | struct crypto_stat_rng rrng; |
cac5818c | 164 | |
9f4debe3 CL |
165 | memset(&rrng, 0, sizeof(rrng)); |
166 | ||
37db69e0 | 167 | strscpy(rrng.type, "rng", sizeof(rrng.type)); |
cac5818c | 168 | |
17c18f9e CL |
169 | rrng.stat_generate_cnt = atomic64_read(&alg->stats.rng.generate_cnt); |
170 | rrng.stat_generate_tlen = atomic64_read(&alg->stats.rng.generate_tlen); | |
171 | rrng.stat_seed_cnt = atomic64_read(&alg->stats.rng.seed_cnt); | |
44f13133 | 172 | rrng.stat_err_cnt = atomic64_read(&alg->stats.rng.err_cnt); |
cac5818c | 173 | |
37db69e0 | 174 | return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng); |
cac5818c CL |
175 | } |
176 | ||
177 | static int crypto_reportstat_one(struct crypto_alg *alg, | |
178 | struct crypto_user_alg *ualg, | |
179 | struct sk_buff *skb) | |
180 | { | |
9f4debe3 CL |
181 | memset(ualg, 0, sizeof(*ualg)); |
182 | ||
37db69e0 EB |
183 | strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name)); |
184 | strscpy(ualg->cru_driver_name, alg->cra_driver_name, | |
cac5818c | 185 | sizeof(ualg->cru_driver_name)); |
37db69e0 | 186 | strscpy(ualg->cru_module_name, module_name(alg->cra_module), |
cac5818c CL |
187 | sizeof(ualg->cru_module_name)); |
188 | ||
189 | ualg->cru_type = 0; | |
190 | ualg->cru_mask = 0; | |
191 | ualg->cru_flags = alg->cra_flags; | |
192 | ualg->cru_refcnt = refcount_read(&alg->cra_refcnt); | |
193 | ||
194 | if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority)) | |
195 | goto nla_put_failure; | |
196 | if (alg->cra_flags & CRYPTO_ALG_LARVAL) { | |
7f0a9d5c | 197 | struct crypto_stat_larval rl; |
cac5818c | 198 | |
9f4debe3 | 199 | memset(&rl, 0, sizeof(rl)); |
37db69e0 EB |
200 | strscpy(rl.type, "larval", sizeof(rl.type)); |
201 | if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl)) | |
cac5818c CL |
202 | goto nla_put_failure; |
203 | goto out; | |
204 | } | |
205 | ||
206 | switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { | |
207 | case CRYPTO_ALG_TYPE_AEAD: | |
208 | if (crypto_report_aead(skb, alg)) | |
209 | goto nla_put_failure; | |
210 | break; | |
211 | case CRYPTO_ALG_TYPE_SKCIPHER: | |
212 | if (crypto_report_cipher(skb, alg)) | |
213 | goto nla_put_failure; | |
214 | break; | |
215 | case CRYPTO_ALG_TYPE_BLKCIPHER: | |
216 | if (crypto_report_cipher(skb, alg)) | |
217 | goto nla_put_failure; | |
218 | break; | |
219 | case CRYPTO_ALG_TYPE_CIPHER: | |
220 | if (crypto_report_cipher(skb, alg)) | |
221 | goto nla_put_failure; | |
222 | break; | |
223 | case CRYPTO_ALG_TYPE_COMPRESS: | |
224 | if (crypto_report_comp(skb, alg)) | |
225 | goto nla_put_failure; | |
226 | break; | |
227 | case CRYPTO_ALG_TYPE_ACOMPRESS: | |
228 | if (crypto_report_acomp(skb, alg)) | |
229 | goto nla_put_failure; | |
230 | break; | |
231 | case CRYPTO_ALG_TYPE_SCOMPRESS: | |
232 | if (crypto_report_acomp(skb, alg)) | |
233 | goto nla_put_failure; | |
234 | break; | |
235 | case CRYPTO_ALG_TYPE_AKCIPHER: | |
236 | if (crypto_report_akcipher(skb, alg)) | |
237 | goto nla_put_failure; | |
238 | break; | |
239 | case CRYPTO_ALG_TYPE_KPP: | |
240 | if (crypto_report_kpp(skb, alg)) | |
241 | goto nla_put_failure; | |
242 | break; | |
243 | case CRYPTO_ALG_TYPE_AHASH: | |
244 | if (crypto_report_ahash(skb, alg)) | |
245 | goto nla_put_failure; | |
246 | break; | |
247 | case CRYPTO_ALG_TYPE_HASH: | |
248 | if (crypto_report_shash(skb, alg)) | |
249 | goto nla_put_failure; | |
250 | break; | |
251 | case CRYPTO_ALG_TYPE_RNG: | |
252 | if (crypto_report_rng(skb, alg)) | |
253 | goto nla_put_failure; | |
254 | break; | |
255 | default: | |
256 | pr_err("ERROR: Unhandled alg %d in %s\n", | |
257 | alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL), | |
258 | __func__); | |
259 | } | |
260 | ||
261 | out: | |
262 | return 0; | |
263 | ||
264 | nla_put_failure: | |
265 | return -EMSGSIZE; | |
266 | } | |
267 | ||
268 | static int crypto_reportstat_alg(struct crypto_alg *alg, | |
269 | struct crypto_dump_info *info) | |
270 | { | |
271 | struct sk_buff *in_skb = info->in_skb; | |
272 | struct sk_buff *skb = info->out_skb; | |
273 | struct nlmsghdr *nlh; | |
274 | struct crypto_user_alg *ualg; | |
275 | int err = 0; | |
276 | ||
277 | nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq, | |
278 | CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags); | |
279 | if (!nlh) { | |
280 | err = -EMSGSIZE; | |
281 | goto out; | |
282 | } | |
283 | ||
284 | ualg = nlmsg_data(nlh); | |
285 | ||
286 | err = crypto_reportstat_one(alg, ualg, skb); | |
287 | if (err) { | |
288 | nlmsg_cancel(skb, nlh); | |
289 | goto out; | |
290 | } | |
291 | ||
292 | nlmsg_end(skb, nlh); | |
293 | ||
294 | out: | |
295 | return err; | |
296 | } | |
297 | ||
298 | int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, | |
299 | struct nlattr **attrs) | |
300 | { | |
301 | struct crypto_user_alg *p = nlmsg_data(in_nlh); | |
302 | struct crypto_alg *alg; | |
303 | struct sk_buff *skb; | |
304 | struct crypto_dump_info info; | |
305 | int err; | |
306 | ||
307 | if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name)) | |
308 | return -EINVAL; | |
309 | ||
310 | alg = crypto_alg_match(p, 0); | |
311 | if (!alg) | |
312 | return -ENOENT; | |
313 | ||
314 | err = -ENOMEM; | |
315 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | |
316 | if (!skb) | |
317 | goto drop_alg; | |
318 | ||
319 | info.in_skb = in_skb; | |
320 | info.out_skb = skb; | |
321 | info.nlmsg_seq = in_nlh->nlmsg_seq; | |
322 | info.nlmsg_flags = 0; | |
323 | ||
324 | err = crypto_reportstat_alg(alg, &info); | |
325 | ||
326 | drop_alg: | |
327 | crypto_mod_put(alg); | |
328 | ||
329 | if (err) | |
330 | return err; | |
331 | ||
332 | return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid); | |
333 | } | |
334 | ||
cac5818c | 335 | MODULE_LICENSE("GPL"); |