getstat.c 8.4 KB

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