diff options
author | Corentin Labbe <clabbe@baylibre.com> | 2018-09-19 06:10:55 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-09-28 00:46:26 -0400 |
commit | a6f37cee6e4f6fa9d61962efbcb06a032efed1ba (patch) | |
tree | 72697266595402660c4a4d6e7a65a5a3a1f02768 /tools | |
parent | cac5818c25d0423bda73e2b6997404ed0a7ed9e3 (diff) |
crypto: tools - Add cryptostat userspace
This patch adds an userspace tool for displaying kernel crypto API
statistics.
Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/crypto/getstat.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/tools/crypto/getstat.c b/tools/crypto/getstat.c new file mode 100644 index 000000000000..24115173a483 --- /dev/null +++ b/tools/crypto/getstat.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* Heavily copied from libkcapi 2015 - 2017, Stephan Mueller <smueller@chronox.de> */ | ||
2 | #include <errno.h> | ||
3 | #include <linux/cryptouser.h> | ||
4 | #include <linux/netlink.h> | ||
5 | #include <linux/rtnetlink.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/socket.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <stdio.h> | ||
10 | #include <string.h> | ||
11 | #include <time.h> | ||
12 | #include <unistd.h> | ||
13 | |||
14 | #define CR_RTA(x) ((struct rtattr *)(((char *)(x)) + NLMSG_ALIGN(sizeof(struct crypto_user_alg)))) | ||
15 | |||
16 | static int get_stat(const char *drivername) | ||
17 | { | ||
18 | struct { | ||
19 | struct nlmsghdr n; | ||
20 | struct crypto_user_alg cru; | ||
21 | } req; | ||
22 | struct sockaddr_nl nl; | ||
23 | int sd = 0, ret; | ||
24 | socklen_t addr_len; | ||
25 | struct iovec iov; | ||
26 | struct msghdr msg; | ||
27 | char buf[4096]; | ||
28 | struct nlmsghdr *res_n = (struct nlmsghdr *)buf; | ||
29 | struct crypto_user_alg *cru_res = NULL; | ||
30 | int res_len = 0; | ||
31 | struct rtattr *tb[CRYPTOCFGA_MAX + 1]; | ||
32 | struct rtattr *rta; | ||
33 | struct nlmsgerr *errmsg; | ||
34 | |||
35 | memset(&req, 0, sizeof(req)); | ||
36 | memset(&buf, 0, sizeof(buf)); | ||
37 | memset(&msg, 0, sizeof(msg)); | ||
38 | |||
39 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.cru)); | ||
40 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
41 | req.n.nlmsg_type = CRYPTO_MSG_GETSTAT; | ||
42 | req.n.nlmsg_seq = time(NULL); | ||
43 | |||
44 | strncpy(req.cru.cru_driver_name, drivername, strlen(drivername)); | ||
45 | |||
46 | sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_CRYPTO); | ||
47 | if (sd < 0) { | ||
48 | fprintf(stderr, "Netlink error: cannot open netlink socket"); | ||
49 | return -errno; | ||
50 | } | ||
51 | memset(&nl, 0, sizeof(nl)); | ||
52 | nl.nl_family = AF_NETLINK; | ||
53 | if (bind(sd, (struct sockaddr *)&nl, sizeof(nl)) < 0) { | ||
54 | ret = -errno; | ||
55 | fprintf(stderr, "Netlink error: cannot bind netlink socket"); | ||
56 | goto out; | ||
57 | } | ||
58 | |||
59 | /* sanity check that netlink socket was successfully opened */ | ||
60 | addr_len = sizeof(nl); | ||
61 | if (getsockname(sd, (struct sockaddr *)&nl, &addr_len) < 0) { | ||
62 | ret = -errno; | ||
63 | printf("Netlink error: cannot getsockname"); | ||
64 | goto out; | ||
65 | } | ||
66 | if (addr_len != sizeof(nl)) { | ||
67 | ret = -errno; | ||
68 | printf("Netlink error: wrong address length %d", addr_len); | ||
69 | goto out; | ||
70 | } | ||
71 | if (nl.nl_family != AF_NETLINK) { | ||
72 | ret = -errno; | ||
73 | printf("Netlink error: wrong address family %d", | ||
74 | nl.nl_family); | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | memset(&nl, 0, sizeof(nl)); | ||
79 | nl.nl_family = AF_NETLINK; | ||
80 | iov.iov_base = (void *)&req.n; | ||
81 | iov.iov_len = req.n.nlmsg_len; | ||
82 | msg.msg_name = &nl; | ||
83 | msg.msg_namelen = sizeof(nl); | ||
84 | msg.msg_iov = &iov; | ||
85 | msg.msg_iovlen = 1; | ||
86 | if (sendmsg(sd, &msg, 0) < 0) { | ||
87 | ret = -errno; | ||
88 | printf("Netlink error: sendmsg failed"); | ||
89 | goto out; | ||
90 | } | ||
91 | memset(buf, 0, sizeof(buf)); | ||
92 | iov.iov_base = buf; | ||
93 | while (1) { | ||
94 | iov.iov_len = sizeof(buf); | ||
95 | ret = recvmsg(sd, &msg, 0); | ||
96 | if (ret < 0) { | ||
97 | if (errno == EINTR || errno == EAGAIN) | ||
98 | continue; | ||
99 | ret = -errno; | ||
100 | printf("Netlink error: netlink receive error"); | ||
101 | goto out; | ||
102 | } | ||
103 | if (ret == 0) { | ||
104 | ret = -errno; | ||
105 | printf("Netlink error: no data"); | ||
106 | goto out; | ||
107 | } | ||
108 | if (ret > sizeof(buf)) { | ||
109 | ret = -errno; | ||
110 | printf("Netlink error: received too much data"); | ||
111 | goto out; | ||
112 | } | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | ret = -EFAULT; | ||
117 | res_len = res_n->nlmsg_len; | ||
118 | if (res_n->nlmsg_type == NLMSG_ERROR) { | ||
119 | errmsg = NLMSG_DATA(res_n); | ||
120 | fprintf(stderr, "Fail with %d\n", errmsg->error); | ||
121 | ret = errmsg->error; | ||
122 | goto out; | ||
123 | } | ||
124 | |||
125 | if (res_n->nlmsg_type == CRYPTO_MSG_GETSTAT) { | ||
126 | cru_res = NLMSG_DATA(res_n); | ||
127 | res_len -= NLMSG_SPACE(sizeof(*cru_res)); | ||
128 | } | ||
129 | if (res_len < 0) { | ||
130 | printf("Netlink error: nlmsg len %d\n", res_len); | ||
131 | goto out; | ||
132 | } | ||
133 | |||
134 | if (!cru_res) { | ||
135 | ret = -EFAULT; | ||
136 | printf("Netlink error: no cru_res\n"); | ||
137 | goto out; | ||
138 | } | ||
139 | |||
140 | rta = CR_RTA(cru_res); | ||
141 | memset(tb, 0, sizeof(struct rtattr *) * (CRYPTOCFGA_MAX + 1)); | ||
142 | while (RTA_OK(rta, res_len)) { | ||
143 | if ((rta->rta_type <= CRYPTOCFGA_MAX) && (!tb[rta->rta_type])) | ||
144 | tb[rta->rta_type] = rta; | ||
145 | rta = RTA_NEXT(rta, res_len); | ||
146 | } | ||
147 | if (res_len) { | ||
148 | printf("Netlink error: unprocessed data %d", | ||
149 | res_len); | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | if (tb[CRYPTOCFGA_STAT_HASH]) { | ||
154 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_HASH]; | ||
155 | struct crypto_stat *rhash = | ||
156 | (struct crypto_stat *)RTA_DATA(rta); | ||
157 | printf("%s\tHash\n\tHash: %u bytes: %llu\n\tErrors: %u\n", | ||
158 | drivername, | ||
159 | rhash->stat_hash_cnt, rhash->stat_hash_tlen, | ||
160 | rhash->stat_hash_err_cnt); | ||
161 | } else if (tb[CRYPTOCFGA_STAT_COMPRESS]) { | ||
162 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_COMPRESS]; | ||
163 | struct crypto_stat *rblk = | ||
164 | (struct crypto_stat *)RTA_DATA(rta); | ||
165 | printf("%s\tCompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", | ||
166 | drivername, | ||
167 | rblk->stat_compress_cnt, rblk->stat_compress_tlen, | ||
168 | rblk->stat_decompress_cnt, rblk->stat_decompress_tlen, | ||
169 | rblk->stat_compress_err_cnt); | ||
170 | } else if (tb[CRYPTOCFGA_STAT_ACOMP]) { | ||
171 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_ACOMP]; | ||
172 | struct crypto_stat *rcomp = | ||
173 | (struct crypto_stat *)RTA_DATA(rta); | ||
174 | printf("%s\tACompress\n\tCompress: %u bytes: %llu\n\tDecompress: %u bytes: %llu\n\tErrors: %u\n", | ||
175 | drivername, | ||
176 | rcomp->stat_compress_cnt, rcomp->stat_compress_tlen, | ||
177 | rcomp->stat_decompress_cnt, rcomp->stat_decompress_tlen, | ||
178 | rcomp->stat_compress_err_cnt); | ||
179 | } else if (tb[CRYPTOCFGA_STAT_AEAD]) { | ||
180 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AEAD]; | ||
181 | struct crypto_stat *raead = | ||
182 | (struct crypto_stat *)RTA_DATA(rta); | ||
183 | printf("%s\tAEAD\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
184 | drivername, | ||
185 | raead->stat_encrypt_cnt, raead->stat_encrypt_tlen, | ||
186 | raead->stat_decrypt_cnt, raead->stat_decrypt_tlen, | ||
187 | raead->stat_aead_err_cnt); | ||
188 | } else if (tb[CRYPTOCFGA_STAT_BLKCIPHER]) { | ||
189 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_BLKCIPHER]; | ||
190 | struct crypto_stat *rblk = | ||
191 | (struct crypto_stat *)RTA_DATA(rta); | ||
192 | printf("%s\tCipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
193 | drivername, | ||
194 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
195 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
196 | rblk->stat_cipher_err_cnt); | ||
197 | } else if (tb[CRYPTOCFGA_STAT_AKCIPHER]) { | ||
198 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_AKCIPHER]; | ||
199 | struct crypto_stat *rblk = | ||
200 | (struct crypto_stat *)RTA_DATA(rta); | ||
201 | printf("%s\tAkcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tSign: %u\n\tVerify: %u\n\tErrors: %u\n", | ||
202 | drivername, | ||
203 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
204 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
205 | rblk->stat_sign_cnt, rblk->stat_verify_cnt, | ||
206 | rblk->stat_akcipher_err_cnt); | ||
207 | } else if (tb[CRYPTOCFGA_STAT_CIPHER]) { | ||
208 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_CIPHER]; | ||
209 | struct crypto_stat *rblk = | ||
210 | (struct crypto_stat *)RTA_DATA(rta); | ||
211 | printf("%s\tcipher\n\tEncrypt: %u bytes: %llu\n\tDecrypt: %u bytes: %llu\n\tErrors: %u\n", | ||
212 | drivername, | ||
213 | rblk->stat_encrypt_cnt, rblk->stat_encrypt_tlen, | ||
214 | rblk->stat_decrypt_cnt, rblk->stat_decrypt_tlen, | ||
215 | rblk->stat_cipher_err_cnt); | ||
216 | } else if (tb[CRYPTOCFGA_STAT_RNG]) { | ||
217 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_RNG]; | ||
218 | struct crypto_stat *rrng = | ||
219 | (struct crypto_stat *)RTA_DATA(rta); | ||
220 | printf("%s\tRNG\n\tSeed: %u\n\tGenerate: %u bytes: %llu\n\tErrors: %u\n", | ||
221 | drivername, | ||
222 | rrng->stat_seed_cnt, | ||
223 | rrng->stat_generate_cnt, rrng->stat_generate_tlen, | ||
224 | rrng->stat_rng_err_cnt); | ||
225 | } else if (tb[CRYPTOCFGA_STAT_KPP]) { | ||
226 | struct rtattr *rta = tb[CRYPTOCFGA_STAT_KPP]; | ||
227 | struct crypto_stat *rkpp = | ||
228 | (struct crypto_stat *)RTA_DATA(rta); | ||
229 | printf("%s\tKPP\n\tSetsecret: %u\n\tGenerate public key: %u\n\tCompute_shared_secret: %u\n\tErrors: %u\n", | ||
230 | drivername, | ||
231 | rkpp->stat_setsecret_cnt, | ||
232 | rkpp->stat_generate_public_key_cnt, | ||
233 | rkpp->stat_compute_shared_secret_cnt, | ||
234 | rkpp->stat_kpp_err_cnt); | ||
235 | } else { | ||
236 | fprintf(stderr, "%s is of an unknown algorithm\n", drivername); | ||
237 | } | ||
238 | ret = 0; | ||
239 | out: | ||
240 | close(sd); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | int main(int argc, const char *argv[]) | ||
245 | { | ||
246 | char buf[4096]; | ||
247 | FILE *procfd; | ||
248 | int i, lastspace; | ||
249 | int ret; | ||
250 | |||
251 | procfd = fopen("/proc/crypto", "r"); | ||
252 | if (!procfd) { | ||
253 | ret = errno; | ||
254 | fprintf(stderr, "Cannot open /proc/crypto %s\n", strerror(errno)); | ||
255 | return ret; | ||
256 | } | ||
257 | if (argc > 1) { | ||
258 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { | ||
259 | printf("Usage: %s [-h|--help] display this help\n", argv[0]); | ||
260 | printf("Usage: %s display all crypto statistics\n", argv[0]); | ||
261 | printf("Usage: %s drivername1 drivername2 ... = display crypto statistics about drivername1 ...\n", argv[0]); | ||
262 | return 0; | ||
263 | } | ||
264 | for (i = 1; i < argc; i++) { | ||
265 | ret = get_stat(argv[i]); | ||
266 | if (ret) { | ||
267 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); | ||
268 | return ret; | ||
269 | } | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | while (fgets(buf, sizeof(buf), procfd)) { | ||
275 | if (!strncmp(buf, "driver", 6)) { | ||
276 | lastspace = 0; | ||
277 | i = 0; | ||
278 | while (i < strlen(buf)) { | ||
279 | i++; | ||
280 | if (buf[i] == ' ') | ||
281 | lastspace = i; | ||
282 | } | ||
283 | buf[strlen(buf) - 1] = '\0'; | ||
284 | ret = get_stat(buf + lastspace + 1); | ||
285 | if (ret) { | ||
286 | fprintf(stderr, "Failed with %s\n", strerror(-ret)); | ||
287 | goto out; | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | out: | ||
292 | fclose(procfd); | ||
293 | return ret; | ||
294 | } | ||