linux/crypto/crypto_user_stat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Crypto user configuration API.
   4 *
   5 * Copyright (C) 2017-2018 Corentin Labbe <clabbe@baylibre.com>
   6 *
   7 */
   8
   9#include <linux/crypto.h>
  10#include <linux/cryptouser.h>
  11#include <linux/sched.h>
  12#include <net/netlink.h>
  13#include <net/sock.h>
  14#include <crypto/internal/skcipher.h>
  15#include <crypto/internal/rng.h>
  16#include <crypto/akcipher.h>
  17#include <crypto/kpp.h>
  18#include <crypto/internal/cryptouser.h>
  19
  20#include "internal.h"
  21
  22#define null_terminated(x)      (strnlen(x, sizeof(x)) < sizeof(x))
  23
  24struct crypto_dump_info {
  25        struct sk_buff *in_skb;
  26        struct sk_buff *out_skb;
  27        u32 nlmsg_seq;
  28        u16 nlmsg_flags;
  29};
  30
  31static int crypto_report_aead(struct sk_buff *skb, struct crypto_alg *alg)
  32{
  33        struct crypto_stat_aead raead;
  34
  35        memset(&raead, 0, sizeof(raead));
  36
  37        strscpy(raead.type, "aead", sizeof(raead.type));
  38
  39        raead.stat_encrypt_cnt = atomic64_read(&alg->stats.aead.encrypt_cnt);
  40        raead.stat_encrypt_tlen = atomic64_read(&alg->stats.aead.encrypt_tlen);
  41        raead.stat_decrypt_cnt = atomic64_read(&alg->stats.aead.decrypt_cnt);
  42        raead.stat_decrypt_tlen = atomic64_read(&alg->stats.aead.decrypt_tlen);
  43        raead.stat_err_cnt = atomic64_read(&alg->stats.aead.err_cnt);
  44
  45        return nla_put(skb, CRYPTOCFGA_STAT_AEAD, sizeof(raead), &raead);
  46}
  47
  48static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
  49{
  50        struct crypto_stat_cipher rcipher;
  51
  52        memset(&rcipher, 0, sizeof(rcipher));
  53
  54        strscpy(rcipher.type, "cipher", sizeof(rcipher.type));
  55
  56        rcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.cipher.encrypt_cnt);
  57        rcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.cipher.encrypt_tlen);
  58        rcipher.stat_decrypt_cnt =  atomic64_read(&alg->stats.cipher.decrypt_cnt);
  59        rcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.cipher.decrypt_tlen);
  60        rcipher.stat_err_cnt =  atomic64_read(&alg->stats.cipher.err_cnt);
  61
  62        return nla_put(skb, CRYPTOCFGA_STAT_CIPHER, sizeof(rcipher), &rcipher);
  63}
  64
  65static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
  66{
  67        struct crypto_stat_compress rcomp;
  68
  69        memset(&rcomp, 0, sizeof(rcomp));
  70
  71        strscpy(rcomp.type, "compression", sizeof(rcomp.type));
  72        rcomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt);
  73        rcomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen);
  74        rcomp.stat_decompress_cnt = atomic64_read(&alg->stats.compress.decompress_cnt);
  75        rcomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen);
  76        rcomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
  77
  78        return nla_put(skb, CRYPTOCFGA_STAT_COMPRESS, sizeof(rcomp), &rcomp);
  79}
  80
  81static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
  82{
  83        struct crypto_stat_compress racomp;
  84
  85        memset(&racomp, 0, sizeof(racomp));
  86
  87        strscpy(racomp.type, "acomp", sizeof(racomp.type));
  88        racomp.stat_compress_cnt = atomic64_read(&alg->stats.compress.compress_cnt);
  89        racomp.stat_compress_tlen = atomic64_read(&alg->stats.compress.compress_tlen);
  90        racomp.stat_decompress_cnt =  atomic64_read(&alg->stats.compress.decompress_cnt);
  91        racomp.stat_decompress_tlen = atomic64_read(&alg->stats.compress.decompress_tlen);
  92        racomp.stat_err_cnt = atomic64_read(&alg->stats.compress.err_cnt);
  93
  94        return nla_put(skb, CRYPTOCFGA_STAT_ACOMP, sizeof(racomp), &racomp);
  95}
  96
  97static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
  98{
  99        struct crypto_stat_akcipher rakcipher;
 100
 101        memset(&rakcipher, 0, sizeof(rakcipher));
 102
 103        strscpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
 104        rakcipher.stat_encrypt_cnt = atomic64_read(&alg->stats.akcipher.encrypt_cnt);
 105        rakcipher.stat_encrypt_tlen = atomic64_read(&alg->stats.akcipher.encrypt_tlen);
 106        rakcipher.stat_decrypt_cnt = atomic64_read(&alg->stats.akcipher.decrypt_cnt);
 107        rakcipher.stat_decrypt_tlen = atomic64_read(&alg->stats.akcipher.decrypt_tlen);
 108        rakcipher.stat_sign_cnt = atomic64_read(&alg->stats.akcipher.sign_cnt);
 109        rakcipher.stat_verify_cnt = atomic64_read(&alg->stats.akcipher.verify_cnt);
 110        rakcipher.stat_err_cnt = atomic64_read(&alg->stats.akcipher.err_cnt);
 111
 112        return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER,
 113                       sizeof(rakcipher), &rakcipher);
 114}
 115
 116static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
 117{
 118        struct crypto_stat_kpp rkpp;
 119
 120        memset(&rkpp, 0, sizeof(rkpp));
 121
 122        strscpy(rkpp.type, "kpp", sizeof(rkpp.type));
 123
 124        rkpp.stat_setsecret_cnt = atomic64_read(&alg->stats.kpp.setsecret_cnt);
 125        rkpp.stat_generate_public_key_cnt = atomic64_read(&alg->stats.kpp.generate_public_key_cnt);
 126        rkpp.stat_compute_shared_secret_cnt = atomic64_read(&alg->stats.kpp.compute_shared_secret_cnt);
 127        rkpp.stat_err_cnt = atomic64_read(&alg->stats.kpp.err_cnt);
 128
 129        return nla_put(skb, CRYPTOCFGA_STAT_KPP, sizeof(rkpp), &rkpp);
 130}
 131
 132static int crypto_report_ahash(struct sk_buff *skb, struct crypto_alg *alg)
 133{
 134        struct crypto_stat_hash rhash;
 135
 136        memset(&rhash, 0, sizeof(rhash));
 137
 138        strscpy(rhash.type, "ahash", sizeof(rhash.type));
 139
 140        rhash.stat_hash_cnt = atomic64_read(&alg->stats.hash.hash_cnt);
 141        rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
 142        rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
 143
 144        return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
 145}
 146
 147static int crypto_report_shash(struct sk_buff *skb, struct crypto_alg *alg)
 148{
 149        struct crypto_stat_hash rhash;
 150
 151        memset(&rhash, 0, sizeof(rhash));
 152
 153        strscpy(rhash.type, "shash", sizeof(rhash.type));
 154
 155        rhash.stat_hash_cnt =  atomic64_read(&alg->stats.hash.hash_cnt);
 156        rhash.stat_hash_tlen = atomic64_read(&alg->stats.hash.hash_tlen);
 157        rhash.stat_err_cnt = atomic64_read(&alg->stats.hash.err_cnt);
 158
 159        return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
 160}
 161
 162static int crypto_report_rng(struct sk_buff *skb, struct crypto_alg *alg)
 163{
 164        struct crypto_stat_rng rrng;
 165
 166        memset(&rrng, 0, sizeof(rrng));
 167
 168        strscpy(rrng.type, "rng", sizeof(rrng.type));
 169
 170        rrng.stat_generate_cnt = atomic64_read(&alg->stats.rng.generate_cnt);
 171        rrng.stat_generate_tlen = atomic64_read(&alg->stats.rng.generate_tlen);
 172        rrng.stat_seed_cnt = atomic64_read(&alg->stats.rng.seed_cnt);
 173        rrng.stat_err_cnt = atomic64_read(&alg->stats.rng.err_cnt);
 174
 175        return nla_put(skb, CRYPTOCFGA_STAT_RNG, sizeof(rrng), &rrng);
 176}
 177
 178static int crypto_reportstat_one(struct crypto_alg *alg,
 179                                 struct crypto_user_alg *ualg,
 180                                 struct sk_buff *skb)
 181{
 182        memset(ualg, 0, sizeof(*ualg));
 183
 184        strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
 185        strscpy(ualg->cru_driver_name, alg->cra_driver_name,
 186                sizeof(ualg->cru_driver_name));
 187        strscpy(ualg->cru_module_name, module_name(alg->cra_module),
 188                sizeof(ualg->cru_module_name));
 189
 190        ualg->cru_type = 0;
 191        ualg->cru_mask = 0;
 192        ualg->cru_flags = alg->cra_flags;
 193        ualg->cru_refcnt = refcount_read(&alg->cra_refcnt);
 194
 195        if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
 196                goto nla_put_failure;
 197        if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
 198                struct crypto_stat_larval rl;
 199
 200                memset(&rl, 0, sizeof(rl));
 201                strscpy(rl.type, "larval", sizeof(rl.type));
 202                if (nla_put(skb, CRYPTOCFGA_STAT_LARVAL, sizeof(rl), &rl))
 203                        goto nla_put_failure;
 204                goto out;
 205        }
 206
 207        switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
 208        case CRYPTO_ALG_TYPE_AEAD:
 209                if (crypto_report_aead(skb, alg))
 210                        goto nla_put_failure;
 211                break;
 212        case CRYPTO_ALG_TYPE_SKCIPHER:
 213                if (crypto_report_cipher(skb, alg))
 214                        goto nla_put_failure;
 215                break;
 216        case CRYPTO_ALG_TYPE_CIPHER:
 217                if (crypto_report_cipher(skb, alg))
 218                        goto nla_put_failure;
 219                break;
 220        case CRYPTO_ALG_TYPE_COMPRESS:
 221                if (crypto_report_comp(skb, alg))
 222                        goto nla_put_failure;
 223                break;
 224        case CRYPTO_ALG_TYPE_ACOMPRESS:
 225                if (crypto_report_acomp(skb, alg))
 226                        goto nla_put_failure;
 227                break;
 228        case CRYPTO_ALG_TYPE_SCOMPRESS:
 229                if (crypto_report_acomp(skb, alg))
 230                        goto nla_put_failure;
 231                break;
 232        case CRYPTO_ALG_TYPE_AKCIPHER:
 233                if (crypto_report_akcipher(skb, alg))
 234                        goto nla_put_failure;
 235                break;
 236        case CRYPTO_ALG_TYPE_KPP:
 237                if (crypto_report_kpp(skb, alg))
 238                        goto nla_put_failure;
 239                break;
 240        case CRYPTO_ALG_TYPE_AHASH:
 241                if (crypto_report_ahash(skb, alg))
 242                        goto nla_put_failure;
 243                break;
 244        case CRYPTO_ALG_TYPE_HASH:
 245                if (crypto_report_shash(skb, alg))
 246                        goto nla_put_failure;
 247                break;
 248        case CRYPTO_ALG_TYPE_RNG:
 249                if (crypto_report_rng(skb, alg))
 250                        goto nla_put_failure;
 251                break;
 252        default:
 253                pr_err("ERROR: Unhandled alg %d in %s\n",
 254                       alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL),
 255                       __func__);
 256        }
 257
 258out:
 259        return 0;
 260
 261nla_put_failure:
 262        return -EMSGSIZE;
 263}
 264
 265static int crypto_reportstat_alg(struct crypto_alg *alg,
 266                                 struct crypto_dump_info *info)
 267{
 268        struct sk_buff *in_skb = info->in_skb;
 269        struct sk_buff *skb = info->out_skb;
 270        struct nlmsghdr *nlh;
 271        struct crypto_user_alg *ualg;
 272        int err = 0;
 273
 274        nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
 275                        CRYPTO_MSG_GETSTAT, sizeof(*ualg), info->nlmsg_flags);
 276        if (!nlh) {
 277                err = -EMSGSIZE;
 278                goto out;
 279        }
 280
 281        ualg = nlmsg_data(nlh);
 282
 283        err = crypto_reportstat_one(alg, ualg, skb);
 284        if (err) {
 285                nlmsg_cancel(skb, nlh);
 286                goto out;
 287        }
 288
 289        nlmsg_end(skb, nlh);
 290
 291out:
 292        return err;
 293}
 294
 295int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
 296                      struct nlattr **attrs)
 297{
 298        struct net *net = sock_net(in_skb->sk);
 299        struct crypto_user_alg *p = nlmsg_data(in_nlh);
 300        struct crypto_alg *alg;
 301        struct sk_buff *skb;
 302        struct crypto_dump_info info;
 303        int err;
 304
 305        if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
 306                return -EINVAL;
 307
 308        alg = crypto_alg_match(p, 0);
 309        if (!alg)
 310                return -ENOENT;
 311
 312        err = -ENOMEM;
 313        skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
 314        if (!skb)
 315                goto drop_alg;
 316
 317        info.in_skb = in_skb;
 318        info.out_skb = skb;
 319        info.nlmsg_seq = in_nlh->nlmsg_seq;
 320        info.nlmsg_flags = 0;
 321
 322        err = crypto_reportstat_alg(alg, &info);
 323
 324drop_alg:
 325        crypto_mod_put(alg);
 326
 327        if (err) {
 328                kfree_skb(skb);
 329                return err;
 330        }
 331
 332        return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 333}
 334
 335MODULE_LICENSE("GPL");
 336