cregit-Linux how code gets into the kernel

Release 4.15 crypto/api.c

Directory: crypto
/*
 * Scatterlist Cryptographic API.
 *
 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
 *
 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
 * and Nettle, by Niels Möller.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */

#include <linux/err.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/module.h>
#include <linux/param.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/completion.h>
#include "internal.h"


LIST_HEAD(crypto_alg_list);

EXPORT_SYMBOL_GPL(crypto_alg_list);

DECLARE_RWSEM(crypto_alg_sem);

EXPORT_SYMBOL_GPL(crypto_alg_sem);


BLOCKING_NOTIFIER_HEAD(crypto_chain);

EXPORT_SYMBOL_GPL(crypto_chain);

static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg);


struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) { return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
James Morris1555.56%240.00%
Herbert Xu1140.74%240.00%
Christoph Hellwig13.70%120.00%
Total27100.00%5100.00%

EXPORT_SYMBOL_GPL(crypto_mod_get);
void crypto_mod_put(struct crypto_alg *alg) { struct module *module = alg->cra_module; crypto_alg_put(alg); module_put(module); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu1655.17%350.00%
James Morris1241.38%233.33%
Christoph Hellwig13.45%116.67%
Total29100.00%6100.00%

EXPORT_SYMBOL_GPL(crypto_mod_put);
static inline int crypto_is_test_larval(struct crypto_larval *larval) { return larval->alg.cra_driver_name[0]; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu22100.00%1100.00%
Total22100.00%1100.00%


static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *q, *alg = NULL; int best = -2; list_for_each_entry(q, &crypto_alg_list, cra_list) { int exact, fuzzy; if (crypto_is_moribund(q)) continue; if ((q->cra_flags ^ type) & mask) continue; if (crypto_is_larval(q) && !crypto_is_test_larval((struct crypto_larval *)q) && ((struct crypto_larval *)q)->mask != mask) continue; exact = !strcmp(q->cra_driver_name, name); fuzzy = !strcmp(q->cra_name, name); if (!exact && !(fuzzy && q->cra_priority > best)) continue; if (unlikely(!crypto_mod_get(q))) continue; best = q->cra_priority; if (alg) crypto_mod_put(alg); alg = q; if (exact) break; } return alg; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu13171.58%758.33%
James Morris5228.42%541.67%
Total183100.00%12100.00%


static void crypto_larval_destroy(struct crypto_alg *alg) { struct crypto_larval *larval = (void *)alg; BUG_ON(!crypto_is_larval(alg)); if (larval->adult) crypto_mod_put(larval->adult); kfree(larval); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu49100.00%1100.00%
Total49100.00%1100.00%


struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask) { struct crypto_larval *larval; larval = kzalloc(sizeof(*larval), GFP_KERNEL); if (!larval) return ERR_PTR(-ENOMEM); larval->mask = mask; larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; larval->alg.cra_priority = -1; larval->alg.cra_destroy = crypto_larval_destroy; strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); init_completion(&larval->completion); return larval; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu105100.00%4100.00%
Total105100.00%4100.00%

EXPORT_SYMBOL_GPL(crypto_larval_alloc);
static struct crypto_alg *crypto_larval_add(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; struct crypto_larval *larval; larval = crypto_larval_alloc(name, type, mask); if (IS_ERR(larval)) return ERR_CAST(larval); atomic_set(&larval->alg.cra_refcnt, 2); down_write(&crypto_alg_sem); alg = __crypto_alg_lookup(name, type, mask); if (!alg) { alg = &larval->alg; list_add(&alg->cra_list, &crypto_alg_list); } up_write(&crypto_alg_sem); if (alg != &larval->alg) { kfree(larval); if (crypto_is_larval(alg)) alg = crypto_larval_wait(alg); } return alg; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu146100.00%4100.00%
Total146100.00%4100.00%


void crypto_larval_kill(struct crypto_alg *alg) { struct crypto_larval *larval = (void *)alg; down_write(&crypto_alg_sem); list_del(&alg->cra_list); up_write(&crypto_alg_sem); complete_all(&larval->completion); crypto_alg_put(alg); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu54100.00%2100.00%
Total54100.00%2100.00%

EXPORT_SYMBOL_GPL(crypto_larval_kill);
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) { struct crypto_larval *larval = (void *)alg; long timeout; timeout = wait_for_completion_killable_timeout( &larval->completion, 60 * HZ); alg = larval->adult; if (timeout < 0) alg = ERR_PTR(-EINTR); else if (!timeout) alg = ERR_PTR(-ETIMEDOUT); else if (!alg) alg = ERR_PTR(-ENOENT); else if (crypto_is_test_larval(larval) && !(alg->cra_flags & CRYPTO_ALG_TESTED)) alg = ERR_PTR(-EAGAIN); else if (!crypto_mod_get(alg)) alg = ERR_PTR(-EAGAIN); crypto_mod_put(&larval->alg); return alg; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu142100.00%4100.00%
Total142100.00%4100.00%


struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; down_read(&crypto_alg_sem); alg = __crypto_alg_lookup(name, type, mask); up_read(&crypto_alg_sem); return alg; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu3979.59%250.00%
James Morris1020.41%250.00%
Total49100.00%4100.00%

EXPORT_SYMBOL_GPL(crypto_alg_lookup);
struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; if (!name) return ERR_PTR(-ENOENT); type &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); alg = crypto_alg_lookup(name, type, mask); if (!alg) { request_module("crypto-%s", name); if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & CRYPTO_ALG_NEED_FALLBACK)) request_module("crypto-%s-all", name); alg = crypto_alg_lookup(name, type, mask); } if (alg) return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; return crypto_larval_add(name, type, mask); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu11684.06%872.73%
Adrian Bunk1712.32%19.09%
Alex Riesen32.17%19.09%
Kees Cook21.45%19.09%
Total138100.00%11100.00%

EXPORT_SYMBOL_GPL(crypto_larval_lookup);
int crypto_probing_notify(unsigned long val, void *v) { int ok; ok = blocking_notifier_call_chain(&crypto_chain, val, v); if (ok == NOTIFY_DONE) { request_module("cryptomgr"); ok = blocking_notifier_call_chain(&crypto_chain, val, v); } return ok; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu56100.00%1100.00%
Total56100.00%1100.00%

EXPORT_SYMBOL_GPL(crypto_probing_notify);
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; struct crypto_alg *larval; int ok; if (!((type | mask) & CRYPTO_ALG_TESTED)) { type |= CRYPTO_ALG_TESTED; mask |= CRYPTO_ALG_TESTED; } /* * If the internal flag is set for a cipher, require a caller to * to invoke the cipher with the internal flag to use that cipher. * Also, if a caller wants to allocate a cipher that may or may * not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and * !(mask & CRYPTO_ALG_INTERNAL). */ if (!((type | mask) & CRYPTO_ALG_INTERNAL)) mask |= CRYPTO_ALG_INTERNAL; larval = crypto_larval_lookup(name, type, mask); if (IS_ERR(larval) || !crypto_is_larval(larval)) return larval; ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval); if (ok == NOTIFY_STOP) alg = crypto_larval_wait(larval); else { crypto_mod_put(larval); alg = ERR_PTR(-ENOENT); } crypto_larval_kill(larval); return alg; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu12586.21%777.78%
Stephan Mueller1812.41%111.11%
Adrian Bunk21.38%111.11%
Total145100.00%9100.00%

EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; if (type_obj) return type_obj->init(tfm, type, mask); switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: return crypto_init_cipher_ops(tfm); case CRYPTO_ALG_TYPE_COMPRESS: return crypto_init_compress_ops(tfm); default: break; } BUG(); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
James Morris4758.02%571.43%
Herbert Xu3441.98%228.57%
Total81100.00%7100.00%


static void crypto_exit_ops(struct crypto_tfm *tfm) { const struct crypto_type *type = tfm->__crt_alg->cra_type; if (type && tfm->exit) tfm->exit(tfm); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2668.42%240.00%
James Morris1128.95%240.00%
Eric Biggers12.63%120.00%
Total38100.00%5100.00%


static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { const struct crypto_type *type_obj = alg->cra_type; unsigned int len; len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); if (type_obj) return len + type_obj->ctxsize(alg, type, mask); switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { default: BUG(); case CRYPTO_ALG_TYPE_CIPHER: len += crypto_cipher_ctxsize(alg); break; case CRYPTO_ALG_TYPE_COMPRESS: len += crypto_compress_ctxsize(alg); break; } return len; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu103100.00%3100.00%
Total103100.00%3100.00%


void crypto_shoot_alg(struct crypto_alg *alg) { down_write(&crypto_alg_sem); alg->cra_flags |= CRYPTO_ALG_DYING; up_write(&crypto_alg_sem); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu28100.00%1100.00%
Total28100.00%1100.00%

EXPORT_SYMBOL_GPL(crypto_shoot_alg);
struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, u32 mask) { struct crypto_tfm *tfm = NULL; unsigned int tfm_size; int err = -ENOMEM; tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) goto out_err; tfm->__crt_alg = alg; err = crypto_init_ops(tfm, type, mask); if (err) goto out_free_tfm; if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) goto cra_init_failed; goto out; cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: if (err == -EAGAIN) crypto_shoot_alg(alg); kfree(tfm); out_err: tfm = ERR_PTR(err); out: return tfm; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu9458.02%535.71%
James Morris5835.80%535.71%
Akinobu Mita31.85%17.14%
David S. Miller31.85%17.14%
Adam J. Richter31.85%17.14%
Eric Sesterhenn / Snakebyte10.62%17.14%
Total162100.00%14100.00%

EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); /* * crypto_alloc_base - Locate algorithm and allocate transform * @alg_name: Name of algorithm * @type: Type of algorithm * @mask: Mask for type comparison * * This function should not be used by new algorithm types. * Please use crypto_alloc_tfm instead. * * crypto_alloc_base() will first attempt to locate an already loaded * algorithm. If that fails and the kernel supports dynamically loadable * modules, it will then attempt to load a module of the same name or * alias. If that fails it will send a query to any loaded crypto manager * to construct an algorithm on the fly. A refcount is grabbed on the * algorithm which is then associated with the new transform. * * The returned transform is of a non-determinate type. Most people * should use one of the more specific allocation functions such as * crypto_alloc_blkcipher. * * In case of error the return value is an error pointer. */
struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) { struct crypto_tfm *tfm; int err; for (;;) { struct crypto_alg *alg; alg = crypto_alg_mod_lookup(alg_name, type, mask); if (IS_ERR(alg)) { err = PTR_ERR(alg); goto err; } tfm = __crypto_alloc_tfm(alg, type, mask); if (!IS_ERR(tfm)) return tfm; crypto_mod_put(alg); err = PTR_ERR(tfm); err: if (err != -EAGAIN) break; if (fatal_signal_pending(current)) { err = -EINTR; break; } } return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu11787.97%375.00%
Akinobu Mita1612.03%125.00%
Total133100.00%4100.00%

EXPORT_SYMBOL_GPL(crypto_alloc_base);
void *crypto_create_tfm(struct crypto_alg *alg, const struct crypto_type *frontend) { char *mem; struct crypto_tfm *tfm = NULL; unsigned int tfmsize; unsigned int total; int err = -ENOMEM; tfmsize = frontend->tfmsize; total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); mem = kzalloc(total, GFP_KERNEL); if (mem == NULL) goto out_err; tfm = (struct crypto_tfm *)(mem + tfmsize); tfm->__crt_alg = alg; err = frontend->init_tfm(tfm); if (err) goto out_free_tfm; if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) goto cra_init_failed; goto out; cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: if (err == -EAGAIN) crypto_shoot_alg(alg); kfree(mem); out_err: mem = ERR_PTR(err); out: return mem; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu186100.00%2100.00%
Total186100.00%2100.00%

EXPORT_SYMBOL_GPL(crypto_create_tfm);
struct crypto_alg *crypto_find_alg(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask) { struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) = crypto_alg_mod_lookup; if (frontend) { type &= frontend->maskclear; mask &= frontend->maskclear; type |= frontend->type; mask |= frontend->maskset; if (frontend->lookup) lookup = frontend->lookup; } return lookup(alg_name, type, mask); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu98100.00%2100.00%
Total98100.00%2100.00%

EXPORT_SYMBOL_GPL(crypto_find_alg); /* * crypto_alloc_tfm - Locate algorithm and allocate transform * @alg_name: Name of algorithm * @frontend: Frontend algorithm type * @type: Type of algorithm * @mask: Mask for type comparison * * crypto_alloc_tfm() will first attempt to locate an already loaded * algorithm. If that fails and the kernel supports dynamically loadable * modules, it will then attempt to load a module of the same name or * alias. If that fails it will send a query to any loaded crypto manager * to construct an algorithm on the fly. A refcount is grabbed on the * algorithm which is then associated with the new transform. * * The returned transform is of a non-determinate type. Most people * should use one of the more specific allocation functions such as * crypto_alloc_blkcipher. * * In case of error the return value is an error pointer. */
void *crypto_alloc_tfm(const char *alg_name, const struct crypto_type *frontend, u32 type, u32 mask) { void *tfm; int err; for (;;) { struct crypto_alg *alg; alg = crypto_find_alg(alg_name, frontend, type, mask); if (IS_ERR(alg)) { err = PTR_ERR(alg); goto err; } tfm = crypto_create_tfm(alg, frontend); if (!IS_ERR(tfm)) return tfm; crypto_mod_put(alg); err = PTR_ERR(tfm); err: if (err != -EAGAIN) break; if (fatal_signal_pending(current)) { err = -EINTR; break; } } return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu137100.00%3100.00%
Total137100.00%3100.00%

EXPORT_SYMBOL_GPL(crypto_alloc_tfm); /* * crypto_destroy_tfm - Free crypto transform * @mem: Start of tfm slab * @tfm: Transform to free * * This function frees up the transform and any associated resources, * then drops the refcount on the associated algorithm. */
void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) { struct crypto_alg *alg; if (unlikely(!mem)) return; alg = tfm->__crt_alg; if (!tfm->exit && alg->cra_exit) alg->cra_exit(tfm); crypto_exit_ops(tfm); crypto_mod_put(alg); kzfree(mem); }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu2638.81%436.36%
James Morris1826.87%436.36%
Jesper Juhl1217.91%19.09%
David S. Miller1014.93%19.09%
Johannes Weiner11.49%19.09%
Total67100.00%11100.00%

EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
int crypto_has_alg(const char *name, u32 type, u32 mask) { int ret = 0; struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask); if (!IS_ERR(alg)) { crypto_mod_put(alg); ret = 1; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu57100.00%1100.00%
Total57100.00%1100.00%

EXPORT_SYMBOL_GPL(crypto_has_alg);
void crypto_req_done(struct crypto_async_request *req, int err) { struct crypto_wait *wait = req->data; if (err == -EINPROGRESS) return; wait->err = err; complete(&wait->completion); }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef44100.00%1100.00%
Total44100.00%1100.00%

EXPORT_SYMBOL_GPL(crypto_req_done); MODULE_DESCRIPTION("Cryptographic core API"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Herbert Xu204583.37%3049.18%
James Morris2439.91%1118.03%
Gilad Ben-Yossef522.12%11.64%
Adrian Bunk220.90%11.64%
Akinobu Mita190.77%11.64%
Stephan Mueller180.73%11.64%
David S. Miller160.65%34.92%
Jesper Juhl120.49%11.64%
Sebastian Andrzej Siewior100.41%11.64%
Adam J. Richter30.12%11.64%
Alex Riesen30.12%11.64%
Christoph Hellwig20.08%23.28%
Kees Cook20.08%11.64%
Johannes Weiner10.04%11.64%
Ingo Molnar10.04%11.64%
Eric Sesterhenn / Snakebyte10.04%11.64%
Richard Hartmann10.04%11.64%
Eric Biggers10.04%11.64%
Cristian Stoica10.04%11.64%
Total2453100.00%61100.00%
Directory: crypto
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.