This patch implement a generic way to get statistics about all crypto usages. Signed-off-by: Corentin Labbe <clabbe@xxxxxxxxxxxx> --- crypto/Kconfig | 11 +++ crypto/ahash.c | 18 +++++ crypto/algapi.c | 186 +++++++++++++++++++++++++++++++++++++++++++++ crypto/rng.c | 3 + include/crypto/acompress.h | 10 +++ include/crypto/akcipher.h | 12 +++ include/crypto/kpp.h | 9 +++ include/crypto/rng.h | 5 ++ include/crypto/skcipher.h | 8 ++ include/linux/crypto.h | 22 ++++++ 10 files changed, 284 insertions(+) diff --git a/crypto/Kconfig b/crypto/Kconfig index d6e9b60fc063..69f1822a026b 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1781,6 +1781,17 @@ config CRYPTO_USER_API_AEAD This option enables the user-spaces interface for AEAD cipher algorithms. +config CRYPTO_STATS + bool "Crypto usage statistics for User-space" + help + This option enables the gathering of crypto stats. + This will collect: + - encrypt/decrypt size and numbers of symmeric operations + - compress/decompress size and numbers of compress operations + - size and numbers of hash operations + - encrypt/decrypt/sign/verify numbers for asymmetric operations + - generate/seed numbers for rng operations + config CRYPTO_HASH_INFO bool diff --git a/crypto/ahash.c b/crypto/ahash.c index 3a35d67de7d9..93b56892f1b8 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -356,18 +356,36 @@ static int crypto_ahash_op(struct ahash_request *req, int crypto_ahash_final(struct ahash_request *req) { +#ifdef CONFIG_CRYPTO_STATS + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += req->nbytes; +#endif return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); } EXPORT_SYMBOL_GPL(crypto_ahash_final); int crypto_ahash_finup(struct ahash_request *req) { +#ifdef CONFIG_CRYPTO_STATS + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += req->nbytes; +#endif return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); } EXPORT_SYMBOL_GPL(crypto_ahash_finup); int crypto_ahash_digest(struct ahash_request *req) { +#ifdef CONFIG_CRYPTO_STATS + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += req->nbytes; +#endif return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest); } EXPORT_SYMBOL_GPL(crypto_ahash_digest); diff --git a/crypto/algapi.c b/crypto/algapi.c index b8f6122f37e9..4fca4576af78 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -20,11 +20,158 @@ #include <linux/rtnetlink.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/kobject.h> #include "internal.h" static LIST_HEAD(crypto_template_list); +#ifdef CONFIG_CRYPTO_STATS +static struct kobject *crypto_root_kobj; + +static struct kobj_type dynamic_kobj_ktype = { + .sysfs_ops = &kobj_sysfs_ops, +}; + +static ssize_t fcrypto_priority(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%d\n", alg->cra_priority); +} + +static ssize_t fcrypto_stat_enc_cnt(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->enc_cnt); +} + +static ssize_t fcrypto_stat_enc_tlen(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->enc_tlen); +} + +static ssize_t fcrypto_stat_dec_cnt(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->dec_cnt); +} + +static ssize_t fcrypto_stat_dec_tlen(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->dec_tlen); +} + +static ssize_t fcrypto_stat_verify_cnt(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->verify_cnt); +} + +static ssize_t fcrypto_stat_sign_cnt(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 9, "%lu\n", alg->sign_cnt); +} + +static ssize_t fcrypto_stat_type(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + u32 type; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + type = (alg->cra_flags & CRYPTO_ALG_TYPE_MASK); + if (type == CRYPTO_ALG_TYPE_ABLKCIPHER || + type == CRYPTO_ALG_TYPE_SKCIPHER || + type == CRYPTO_ALG_TYPE_CIPHER || + type == CRYPTO_ALG_TYPE_BLKCIPHER + ) + return snprintf(buf, 9, "cipher\n"); + if (type == CRYPTO_ALG_TYPE_AHASH || + type == CRYPTO_ALG_TYPE_HASH + ) + return snprintf(buf, 9, "hash\n"); + if (type == CRYPTO_ALG_TYPE_COMPRESS || + type == CRYPTO_ALG_TYPE_SCOMPRESS) + return snprintf(buf, 11, "compress\n"); + if (type == CRYPTO_ALG_TYPE_RNG) + return snprintf(buf, 9, "rng\n"); + if (type == CRYPTO_ALG_TYPE_AKCIPHER) + return snprintf(buf, 11, "asymetric\n"); + if (type == CRYPTO_ALG_TYPE_KPP) + return snprintf(buf, 4, "kpp\n"); + return snprintf(buf, 16, "unknown %x\n", type); +} + +static ssize_t fcrypto_stat_algname(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct crypto_alg *alg; + + alg = container_of(kobj, struct crypto_alg, cra_stat_obj); + return snprintf(buf, 32, "%s\n", alg->cra_name); +} + +static struct kobj_attribute crypto_stat_attribute_priority = + __ATTR(priority, 0444, fcrypto_priority, NULL); +static struct kobj_attribute crypto_stat_attribute_enc_cnt = + __ATTR(enc_cnt, 0444, fcrypto_stat_enc_cnt, NULL); +static struct kobj_attribute crypto_stat_attribute_enc_tlen = + __ATTR(enc_tlen, 0444, fcrypto_stat_enc_tlen, NULL); +static struct kobj_attribute crypto_stat_attribute_dec_cnt = + __ATTR(dec_cnt, 0444, fcrypto_stat_dec_cnt, NULL); +static struct kobj_attribute crypto_stat_attribute_dec_tlen = + __ATTR(dec_tlen, 0444, fcrypto_stat_dec_tlen, NULL); +static struct kobj_attribute crypto_stat_attribute_verify_cnt = + __ATTR(verify_cnt, 0444, fcrypto_stat_verify_cnt, NULL); +static struct kobj_attribute crypto_stat_attribute_sign_cnt = + __ATTR(sign_cnt, 0444, fcrypto_stat_sign_cnt, NULL); +static struct kobj_attribute crypto_stat_attribute_algtype = + __ATTR(algtype, 0444, fcrypto_stat_type, NULL); +static struct kobj_attribute crypto_stat_attribute_algname = + __ATTR(algname, 0444, fcrypto_stat_algname, NULL); + +static struct attribute *attrs[] = { + &crypto_stat_attribute_priority.attr, + &crypto_stat_attribute_enc_cnt.attr, + &crypto_stat_attribute_enc_tlen.attr, + &crypto_stat_attribute_dec_cnt.attr, + &crypto_stat_attribute_dec_tlen.attr, + &crypto_stat_attribute_verify_cnt.attr, + &crypto_stat_attribute_sign_cnt.attr, + &crypto_stat_attribute_algtype.attr, + &crypto_stat_attribute_algname.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; +#endif + static inline int crypto_set_driver_name(struct crypto_alg *alg) { static const char suffix[] = "-generic"; @@ -73,6 +220,9 @@ static void crypto_free_instance(struct crypto_instance *inst) inst->tmpl->free(inst); return; } +#ifdef CONFIG_CRYPTO_STATS + kobject_put(&inst->alg.cra_stat_obj); +#endif inst->alg.cra_type->free(inst); } @@ -237,6 +387,38 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) list_add(&alg->cra_list, &crypto_alg_list); list_add(&larval->alg.cra_list, &crypto_alg_list); +#ifdef CONFIG_CRYPTO_STATS + if (!crypto_root_kobj) { + pr_info("crypto: register crypto sysfs\n"); + crypto_root_kobj = kobject_create_and_add("crypto", + kernel_kobj); + if (!crypto_root_kobj) { + pr_err("crypto: register crypto class failed\n"); + ret = -ENOMEM; + goto err; + } + /* TODO class_destroy */ + } + + pr_debug("Register %s %s %p\n", alg->cra_name, alg->cra_driver_name, + alg->cra_type); + + ret = kobject_init_and_add(&alg->cra_stat_obj, &dynamic_kobj_ktype, + crypto_root_kobj, "%s", alg->cra_driver_name); + if (ret == 0) { + alg->enc_cnt = 0; + alg->dec_cnt = 0; + alg->enc_tlen = 0; + alg->dec_tlen = 0; + ret = sysfs_create_group(&alg->cra_stat_obj, &attr_group); + if (ret) { + pr_err("crypto: Failed to add stats for %s\n", + alg->cra_driver_name); + kobject_put(&alg->cra_stat_obj); + } + } +#endif + out: return larval; @@ -401,6 +583,10 @@ int crypto_unregister_alg(struct crypto_alg *alg) ret = crypto_remove_alg(alg, &list); up_write(&crypto_alg_sem); +#ifdef CONFIG_CRYPTO_STATS + kobject_put(&alg->cra_stat_obj); +#endif + if (ret) return ret; diff --git a/crypto/rng.c b/crypto/rng.c index b4a618668161..1e9d45c8e9b2 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -49,6 +49,9 @@ int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) seed = buf; } +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->dec_cnt++; +#endif err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); out: kzfree(buf); diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h index e328b52425a8..3a091fb914cf 100644 --- a/include/crypto/acompress.h +++ b/include/crypto/acompress.h @@ -247,6 +247,11 @@ static inline int crypto_acomp_compress(struct acomp_req *req) { struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += req->slen; +#endif + return tfm->compress(req); } @@ -263,6 +268,11 @@ static inline int crypto_acomp_decompress(struct acomp_req *req) { struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->dec_cnt++; + tfm->base.__crt_alg->dec_tlen += req->slen; +#endif + return tfm->decompress(req); } diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index b5e11de4d497..6a625f319fd0 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -286,6 +286,9 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->enc_cnt++; +#endif return alg->encrypt(req); } @@ -304,6 +307,9 @@ static inline int crypto_akcipher_decrypt(struct akcipher_request *req) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->dec_cnt++; +#endif return alg->decrypt(req); } @@ -322,6 +328,9 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->sign_cnt++; +#endif return alg->sign(req); } @@ -340,6 +349,9 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct akcipher_alg *alg = crypto_akcipher_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->verify_cnt++; +#endif return alg->verify(req); } diff --git a/include/crypto/kpp.h b/include/crypto/kpp.h index 1bde0a6514fa..d17a84e43b3c 100644 --- a/include/crypto/kpp.h +++ b/include/crypto/kpp.h @@ -288,6 +288,9 @@ static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, { struct kpp_alg *alg = crypto_kpp_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->dec_cnt++; +#endif return alg->set_secret(tfm, buffer, len); } @@ -309,6 +312,9 @@ static inline int crypto_kpp_generate_public_key(struct kpp_request *req) struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct kpp_alg *alg = crypto_kpp_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->enc_cnt++; +#endif return alg->generate_public_key(req); } @@ -327,6 +333,9 @@ static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct kpp_alg *alg = crypto_kpp_alg(tfm); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->verify_cnt++; +#endif return alg->compute_shared_secret(req); } diff --git a/include/crypto/rng.h b/include/crypto/rng.h index b95ede354a66..7893217b2fb5 100644 --- a/include/crypto/rng.h +++ b/include/crypto/rng.h @@ -140,6 +140,11 @@ static inline int crypto_rng_generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int dlen) { +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += dlen; +#endif + return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); } diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 562001cb412b..3b730384e27f 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -442,6 +442,10 @@ static inline int crypto_skcipher_encrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->enc_cnt++; + tfm->base.__crt_alg->enc_tlen += req->cryptlen; +#endif return tfm->encrypt(req); } @@ -460,6 +464,10 @@ static inline int crypto_skcipher_decrypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +#ifdef CONFIG_CRYPTO_STATS + tfm->base.__crt_alg->dec_cnt++; + tfm->base.__crt_alg->dec_tlen += req->cryptlen; +#endif return tfm->decrypt(req); } diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 78508ca4b108..18831a386c36 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -19,6 +19,7 @@ #include <linux/atomic.h> #include <linux/kernel.h> +#include <linux/kobject.h> #include <linux/list.h> #include <linux/bug.h> #include <linux/slab.h> @@ -466,6 +467,17 @@ struct crypto_alg { void (*cra_destroy)(struct crypto_alg *alg); struct module *cra_module; + +#ifdef CONFIG_CRYPTO_STATS + struct kobject cra_stat_obj; + /* enc is for encrypt / compress/ hash / generate, + * dec is decrypt / decompress / seed + */ + unsigned long enc_cnt, dec_cnt; + unsigned long enc_tlen, dec_tlen; + unsigned long verify_cnt; + unsigned long sign_cnt; +#endif } CRYPTO_MINALIGN_ATTR; /* @@ -901,6 +913,11 @@ static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req) { struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + +#ifdef CONFIG_CRYPTO_STATS + crt->base->base.__crt_alg->enc_cnt++; + crt->base->base.__crt_alg->enc_tlen += req->nbytes; +#endif return crt->encrypt(req); } @@ -919,6 +936,11 @@ static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req) { struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + +#ifdef CONFIG_CRYPTO_STATS + crt->base->base.__crt_alg->dec_cnt++; + crt->base->base.__crt_alg->dec_tlen += req->nbytes; +#endif return crt->decrypt(req); } -- 2.13.6