[OS-BUILD PATCH 2/2] crypto: rng - Override drivers/char/random in FIPS mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Herbert Xu <herbert.xu@xxxxxxxxxx>

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@xxxxxxxxxx>

diff --git a/crypto/drbg.c b/crypto/drbg.c
index blahblah..blahblah 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1510,13 +1510,14 @@ static int drbg_generate(struct drbg_state *drbg,
  * 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;
@@ -1526,6 +1527,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)
@@ -1952,6 +1955,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 */
@@ -1959,7 +1963,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;
 }
 
 /*
diff --git a/crypto/rng.c b/crypto/rng.c
index blahblah..blahblah 100644
--- a/crypto/rng.c
+++ b/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;
@@ -136,31 +141,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;
+}
+
+int crypto_get_default_rng(void)
+{
+	int err;
 
-unlock:
+	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;
@@ -176,24 +187,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
 
@@ -251,5 +271,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");
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index blahblah..blahblah 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -135,6 +135,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.

--
https://gitlab.com/cki-project/kernel-ark/-/merge_requests/2757
_______________________________________________
kernel mailing list -- kernel@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to kernel-leave@xxxxxxxxxxxxxxxxxxxxxxx
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/kernel@xxxxxxxxxxxxxxxxxxxxxxx
Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue




[Index of Archives]     [Fedora General Discussion]     [Older Fedora Users Archive]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Legacy]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Announce]     [Fedora Package Review]     [Fedora Music]     [Fedora Packaging]     [Centos]     [Fedora SELinux]     [Coolkey]     [Yum Users]     [Tux]     [Yosemite News]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [USB]     [Asterisk PBX]

  Powered by Linux