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 } 295
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.