Skip to content

Commit

Permalink
crypto: hash - Count error stats differently
Browse files Browse the repository at this point in the history
Move all stat code specific to hash into the hash code.

While we're at it, change the stats so that bytes and counts
are always incremented even in case of error.  This allows the
reference counting to be removed as we can now increment the
counters prior to the operation.

After the operation we simply increase the error count if necessary.
This is safe as errors can only occur synchronously (or rather,
the existing code already ignored asynchronous errors which are
only visible to the callback function).

Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
herbertx committed Mar 14, 2023
1 parent 035d78a commit 42808e5
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 157 deletions.
81 changes: 48 additions & 33 deletions crypto/ahash.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@
* Copyright (c) 2008 Loc Ho <[email protected]>
*/

#include <crypto/internal/hash.h>
#include <crypto/scatterwalk.h>
#include <linux/cryptouser.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/cryptouser.h>
#include <linux/compiler.h>
#include <linux/string.h>
#include <net/netlink.h>

#include "internal.h"
#include "hash.h"

static const struct crypto_type crypto_ahash_type;

Expand Down Expand Up @@ -296,55 +295,60 @@ static int crypto_ahash_op(struct ahash_request *req,
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
unsigned long alignmask = crypto_ahash_alignmask(tfm);
int err;

if ((unsigned long)req->result & alignmask)
return ahash_op_unaligned(req, op, has_state);
err = ahash_op_unaligned(req, op, has_state);
else
err = op(req);

return op(req);
return crypto_hash_errstat(crypto_hash_alg_common(tfm), err);
}

int crypto_ahash_final(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct crypto_alg *alg = tfm->base.__crt_alg;
unsigned int nbytes = req->nbytes;
int ret;
struct hash_alg_common *alg = crypto_hash_alg_common(tfm);

crypto_stats_get(alg);
ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final, true);
crypto_stats_ahash_final(nbytes, ret, alg);
return ret;
if (IS_ENABLED(CONFIG_CRYPTO_STATS))
atomic64_inc(&hash_get_stat(alg)->hash_cnt);

return crypto_ahash_op(req, tfm->final, true);
}
EXPORT_SYMBOL_GPL(crypto_ahash_final);

int crypto_ahash_finup(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct crypto_alg *alg = tfm->base.__crt_alg;
unsigned int nbytes = req->nbytes;
int ret;
struct hash_alg_common *alg = crypto_hash_alg_common(tfm);

crypto_stats_get(alg);
ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup, true);
crypto_stats_ahash_final(nbytes, ret, alg);
return ret;
if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
struct crypto_istat_hash *istat = hash_get_stat(alg);

atomic64_inc(&istat->hash_cnt);
atomic64_add(req->nbytes, &istat->hash_tlen);
}

return crypto_ahash_op(req, tfm->finup, true);
}
EXPORT_SYMBOL_GPL(crypto_ahash_finup);

int crypto_ahash_digest(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct crypto_alg *alg = tfm->base.__crt_alg;
unsigned int nbytes = req->nbytes;
int ret;
struct hash_alg_common *alg = crypto_hash_alg_common(tfm);

if (IS_ENABLED(CONFIG_CRYPTO_STATS)) {
struct crypto_istat_hash *istat = hash_get_stat(alg);

atomic64_inc(&istat->hash_cnt);
atomic64_add(req->nbytes, &istat->hash_tlen);
}

crypto_stats_get(alg);
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
ret = -ENOKEY;
else
ret = crypto_ahash_op(req, tfm->digest, false);
crypto_stats_ahash_final(nbytes, ret, alg);
return ret;
return crypto_hash_errstat(alg, -ENOKEY);

return crypto_ahash_op(req, tfm->digest, false);
}
EXPORT_SYMBOL_GPL(crypto_ahash_digest);

Expand Down Expand Up @@ -498,6 +502,12 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
__crypto_hash_alg_common(alg)->digestsize);
}

static int __maybe_unused crypto_ahash_report_stat(
struct sk_buff *skb, struct crypto_alg *alg)
{
return crypto_hash_report_stat(skb, alg, "ahash");
}

static const struct crypto_type crypto_ahash_type = {
.extsize = crypto_ahash_extsize,
.init_tfm = crypto_ahash_init_tfm,
Expand All @@ -506,6 +516,9 @@ static const struct crypto_type crypto_ahash_type = {
.show = crypto_ahash_show,
#endif
.report = crypto_ahash_report,
#ifdef CONFIG_CRYPTO_STATS
.report_stat = crypto_ahash_report_stat,
#endif
.maskclear = ~CRYPTO_ALG_TYPE_MASK,
.maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
.type = CRYPTO_ALG_TYPE_AHASH,
Expand Down Expand Up @@ -537,14 +550,16 @@ EXPORT_SYMBOL_GPL(crypto_has_ahash);
static int ahash_prepare_alg(struct ahash_alg *alg)
{
struct crypto_alg *base = &alg->halg.base;
int err;

if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE ||
alg->halg.statesize > HASH_MAX_STATESIZE ||
alg->halg.statesize == 0)
if (alg->halg.statesize == 0)
return -EINVAL;

err = hash_prepare_alg(&alg->halg);
if (err)
return err;

base->cra_type = &crypto_ahash_type;
base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;

return 0;
Expand Down
24 changes: 0 additions & 24 deletions crypto/algapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,30 +1075,6 @@ void crypto_stats_decompress(unsigned int slen, int ret, struct crypto_alg *alg)
}
EXPORT_SYMBOL_GPL(crypto_stats_decompress);

void crypto_stats_ahash_update(unsigned int nbytes, int ret,
struct crypto_alg *alg)
{
if (ret && ret != -EINPROGRESS && ret != -EBUSY)
atomic64_inc(&alg->stats.hash.err_cnt);
else
atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
crypto_alg_put(alg);
}
EXPORT_SYMBOL_GPL(crypto_stats_ahash_update);

void crypto_stats_ahash_final(unsigned int nbytes, int ret,
struct crypto_alg *alg)
{
if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
atomic64_inc(&alg->stats.hash.err_cnt);
} else {
atomic64_inc(&alg->stats.hash.hash_cnt);
atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
}
crypto_alg_put(alg);
}
EXPORT_SYMBOL_GPL(crypto_stats_ahash_final);

void crypto_stats_kpp_set_secret(struct crypto_alg *alg, int ret)
{
if (ret)
Expand Down
38 changes: 0 additions & 38 deletions crypto/crypto_user_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,36 +92,6 @@ static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp);
}

static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_stat_hash rhash;

memset(&rhash, 0, sizeof(rhash));

strscpy(rhash.type, "ahash", sizeof(rhash.type));

rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);

return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
}

static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_stat_hash rhash;

memset(&rhash, 0, sizeof(rhash));

strscpy(rhash.type, "shash", sizeof(rhash.type));

rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);

return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
}

static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
{
struct crypto_stat_rng rrng;
Expand Down Expand Up @@ -198,14 +168,6 @@ static int crypto_reportstat_one(struct crypto_alg *alg,
if (crypto_report_kpp(skb, alg))
goto nla_put_failure;
break;
case CRYPTO_ALG_TYPE_AHASH:
if (crypto_report_ahash(skb, alg))
goto nla_put_failure;
break;
case CRYPTO_ALG_TYPE_HASH:
if (crypto_report_shash(skb, alg))
goto nla_put_failure;
break;
case CRYPTO_ALG_TYPE_RNG:
if (crypto_report_rng(skb, alg))
goto nla_put_failure;
Expand Down
36 changes: 36 additions & 0 deletions crypto/hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Cryptographic API.
*
* Copyright (c) 2023 Herbert Xu <[email protected]>
*/
#ifndef _LOCAL_CRYPTO_HASH_H
#define _LOCAL_CRYPTO_HASH_H

#include <crypto/internal/hash.h>
#include <linux/cryptouser.h>

#include "internal.h"

static inline int crypto_hash_report_stat(struct sk_buff *skb,
struct crypto_alg *alg,
const char *type)
{
struct hash_alg_common *halg = __crypto_hash_alg_common(alg);
struct crypto_istat_hash *istat = hash_get_stat(halg);
struct crypto_stat_hash rhash;

memset(&rhash, 0, sizeof(rhash));

strscpy(rhash.type, type, sizeof(rhash.type));

rhash.stat_hash_cnt = atomic64_read(&istat->hash_cnt);
rhash.stat_hash_tlen = atomic64_read(&istat->hash_tlen);
rhash.stat_err_cnt = atomic64_read(&istat->err_cnt);

return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
}

int hash_prepare_alg(struct hash_alg_common *alg);

#endif /* _LOCAL_CRYPTO_HASH_H */
Loading

0 comments on commit 42808e5

Please sign in to comment.