crypto: rng - Override drivers/char/random in FIPS mode
Upstream Status: RHEL only Restore the changes to use the crypto RNG in drivers/char/random which were reverted after 5.18. This reverts commit 297bcb88233101e8d5062729ff3a5f989bad1c3b. This also brings the code up-to-date with respect to centos-stream commit 9de3a7339793d3c516b9305a8854267156f90c53 so that changes that were made after the kernel-ark revert have been brought in. Signed-off-by: Herbert Xu <herbert.xu@redhat.com>
This commit is contained in:
parent
6892c65de8
commit
2f94aa1d03
|
@ -1494,13 +1494,14 @@ err:
|
|||
* Wrapper around drbg_generate which can pull arbitrary long strings
|
||||
* from the DRBG without hitting the maximum request limitation.
|
||||
*
|
||||
* Parameters: see drbg_generate
|
||||
* Parameters: see drbg_generate, except @reseed, which triggers reseeding
|
||||
* Return codes: see drbg_generate -- if one drbg_generate request fails,
|
||||
* the entire drbg_generate_long request fails
|
||||
*/
|
||||
static int drbg_generate_long(struct drbg_state *drbg,
|
||||
unsigned char *buf, unsigned int buflen,
|
||||
struct drbg_string *addtl)
|
||||
struct drbg_string *addtl,
|
||||
bool reseed)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
unsigned int slice = 0;
|
||||
|
@ -1510,6 +1511,8 @@ static int drbg_generate_long(struct drbg_state *drbg,
|
|||
slice = ((buflen - len) / drbg_max_request_bytes(drbg));
|
||||
chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len);
|
||||
mutex_lock(&drbg->drbg_mutex);
|
||||
if (reseed)
|
||||
drbg->seeded = DRBG_SEED_STATE_UNSEEDED;
|
||||
err = drbg_generate(drbg, buf + len, chunk, addtl);
|
||||
mutex_unlock(&drbg->drbg_mutex);
|
||||
if (0 > err)
|
||||
|
@ -1936,6 +1939,7 @@ static int drbg_kcapi_random(struct crypto_rng *tfm,
|
|||
struct drbg_state *drbg = crypto_rng_ctx(tfm);
|
||||
struct drbg_string *addtl = NULL;
|
||||
struct drbg_string string;
|
||||
int err;
|
||||
|
||||
if (slen) {
|
||||
/* linked list variable is now local to allow modification */
|
||||
|
@ -1943,7 +1947,15 @@ static int drbg_kcapi_random(struct crypto_rng *tfm,
|
|||
addtl = &string;
|
||||
}
|
||||
|
||||
return drbg_generate_long(drbg, dst, dlen, addtl);
|
||||
err = drbg_generate_long(drbg, dst, dlen, addtl,
|
||||
(crypto_tfm_get_flags(crypto_rng_tfm(tfm)) &
|
||||
CRYPTO_TFM_REQ_NEED_RESEED) ==
|
||||
CRYPTO_TFM_REQ_NEED_RESEED);
|
||||
|
||||
crypto_tfm_clear_flags(crypto_rng_tfm(tfm),
|
||||
CRYPTO_TFM_REQ_NEED_RESEED);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
149
crypto/rng.c
149
crypto/rng.c
|
@ -12,10 +12,13 @@
|
|||
#include <linux/atomic.h>
|
||||
#include <linux/cryptouser.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/fips.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
@ -23,7 +26,9 @@
|
|||
|
||||
#include "internal.h"
|
||||
|
||||
static DEFINE_MUTEX(crypto_default_rng_lock);
|
||||
static ____cacheline_aligned_in_smp DEFINE_MUTEX(crypto_reseed_rng_lock);
|
||||
static struct crypto_rng *crypto_reseed_rng;
|
||||
static ____cacheline_aligned_in_smp DEFINE_MUTEX(crypto_default_rng_lock);
|
||||
struct crypto_rng *crypto_default_rng;
|
||||
EXPORT_SYMBOL_GPL(crypto_default_rng);
|
||||
static int crypto_default_rng_refcnt;
|
||||
|
@ -106,31 +111,37 @@ struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_alloc_rng);
|
||||
|
||||
int crypto_get_default_rng(void)
|
||||
static int crypto_get_rng(struct crypto_rng **rngp)
|
||||
{
|
||||
struct crypto_rng *rng;
|
||||
int err;
|
||||
|
||||
mutex_lock(&crypto_default_rng_lock);
|
||||
if (!crypto_default_rng) {
|
||||
if (!*rngp) {
|
||||
rng = crypto_alloc_rng("stdrng", 0, 0);
|
||||
err = PTR_ERR(rng);
|
||||
if (IS_ERR(rng))
|
||||
goto unlock;
|
||||
return err;
|
||||
|
||||
err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
|
||||
if (err) {
|
||||
crypto_free_rng(rng);
|
||||
goto unlock;
|
||||
return err;
|
||||
}
|
||||
|
||||
crypto_default_rng = rng;
|
||||
*rngp = rng;
|
||||
}
|
||||
|
||||
crypto_default_rng_refcnt++;
|
||||
err = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock:
|
||||
int crypto_get_default_rng(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&crypto_default_rng_lock);
|
||||
err = crypto_get_rng(&crypto_default_rng);
|
||||
if (!err)
|
||||
crypto_default_rng_refcnt++;
|
||||
mutex_unlock(&crypto_default_rng_lock);
|
||||
|
||||
return err;
|
||||
|
@ -146,24 +157,33 @@ void crypto_put_default_rng(void)
|
|||
EXPORT_SYMBOL_GPL(crypto_put_default_rng);
|
||||
|
||||
#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE)
|
||||
int crypto_del_default_rng(void)
|
||||
static int crypto_del_rng(struct crypto_rng **rngp, int *refcntp,
|
||||
struct mutex *lock)
|
||||
{
|
||||
int err = -EBUSY;
|
||||
|
||||
mutex_lock(&crypto_default_rng_lock);
|
||||
if (crypto_default_rng_refcnt)
|
||||
mutex_lock(lock);
|
||||
if (refcntp && *refcntp)
|
||||
goto out;
|
||||
|
||||
crypto_free_rng(crypto_default_rng);
|
||||
crypto_default_rng = NULL;
|
||||
crypto_free_rng(*rngp);
|
||||
*rngp = NULL;
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&crypto_default_rng_lock);
|
||||
mutex_unlock(lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int crypto_del_default_rng(void)
|
||||
{
|
||||
return crypto_del_rng(&crypto_default_rng, &crypto_default_rng_refcnt,
|
||||
&crypto_default_rng_lock) ?:
|
||||
crypto_del_rng(&crypto_reseed_rng, NULL,
|
||||
&crypto_reseed_rng_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_del_default_rng);
|
||||
#endif
|
||||
|
||||
|
@ -217,5 +237,102 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
|
||||
|
||||
static ssize_t crypto_devrandom_read_iter(struct iov_iter *iter, bool reseed)
|
||||
{
|
||||
struct crypto_rng *rng;
|
||||
u8 tmp[256];
|
||||
ssize_t ret;
|
||||
|
||||
if (unlikely(!iov_iter_count(iter)))
|
||||
return 0;
|
||||
|
||||
if (reseed) {
|
||||
u32 flags = 0;
|
||||
|
||||
/* If reseeding is requested, acquire a lock on
|
||||
* crypto_reseed_rng so it is not swapped out until
|
||||
* the initial random bytes are generated.
|
||||
*
|
||||
* The algorithm implementation is also protected with
|
||||
* a separate mutex (drbg->drbg_mutex) around the
|
||||
* reseed-and-generate operation.
|
||||
*/
|
||||
mutex_lock(&crypto_reseed_rng_lock);
|
||||
|
||||
/* If crypto_default_rng is not set, it will be seeded
|
||||
* at creation in __crypto_get_default_rng and thus no
|
||||
* reseeding is needed.
|
||||
*/
|
||||
if (crypto_reseed_rng)
|
||||
flags |= CRYPTO_TFM_REQ_NEED_RESEED;
|
||||
|
||||
ret = crypto_get_rng(&crypto_reseed_rng);
|
||||
if (ret) {
|
||||
mutex_unlock(&crypto_reseed_rng_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rng = crypto_reseed_rng;
|
||||
crypto_tfm_set_flags(crypto_rng_tfm(rng), flags);
|
||||
} else {
|
||||
ret = crypto_get_default_rng();
|
||||
if (ret)
|
||||
return ret;
|
||||
rng = crypto_default_rng;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
size_t i, copied;
|
||||
int err;
|
||||
|
||||
i = min_t(size_t, iov_iter_count(iter), sizeof(tmp));
|
||||
err = crypto_rng_get_bytes(rng, tmp, i);
|
||||
if (err) {
|
||||
ret = err;
|
||||
break;
|
||||
}
|
||||
|
||||
copied = copy_to_iter(tmp, i, iter);
|
||||
ret += copied;
|
||||
|
||||
if (!iov_iter_count(iter))
|
||||
break;
|
||||
|
||||
if (need_resched()) {
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
if (reseed)
|
||||
mutex_unlock(&crypto_reseed_rng_lock);
|
||||
else
|
||||
crypto_put_default_rng();
|
||||
memzero_explicit(tmp, sizeof(tmp));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct random_extrng crypto_devrandom_rng = {
|
||||
.extrng_read_iter = crypto_devrandom_read_iter,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init crypto_rng_init(void)
|
||||
{
|
||||
if (fips_enabled)
|
||||
random_register_extrng(&crypto_devrandom_rng);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit crypto_rng_exit(void)
|
||||
{
|
||||
random_unregister_extrng();
|
||||
}
|
||||
|
||||
late_initcall(crypto_rng_init);
|
||||
module_exit(crypto_rng_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Random Number Generator");
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
#define CRYPTO_TFM_REQ_FORBID_WEAK_KEYS 0x00000100
|
||||
#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200
|
||||
#define CRYPTO_TFM_REQ_MAY_BACKLOG 0x00000400
|
||||
#define CRYPTO_TFM_REQ_NEED_RESEED 0x00000800
|
||||
|
||||
/*
|
||||
* Miscellaneous stuff.
|
||||
|
|
Loading…
Reference in New Issue