xref: /openbmc/linux/crypto/crypto_user_stat.c (revision 4a075bd4)
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 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 {
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 
47 static 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 
64 static 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 
80 static 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 
96 static 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 
115 static 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 
131 static 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 
146 static 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 
161 static 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 
177 static 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 
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 
335 MODULE_LICENSE("GPL");
336