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
23struct 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
30static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg)
31{
32 struct crypto_stat_aead raead;
33
34 memset(&raead, 0, sizeof(raead));
35
36 strscpy(raead.type, "aead", sizeof(raead.type));
37
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);
42 raead.stat_err_cnt = atomic64_read(&alg->stats.aead.err_cnt);
43
44 return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead);
45}
46
47static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
48{
49 struct crypto_stat_cipher rcipher;
50
51 memset(&rcipher, 0, sizeof(rcipher));
52
53 strscpy(rcipher.type, "cipher", sizeof(rcipher.type));
54
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);
59 rcipher.stat_err_cnt = atomic64_read(&alg->stats.cipher.err_cnt);
60
61 return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher);
62}
63
64static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
65{
66 struct crypto_stat_compress rcomp;
67
68 memset(&rcomp, 0, sizeof(rcomp));
69
70 strscpy(rcomp.type, "compression", sizeof(rcomp.type));
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);
75 rcomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
76
77 return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp);
78}
79
80static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
81{
82 struct crypto_stat_compress racomp;
83
84 memset(&racomp, 0, sizeof(racomp));
85
86 strscpy(racomp.type, "acomp", sizeof(racomp.type));
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);
91 racomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
92
93 return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp);
94}
95
96static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
97{
98 struct crypto_stat_akcipher rakcipher;
99
100 memset(&rakcipher, 0, sizeof(rakcipher));
101
102 strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
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);
109 rakcipher.stat_err_cnt = atomic64_read(&alg->stats.akcipher.err_cnt);
110
111 return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
112 sizeof(rakcipher), &rakcipher);
113}
114
115static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
116{
117 struct crypto_stat_kpp rkpp;
118
119 memset(&rkpp, 0, sizeof(rkpp));
120
121 strscpy(rkpp.type, "kpp", sizeof(rkpp.type));
122
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);
126 rkpp.stat_err_cnt = atomic64_read(&alg->stats.kpp.err_cnt);
127
128 return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp);
129}
130
131static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
132{
133 struct crypto_stat_hash rhash;
134
135 memset(&rhash, 0, sizeof(rhash));
136
137 strscpy(rhash.type, "ahash", sizeof(rhash.type));
138
139 rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
140 rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
141 rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
142
143 return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
144}
145
146static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
147{
148 struct crypto_stat_hash rhash;
149
150 memset(&rhash, 0, sizeof(rhash));
151
152 strscpy(rhash.type, "shash", sizeof(rhash.type));
153
154 rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
155 rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
156 rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
157
158 return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
159}
160
161static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
162{
163 struct crypto_stat_rng rrng;
164
165 memset(&rrng, 0, sizeof(rrng));
166
167 strscpy(rrng.type, "rng", sizeof(rrng.type));
168
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);
172 rrng.stat_err_cnt = atomic64_read(&alg->stats.rng.err_cnt);
173
174 return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng);
175}
176
177static int crypto_reportstat_one(struct crypto_alg *alg,
178 struct crypto_user_alg *ualg,
179 struct sk_buff *skb)
180{
181 memset(ualg, 0, sizeof(*ualg));
182
183 strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
184 strscpy(ualg->cru_driver_name, alg->cra_driver_name,
185 sizeof(ualg->cru_driver_name));
186 strscpy(ualg->cru_module_name, module_name(alg->cra_module),
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) {
197 struct crypto_stat_larval rl;
198
199 memset(&rl, 0, sizeof(rl));
200 strscpy(rl.type, "larval", sizeof(rl.type));
201 if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl))
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
261out:
262 return 0;
263
264nla_put_failure:
265 return -EMSGSIZE;
266}
267
268static 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
294out:
295 return err;
296}
297
298int 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
326drop_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
335MODULE_LICENSE("GPL");
336