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