linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] crypto: use list to stage async seeding requests
@ 2015-06-06  2:16 Stephan Mueller
  2015-06-09  6:49 ` Herbert Xu
  0 siblings, 1 reply; 10+ messages in thread
From: Stephan Mueller @ 2015-06-06  2:16 UTC (permalink / raw)
  To: herbert
  Cc: Ted Tso, andreas.steffen, sandyinchina, linux-crypto, linux-kernel

This patch uses a list to track the asynchronous seeding requests until
the nonblocking pool is fully initialized. The random.c is provided with
two API calls: the get_blocking_random_bytes_cb allows the caller to
provide a callback function that is triggered once the nonblocking pool
is initialized. If the nonblocking pool is already initialized at the
time of invocation, the function is a noop. The second API call of
get_blocking_random_bytes_cancel allows the caller to cancel an
outstanding request.

The previous approach used a waitqueue for maintaining the requests
until the nonblocking pool is initialized. In some circumstances, the
wait can be very long (in the orders of minutes) where the use of
waitqueues is not appropriate.

The patch also removes the entropy buffer registered with the DRBG
handle in favor of stack variables to hold the seed data.

CC: Andreas Steffen <andreas.steffen@strongswan.org>
CC: Theodore Ts'o <tytso@mit.edu>
CC: Sandy Harris <sandyinchina@gmail.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/drbg.c          | 112 ++++++++++++++++++++++++-------------------------
 drivers/char/random.c  |  99 +++++++++++++++++++++++++++++++++++++++----
 include/crypto/drbg.h  |   4 --
 include/linux/random.h |   4 +-
 4 files changed, 149 insertions(+), 70 deletions(-)

diff --git a/crypto/drbg.c b/crypto/drbg.c
index 04836b4..7339cc5 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1056,25 +1056,31 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed,
 	return ret;
 }
 
-static void drbg_async_seed(struct work_struct *work)
+static void drbg_async_seed(void *private)
 {
 	struct drbg_string data;
 	LIST_HEAD(seedlist);
-	struct drbg_state *drbg = container_of(work, struct drbg_state,
-					       seed_work);
-	int ret;
+	struct drbg_state *drbg = (struct drbg_state *)private;
+	unsigned char entropy[32];
+	size_t entropylen = drbg_sec_strength(drbg->core->flags);
+	int ret = 0;
 
-	get_blocking_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+	BUG_ON(!entropylen);
+	BUG_ON(entropylen > sizeof(entropy));
+	get_random_bytes(entropy, entropylen);
 
-	drbg_string_fill(&data, drbg->seed_buf, drbg->seed_buf_len);
+	drbg_string_fill(&data, entropy, entropylen);
 	list_add_tail(&data.list, &seedlist);
+
 	mutex_lock(&drbg->drbg_mutex);
 	ret = __drbg_seed(drbg, &seedlist, true);
+
+	/* If nonblocking pool is initialized, deactivate Jitter RNG */
 	if (!ret && drbg->jent) {
 		crypto_free_rng(drbg->jent);
 		drbg->jent = NULL;
 	}
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
+	memzero_explicit(entropy, entropylen);
 	mutex_unlock(&drbg->drbg_mutex);
 }
 
@@ -1093,6 +1099,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 		     bool reseed)
 {
 	int ret = 0;
+	unsigned char entropy[((32 + 16) * 2)];
+	size_t entropylen = drbg_sec_strength(drbg->core->flags);
 	struct drbg_string data1;
 	LIST_HEAD(seedlist);
 
@@ -1108,23 +1116,51 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 				 drbg->test_data.len);
 		pr_devel("DRBG: using test entropy\n");
 	} else {
+		/*
+		 * Gather entropy equal to the security strength of the DRBG.
+		 * With a derivation function, a nonce is required in addition
+		 * to the entropy. A nonce must be at least 1/2 of the security
+		 * strength of the DRBG in size. Thus, entropy + nonce is 3/2
+		 * of the strength. The consideration of a nonce is only
+		 * applicable during initial seeding.
+		 */
+		BUG_ON(!entropylen);
+		if (!reseed)
+			entropylen = ((entropylen + 1) / 2) * 3;
+		BUG_ON((entropylen * 2) > sizeof(entropy));
+
+		/*
+		 * Trigger async seeding: This function may not trigger the
+		 * async callback in case the nonblocking is filled. To avoid
+		 * a race between get_random_bytes operating on a not yet
+		 * initialized nonblocking pool and get_blocking_random_bytes_cb
+		 * already operating on an initialized nonblocking pool and thus
+		 * not calling the async callback, invoke the async trigger
+		 * before get_random_bytes.
+		 */
+		ret = get_blocking_random_bytes_cb(drbg, drbg_async_seed);
+
 		/* Get seed from in-kernel /dev/urandom */
-		get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+		get_random_bytes(entropy, entropylen);
 
 		/* Get seed from Jitter RNG */
 		if (!drbg->jent ||
 		    crypto_rng_get_bytes(drbg->jent,
-					 drbg->seed_buf + drbg->seed_buf_len,
-					 drbg->seed_buf_len)) {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len);
+					 entropy + entropylen,
+					 entropylen)) {
+			drbg_string_fill(&data1, entropy, entropylen);
 			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len);
+				 entropylen);
 		} else {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len * 2);
+			drbg_string_fill(&data1, entropy, entropylen * 2);
 			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len * 2);
+				 entropylen * 2);
+		}
+
+		/* If nonblocking pool is initialized, deactivate Jitter RNG */
+		if (!ret && drbg->jent) {
+			crypto_free_rng(drbg->jent);
+			drbg->jent = NULL;
 		}
 	}
 	list_add_tail(&data1.list, &seedlist);
@@ -1150,22 +1186,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 	 * Clear the initial entropy buffer as the async call may not overwrite
 	 * that buffer for quite some time.
 	 */
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len * 2);
-	if (ret)
-		goto out;
-	/*
-	 * For all subsequent seeding calls, we only need the seed buffer
-	 * equal to the security strength of the DRBG. We undo the calculation
-	 * in drbg_alloc_state.
-	 */
-	if (!reseed)
-		drbg->seed_buf_len = drbg->seed_buf_len / 3 * 2;
+	memzero_explicit(entropy, entropylen * 2);
 
-	/* Invoke asynchronous seeding unless DRBG is in test mode. */
-	if (!list_empty(&drbg->test_data.list) && !reseed)
-		schedule_work(&drbg->seed_work);
-
-out:
 	return ret;
 }
 
@@ -1188,8 +1210,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 	drbg->prev = NULL;
 	drbg->fips_primed = false;
 #endif
-	kzfree(drbg->seed_buf);
-	drbg->seed_buf = NULL;
 	if (drbg->jent) {
 		crypto_free_rng(drbg->jent);
 		drbg->jent = NULL;
@@ -1256,30 +1276,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
 			goto err;
 	}
 
-	/*
-	 * Gather entropy equal to the security strength of the DRBG.
-	 * With a derivation function, a nonce is required in addition
-	 * to the entropy. A nonce must be at least 1/2 of the security
-	 * strength of the DRBG in size. Thus, entropy * nonce is 3/2
-	 * of the strength. The consideration of a nonce is only
-	 * applicable during initial seeding.
-	 */
-	drbg->seed_buf_len = drbg_sec_strength(drbg->core->flags);
-	if (!drbg->seed_buf_len) {
-		ret = -EFAULT;
-		goto err;
-	}
-	/*
-	 * Ensure we have sufficient buffer space for initial seed which
-	 * consists of the seed from get_random_bytes and the Jitter RNG.
-	 */
-	drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
-	drbg->seed_buf = kzalloc(drbg->seed_buf_len * 2, GFP_KERNEL);
-	if (!drbg->seed_buf)
-		goto err;
-
-	INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
 	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
 	if(IS_ERR(drbg->jent))
 	{
@@ -1548,7 +1544,7 @@ unlock:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-	cancel_work_sync(&drbg->seed_work);
+	get_blocking_random_bytes_cancel(drbg);
 	if (drbg->d_ops)
 		drbg->d_ops->crypto_fini(drbg);
 	drbg_dealloc_state(drbg);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 159d070..53eff0f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -409,6 +409,16 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait);
 static struct fasync_struct *fasync;
 
+static LIST_HEAD(random_wait_list);
+static DEFINE_MUTEX(random_wait_list_mutex);
+struct random_work {
+	struct list_head	list;
+	struct work_struct	rw_work;
+	void			*rw_private;
+	void			(*rw_cb)(void *private);
+};
+static void process_random_waiters(void);
+
 /**********************************************************************
  *
  * OS independent entropy store.   Here are the functions which handle
@@ -660,6 +670,7 @@ retry:
 		r->entropy_total = 0;
 		if (r == &nonblocking_pool) {
 			prandom_reseed_late();
+			process_random_waiters();
 			wake_up_all(&urandom_init_wait);
 			pr_notice("random: %s pool is initialized\n", r->name);
 		}
@@ -1244,17 +1255,91 @@ void get_random_bytes(void *buf, int nbytes)
 }
 EXPORT_SYMBOL(get_random_bytes);
 
+static void process_random_waiters(void)
+{
+	struct random_work *rw, *tmp;
+
+	mutex_lock(&random_wait_list_mutex);
+	list_for_each_entry_safe(rw, tmp, &random_wait_list, list) {
+		list_del(&rw->list);
+		schedule_work(&rw->rw_work);
+	}
+	mutex_unlock(&random_wait_list_mutex);
+}
+
+static void get_blocking_random_bytes_work(struct work_struct *work)
+{
+	struct random_work *rw = container_of(work, struct random_work,
+					      rw_work);
+
+	rw->rw_cb(rw->rw_private);
+	kfree(rw);
+}
+
 /*
- * Equivalent function to get_random_bytes with the difference that this
- * function blocks the request until the nonblocking_pool is initialized.
+ * API to ping the caller once the nonblocking_pool is initialized
+ *
+ * returns: 0 if nonblocking_pool is already initialized (callback is not
+ *	      invoked)
+ *	    -EINPROGRESS if nonblocking_pool is not initialized and the callback
+ *	      will be called after it has been initialized.
+ *	    other errors in case of error condition
  */
-void get_blocking_random_bytes(void *buf, int nbytes)
+int get_blocking_random_bytes_cb(void *private, void (*cb)(void *private))
 {
-	if (unlikely(nonblocking_pool.initialized == 0))
-		wait_event(urandom_init_wait, nonblocking_pool.initialized);
-	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
+	struct random_work *rw;
+	int ret = 0;
+
+	mutex_lock(&random_wait_list_mutex);
+
+	if (nonblocking_pool.initialized)
+		goto out;
+
+	list_for_each_entry(rw, &random_wait_list, list) {
+		/* no double enqueuing */
+		if (private == rw->rw_private) {
+			ret = -EINPROGRESS;
+			goto out;
+		}
+	}
+
+	rw = kmalloc(sizeof(struct random_work), GFP_KERNEL);
+	if (!rw) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	INIT_WORK(&rw->rw_work, get_blocking_random_bytes_work);
+	rw->rw_private = private;
+	rw->rw_cb = cb;
+	list_add_tail(&rw->list, &random_wait_list);
+	ret = -EINPROGRESS;
+
+out:
+	mutex_unlock(&random_wait_list_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(get_blocking_random_bytes_cb);
+
+/*
+ * Cancel an outstanding request initialized with get_blocking_random_bytes_cb.
+ * It is harmless to call this function even when no request is registered or
+ * the registered request has already been processed.
+ */
+void get_blocking_random_bytes_cancel(void *private)
+{
+	struct random_work *rw, *tmp;
+
+	mutex_lock(&random_wait_list_mutex);
+	list_for_each_entry_safe(rw, tmp, &random_wait_list, list) {
+		if (private == rw->rw_private) {
+			list_del(&rw->list);
+			kfree(rw);
+			break;
+		}
+	}
+	mutex_unlock(&random_wait_list_mutex);
 }
-EXPORT_SYMBOL(get_blocking_random_bytes);
+EXPORT_SYMBOL(get_blocking_random_bytes_cancel);
 
 /*
  * This function will use the architecture-specific hardware random
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index c3f208d..e2c9530 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -51,7 +51,6 @@
 #include <linux/fips.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-#include <linux/workqueue.h>
 
 /*
  * Concatenation Helper and string operation helper
@@ -120,9 +119,6 @@ struct drbg_state {
 	bool fips_primed;	/* Continuous test primed? */
 	unsigned char *prev;	/* FIPS 140-2 continuous test value */
 #endif
-	struct work_struct seed_work;	/* asynchronous seeding support */
-	u8 *seed_buf;			/* buffer holding the seed */
-	size_t seed_buf_len;
 	struct crypto_rng *jent;
 	const struct drbg_state_ops *d_ops;
 	const struct drbg_core *core;
diff --git a/include/linux/random.h b/include/linux/random.h
index 796267d..4b07de0 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -14,7 +14,9 @@ extern void add_input_randomness(unsigned int type, unsigned int code,
 extern void add_interrupt_randomness(int irq, int irq_flags);
 
 extern void get_random_bytes(void *buf, int nbytes);
-extern void get_blocking_random_bytes(void *buf, int nbytes);
+extern int get_blocking_random_bytes_cb(void *private,
+					void (*cb)(void *private));
+extern void get_blocking_random_bytes_cancel(void *private);
 extern void get_random_bytes_arch(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 extern int random_int_secret_init(void);
-- 
2.4.2



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] crypto: use list to stage async seeding requests
  2015-06-06  2:16 [PATCH] crypto: use list to stage async seeding requests Stephan Mueller
@ 2015-06-09  6:49 ` Herbert Xu
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
  0 siblings, 1 reply; 10+ messages in thread
From: Herbert Xu @ 2015-06-09  6:49 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Ted Tso, andreas.steffen, sandyinchina, linux-crypto, linux-kernel

On Sat, Jun 06, 2015 at 04:16:54AM +0200, Stephan Mueller wrote:
> This patch uses a list to track the asynchronous seeding requests until
> the nonblocking pool is fully initialized. The random.c is provided with
> two API calls: the get_blocking_random_bytes_cb allows the caller to
> provide a callback function that is triggered once the nonblocking pool
> is initialized. If the nonblocking pool is already initialized at the
> time of invocation, the function is a noop. The second API call of
> get_blocking_random_bytes_cancel allows the caller to cancel an
> outstanding request.
> 
> The previous approach used a waitqueue for maintaining the requests
> until the nonblocking pool is initialized. In some circumstances, the
> wait can be very long (in the orders of minutes) where the use of
> waitqueues is not appropriate.
> 
> The patch also removes the entropy buffer registered with the DRBG
> handle in favor of stack variables to hold the seed data.
> 
> CC: Andreas Steffen <andreas.steffen@strongswan.org>
> CC: Theodore Ts'o <tytso@mit.edu>
> CC: Sandy Harris <sandyinchina@gmail.com>
> Signed-off-by: Stephan Mueller <smueller@chronox.de>

This patch still has many issues with repsect to work cancellation.
I've decided to do this myself.  I will post the result once I have
done some testing.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 0/3] random: Replace kernel blocking API with callback API
  2015-06-09  6:49 ` Herbert Xu
@ 2015-06-09 10:18   ` Herbert Xu
  2015-06-09 10:19     ` [PATCH 1/3] random: Add callback API for random pool readiness Herbert Xu
                       ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 10:18 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Ted Tso, andreas.steffen, sandyinchina, linux-crypto, linux-kernel

Hi:

This series replaces the blocking API for random pool readiness
with a callback API.  The reason is that the random pool may not
become ready for quite some time so we cannot really wait for it
in a kernel thread as we quickly run into the 2-minute time limit
for detecting lockups.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] random: Add callback API for random pool readiness
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
@ 2015-06-09 10:19     ` Herbert Xu
  2015-06-09 10:19     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 10:19 UTC (permalink / raw)
  To: Stephan Mueller, Ted Tso, andreas.steffen, sandyinchina,
	linux-crypto, linux-kernel

The get_blocking_random_bytes API is broken because the wait can
be arbitrarily long (potentially forever) so there is no safe way
of calling it from within the kernel.

This patch replaces it with a callback API instead.  The callback
is invoked potentially from interrupt context so the user needs
to schedule their own work thread if necessary.

In addition to adding callbacks, they can also be removed as
otherwise this opens up a way for user-space to allocate kernel
memory with no bound (by opening algif_rng descriptors and then
closing them).

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 drivers/char/random.c  |   78 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/random.h |    9 +++++
 2 files changed, 87 insertions(+)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 159d070..a1576ed 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -409,6 +409,9 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait);
 static struct fasync_struct *fasync;
 
+static DEFINE_SPINLOCK(random_ready_list_lock);
+static LIST_HEAD(random_ready_list);
+
 /**********************************************************************
  *
  * OS independent entropy store.   Here are the functions which handle
@@ -589,6 +592,22 @@ static void fast_mix(struct fast_pool *f)
 	f->count++;
 }
 
+static void process_random_ready_list(void)
+{
+	unsigned long flags;
+	struct random_ready_callback *rdy, *tmp;
+
+	spin_lock_irqsave(&random_ready_list_lock, flags);
+	list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) {
+		struct module *owner = rdy->owner;
+
+		list_del_init(&rdy->list);
+		rdy->func(rdy);
+		module_put(owner);
+	}
+	spin_unlock_irqrestore(&random_ready_list_lock, flags);
+}
+
 /*
  * Credit (or debit) the entropy store with n bits of entropy.
  * Use credit_entropy_bits_safe() if the value comes from userspace
@@ -660,6 +679,7 @@ retry:
 		r->entropy_total = 0;
 		if (r == &nonblocking_pool) {
 			prandom_reseed_late();
+			process_random_ready_list();
 			wake_up_all(&urandom_init_wait);
 			pr_notice("random: %s pool is initialized\n", r->name);
 		}
@@ -1257,6 +1277,64 @@ void get_blocking_random_bytes(void *buf, int nbytes)
 EXPORT_SYMBOL(get_blocking_random_bytes);
 
 /*
+ * Add a callback function that will be invoked when the nonblocking
+ * pool is initialised.
+ *
+ * returns: 0 if callback is successfully added
+ *	    -EALREADY if pool is already initialised (callback not called)
+ *	    -ENOENT if module for callback is not alive
+ */
+int add_random_ready_callback(struct random_ready_callback *rdy)
+{
+	struct module *owner;
+	unsigned long flags;
+	int err = -EALREADY;
+
+	if (likely(nonblocking_pool.initialized))
+		return err;
+
+	owner = rdy->owner;
+	if (!try_module_get(owner))
+		return -ENOENT;
+
+	spin_lock_irqsave(&random_ready_list_lock, flags);
+	if (nonblocking_pool.initialized)
+		goto out;
+
+	owner = NULL;
+
+	list_add(&rdy->list, &random_ready_list);
+	err = 0;
+
+out:
+	spin_unlock_irqrestore(&random_ready_list_lock, flags);
+
+	module_put(owner);
+
+	return err;
+}
+EXPORT_SYMBOL(add_random_ready_callback);
+
+/*
+ * Delete a previously registered readiness callback function.
+ */
+void del_random_ready_callback(struct random_ready_callback *rdy)
+{
+	unsigned long flags;
+	struct module *owner = NULL;
+
+	spin_lock_irqsave(&random_ready_list_lock, flags);
+	if (!list_empty(&rdy->list)) {
+		list_del_init(&rdy->list);
+		owner = rdy->owner;
+	}
+	spin_unlock_irqrestore(&random_ready_list_lock, flags);
+
+	module_put(owner);
+}
+EXPORT_SYMBOL(del_random_ready_callback);
+
+/*
  * This function will use the architecture-specific hardware random
  * number generator if it is available.  The arch-specific hw RNG will
  * almost certainly be faster than what we can do in software, but it
diff --git a/include/linux/random.h b/include/linux/random.h
index 796267d..30e2aca 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -6,8 +6,15 @@
 #ifndef _LINUX_RANDOM_H
 #define _LINUX_RANDOM_H
 
+#include <linux/list.h>
 #include <uapi/linux/random.h>
 
+struct random_ready_callback {
+	struct list_head list;
+	void (*func)(struct random_ready_callback *rdy);
+	struct module *owner;
+};
+
 extern void add_device_randomness(const void *, unsigned int);
 extern void add_input_randomness(unsigned int type, unsigned int code,
 				 unsigned int value);
@@ -15,6 +22,8 @@ extern void add_interrupt_randomness(int irq, int irq_flags);
 
 extern void get_random_bytes(void *buf, int nbytes);
 extern void get_blocking_random_bytes(void *buf, int nbytes);
+extern int add_random_ready_callback(struct random_ready_callback *rdy);
+extern void del_random_ready_callback(struct random_ready_callback *rdy);
 extern void get_random_bytes_arch(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 extern int random_int_secret_init(void);

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] crypto: drbg - Use callback API for random readiness
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
  2015-06-09 10:19     ` [PATCH 1/3] random: Add callback API for random pool readiness Herbert Xu
@ 2015-06-09 10:19     ` Herbert Xu
  2015-06-09 12:23       ` Stephan Mueller
  2015-06-09 10:19     ` [PATCH 3/3] random: Remove kernel blocking API Herbert Xu
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 10:19 UTC (permalink / raw)
  To: Stephan Mueller, Ted Tso, andreas.steffen, sandyinchina,
	linux-crypto, linux-kernel

The get_blocking_random_bytes API is broken because the wait can
be arbitrarily long (potentially forever) so there is no safe way
of calling it from within the kernel.

This patch replaces it with the new callback API which does not
have this problem.

The patch also removes the entropy buffer registered with the DRBG
handle in favor of stack variables to hold the seed data.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 crypto/drbg.c         |  215 ++++++++++++++++++++++++++++----------------------
 include/crypto/drbg.h |    3 
 2 files changed, 125 insertions(+), 93 deletions(-)

diff --git a/crypto/drbg.c b/crypto/drbg.c
index 04836b4..6118fd5 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -98,6 +98,7 @@
  */
 
 #include <crypto/drbg.h>
+#include <linux/kernel.h>
 
 /***************************************************************
  * Backend cipher definitions available to DRBG
@@ -190,6 +191,8 @@ static const struct drbg_core drbg_cores[] = {
 #endif /* CONFIG_CRYPTO_DRBG_HMAC */
 };
 
+static int drbg_uninstantiate(struct drbg_state *drbg);
+
 /******************************************************************
  * Generic helper functions
  ******************************************************************/
@@ -1062,20 +1065,32 @@ static void drbg_async_seed(struct work_struct *work)
 	LIST_HEAD(seedlist);
 	struct drbg_state *drbg = container_of(work, struct drbg_state,
 					       seed_work);
-	int ret;
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
+	unsigned char entropy[32];
 
-	get_blocking_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+	BUG_ON(!entropylen);
+	BUG_ON(entropylen > sizeof(entropy));
+	get_random_bytes(entropy, entropylen);
 
-	drbg_string_fill(&data, drbg->seed_buf, drbg->seed_buf_len);
+	drbg_string_fill(&data, entropy, entropylen);
 	list_add_tail(&data.list, &seedlist);
+
 	mutex_lock(&drbg->drbg_mutex);
-	ret = __drbg_seed(drbg, &seedlist, true);
-	if (!ret && drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
+
+	/* If nonblocking pool is initialized, deactivate Jitter RNG */
+	crypto_free_rng(drbg->jent);
+	drbg->jent = NULL;
+
+	/* Set seeded to false so that if __drbg_seed fails the
+	 * next generate call will trigger a reseed.
+	 */
+	drbg->seeded = false;
+
+	__drbg_seed(drbg, &seedlist, true);
+
 	mutex_unlock(&drbg->drbg_mutex);
+
+	memzero_explicit(entropy, entropylen);
 }
 
 /*
@@ -1092,7 +1107,9 @@ static void drbg_async_seed(struct work_struct *work)
 static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 		     bool reseed)
 {
-	int ret = 0;
+	int ret;
+	unsigned char entropy[((32 + 16) * 2)];
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
 	struct drbg_string data1;
 	LIST_HEAD(seedlist);
 
@@ -1108,23 +1125,39 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 				 drbg->test_data.len);
 		pr_devel("DRBG: using test entropy\n");
 	} else {
+		/*
+		 * Gather entropy equal to the security strength of the DRBG.
+		 * With a derivation function, a nonce is required in addition
+		 * to the entropy. A nonce must be at least 1/2 of the security
+		 * strength of the DRBG in size. Thus, entropy + nonce is 3/2
+		 * of the strength. The consideration of a nonce is only
+		 * applicable during initial seeding.
+		 */
+		BUG_ON(!entropylen);
+		if (!reseed)
+			entropylen = ((entropylen + 1) / 2) * 3;
+		BUG_ON((entropylen * 2) > sizeof(entropy));
+
 		/* Get seed from in-kernel /dev/urandom */
-		get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
-
-		/* Get seed from Jitter RNG */
-		if (!drbg->jent ||
-		    crypto_rng_get_bytes(drbg->jent,
-					 drbg->seed_buf + drbg->seed_buf_len,
-					 drbg->seed_buf_len)) {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len);
+		get_random_bytes(entropy, entropylen);
+
+		if (!drbg->jent) {
+			drbg_string_fill(&data1, entropy, entropylen);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen);
 		} else {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len * 2);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len * 2);
+			/* Get seed from Jitter RNG */
+			ret = crypto_rng_get_bytes(drbg->jent,
+						   entropy + entropylen,
+						   entropylen);
+			if (ret) {
+				pr_devel("DRBG: jent failed with %d\n", ret);
+				return ret;
+			}
+
+			drbg_string_fill(&data1, entropy, entropylen * 2);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen * 2);
 		}
 	}
 	list_add_tail(&data1.list, &seedlist);
@@ -1146,26 +1179,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 
 	ret = __drbg_seed(drbg, &seedlist, reseed);
 
-	/*
-	 * Clear the initial entropy buffer as the async call may not overwrite
-	 * that buffer for quite some time.
-	 */
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len * 2);
-	if (ret)
-		goto out;
-	/*
-	 * For all subsequent seeding calls, we only need the seed buffer
-	 * equal to the security strength of the DRBG. We undo the calculation
-	 * in drbg_alloc_state.
-	 */
-	if (!reseed)
-		drbg->seed_buf_len = drbg->seed_buf_len / 3 * 2;
-
-	/* Invoke asynchronous seeding unless DRBG is in test mode. */
-	if (!list_empty(&drbg->test_data.list) && !reseed)
-		schedule_work(&drbg->seed_work);
+	memzero_explicit(entropy, entropylen * 2);
 
-out:
 	return ret;
 }
 
@@ -1188,12 +1203,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 	drbg->prev = NULL;
 	drbg->fips_primed = false;
 #endif
-	kzfree(drbg->seed_buf);
-	drbg->seed_buf = NULL;
-	if (drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
 }
 
 /*
@@ -1256,42 +1265,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
 			goto err;
 	}
 
-	/*
-	 * Gather entropy equal to the security strength of the DRBG.
-	 * With a derivation function, a nonce is required in addition
-	 * to the entropy. A nonce must be at least 1/2 of the security
-	 * strength of the DRBG in size. Thus, entropy * nonce is 3/2
-	 * of the strength. The consideration of a nonce is only
-	 * applicable during initial seeding.
-	 */
-	drbg->seed_buf_len = drbg_sec_strength(drbg->core->flags);
-	if (!drbg->seed_buf_len) {
-		ret = -EFAULT;
-		goto err;
-	}
-	/*
-	 * Ensure we have sufficient buffer space for initial seed which
-	 * consists of the seed from get_random_bytes and the Jitter RNG.
-	 */
-	drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
-	drbg->seed_buf = kzalloc(drbg->seed_buf_len * 2, GFP_KERNEL);
-	if (!drbg->seed_buf)
-		goto err;
-
-	INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
-	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
-	if(IS_ERR(drbg->jent))
-	{
-		pr_info("DRBG: could not allocate Jitter RNG handle for seeding\n");
-		/*
-		 * As the Jitter RNG is a module that may not be present, we
-		 * continue with the operation and do not fully tie the DRBG
-		 * to the Jitter RNG.
-		 */
-		drbg->jent = NULL;
-	}
-
 	return 0;
 
 err:
@@ -1467,6 +1440,47 @@ static int drbg_generate_long(struct drbg_state *drbg,
 	return 0;
 }
 
+static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
+{
+	struct drbg_state *drbg = container_of(rdy, struct drbg_state,
+					       random_ready);
+
+	schedule_work(&drbg->seed_work);
+}
+
+static int drbg_prepare_hrng(struct drbg_state *drbg)
+{
+	int err;
+
+	/* We do not need an HRNG in test mode. */
+	if (list_empty(&drbg->test_data.list))
+		return 0;
+
+	INIT_WORK(&drbg->seed_work, drbg_async_seed);
+
+	drbg->random_ready.owner = THIS_MODULE;
+	drbg->random_ready.func = drbg_schedule_async_seed;
+
+	err = add_random_ready_callback(&drbg->random_ready);
+
+	switch (err) {
+	case 0:
+		break;
+
+	case -EALREADY:
+		err = 0;
+		/* fall through */
+
+	default:
+		drbg->random_ready.func = NULL;
+		return err;
+	}
+
+	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+
+	return err;
+}
+
 /*
  * DRBG instantiation function as required by SP800-90A - this function
  * sets up the DRBG handle, performs the initial seeding and all sanity
@@ -1517,15 +1531,23 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
 		if (drbg->d_ops->crypto_init(drbg))
 			goto err;
 
+		ret = drbg_prepare_hrng(drbg);
+		if (ret)
+			goto free_everything;
+
+		if (IS_ERR(drbg->jent)) {
+			ret = PTR_ERR(drbg->jent);
+			drbg->jent = NULL;
+			goto free_everything;
+		}
+
 		reseed = false;
 	}
 
 	ret = drbg_seed(drbg, pers, reseed);
 
-	if (ret && !reseed) {
-		drbg->d_ops->crypto_fini(drbg);
-		goto err;
-	}
+	if (ret && !reseed)
+		goto free_everything;
 
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
@@ -1535,6 +1557,11 @@ err:
 unlock:
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
+
+free_everything:
+	mutex_unlock(&drbg->drbg_mutex);
+	drbg_uninstantiate(drbg);
+	return ret;
 }
 
 /*
@@ -1548,7 +1575,13 @@ unlock:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-	cancel_work_sync(&drbg->seed_work);
+	if (drbg->random_ready.func) {
+		del_random_ready_callback(&drbg->random_ready);
+		cancel_work_sync(&drbg->seed_work);
+		crypto_free_rng(drbg->jent);
+		drbg->jent = NULL;
+	}
+
 	if (drbg->d_ops)
 		drbg->d_ops->crypto_fini(drbg);
 	drbg_dealloc_state(drbg);
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index c3f208d..fad6450 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -121,12 +121,11 @@ struct drbg_state {
 	unsigned char *prev;	/* FIPS 140-2 continuous test value */
 #endif
 	struct work_struct seed_work;	/* asynchronous seeding support */
-	u8 *seed_buf;			/* buffer holding the seed */
-	size_t seed_buf_len;
 	struct crypto_rng *jent;
 	const struct drbg_state_ops *d_ops;
 	const struct drbg_core *core;
 	struct drbg_string test_data;
+	struct random_ready_callback random_ready;
 };
 
 static inline __u8 drbg_statelen(struct drbg_state *drbg)

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] random: Remove kernel blocking API
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
  2015-06-09 10:19     ` [PATCH 1/3] random: Add callback API for random pool readiness Herbert Xu
  2015-06-09 10:19     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
@ 2015-06-09 10:19     ` Herbert Xu
  2015-06-09 10:21     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
  2015-06-09 13:55     ` Herbert Xu
  4 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 10:19 UTC (permalink / raw)
  To: Stephan Mueller, Ted Tso, andreas.steffen, sandyinchina,
	linux-crypto, linux-kernel

This patch removes the kernel blocking API as it has been completely
replaced by the callback API.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 drivers/char/random.c  |   12 ------------
 include/linux/random.h |    1 -
 2 files changed, 13 deletions(-)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index a1576ed..d0da5d8 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1265,18 +1265,6 @@ void get_random_bytes(void *buf, int nbytes)
 EXPORT_SYMBOL(get_random_bytes);
 
 /*
- * Equivalent function to get_random_bytes with the difference that this
- * function blocks the request until the nonblocking_pool is initialized.
- */
-void get_blocking_random_bytes(void *buf, int nbytes)
-{
-	if (unlikely(nonblocking_pool.initialized == 0))
-		wait_event(urandom_init_wait, nonblocking_pool.initialized);
-	extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
-}
-EXPORT_SYMBOL(get_blocking_random_bytes);
-
-/*
  * Add a callback function that will be invoked when the nonblocking
  * pool is initialised.
  *
diff --git a/include/linux/random.h b/include/linux/random.h
index 30e2aca..e651874 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -21,7 +21,6 @@ extern void add_input_randomness(unsigned int type, unsigned int code,
 extern void add_interrupt_randomness(int irq, int irq_flags);
 
 extern void get_random_bytes(void *buf, int nbytes);
-extern void get_blocking_random_bytes(void *buf, int nbytes);
 extern int add_random_ready_callback(struct random_ready_callback *rdy);
 extern void del_random_ready_callback(struct random_ready_callback *rdy);
 extern void get_random_bytes_arch(void *buf, int nbytes);

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] crypto: drbg - Use callback API for random readiness
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
                       ` (2 preceding siblings ...)
  2015-06-09 10:19     ` [PATCH 3/3] random: Remove kernel blocking API Herbert Xu
@ 2015-06-09 10:21     ` Herbert Xu
  2015-06-09 13:55     ` Herbert Xu
  4 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 10:21 UTC (permalink / raw)
  To: Stephan Mueller, Ted Tso, andreas.steffen, sandyinchina,
	linux-crypto, linux-kernel

From: Stephan Mueller <smueller@chronox.de>

The get_blocking_random_bytes API is broken because the wait can
be arbitrarily long (potentially forever) so there is no safe way
of calling it from within the kernel.

This patch replaces it with the new callback API which does not
have this problem.

The patch also removes the entropy buffer registered with the DRBG
handle in favor of stack variables to hold the seed data.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 crypto/drbg.c         |  215 ++++++++++++++++++++++++++++----------------------
 include/crypto/drbg.h |    3 
 2 files changed, 125 insertions(+), 93 deletions(-)

diff --git a/crypto/drbg.c b/crypto/drbg.c
index 04836b4..6118fd5 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -98,6 +98,7 @@
  */
 
 #include <crypto/drbg.h>
+#include <linux/kernel.h>
 
 /***************************************************************
  * Backend cipher definitions available to DRBG
@@ -190,6 +191,8 @@ static const struct drbg_core drbg_cores[] = {
 #endif /* CONFIG_CRYPTO_DRBG_HMAC */
 };
 
+static int drbg_uninstantiate(struct drbg_state *drbg);
+
 /******************************************************************
  * Generic helper functions
  ******************************************************************/
@@ -1062,20 +1065,32 @@ static void drbg_async_seed(struct work_struct *work)
 	LIST_HEAD(seedlist);
 	struct drbg_state *drbg = container_of(work, struct drbg_state,
 					       seed_work);
-	int ret;
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
+	unsigned char entropy[32];
 
-	get_blocking_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+	BUG_ON(!entropylen);
+	BUG_ON(entropylen > sizeof(entropy));
+	get_random_bytes(entropy, entropylen);
 
-	drbg_string_fill(&data, drbg->seed_buf, drbg->seed_buf_len);
+	drbg_string_fill(&data, entropy, entropylen);
 	list_add_tail(&data.list, &seedlist);
+
 	mutex_lock(&drbg->drbg_mutex);
-	ret = __drbg_seed(drbg, &seedlist, true);
-	if (!ret && drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
+
+	/* If nonblocking pool is initialized, deactivate Jitter RNG */
+	crypto_free_rng(drbg->jent);
+	drbg->jent = NULL;
+
+	/* Set seeded to false so that if __drbg_seed fails the
+	 * next generate call will trigger a reseed.
+	 */
+	drbg->seeded = false;
+
+	__drbg_seed(drbg, &seedlist, true);
+
 	mutex_unlock(&drbg->drbg_mutex);
+
+	memzero_explicit(entropy, entropylen);
 }
 
 /*
@@ -1092,7 +1107,9 @@ static void drbg_async_seed(struct work_struct *work)
 static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 		     bool reseed)
 {
-	int ret = 0;
+	int ret;
+	unsigned char entropy[((32 + 16) * 2)];
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
 	struct drbg_string data1;
 	LIST_HEAD(seedlist);
 
@@ -1108,23 +1125,39 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 				 drbg->test_data.len);
 		pr_devel("DRBG: using test entropy\n");
 	} else {
+		/*
+		 * Gather entropy equal to the security strength of the DRBG.
+		 * With a derivation function, a nonce is required in addition
+		 * to the entropy. A nonce must be at least 1/2 of the security
+		 * strength of the DRBG in size. Thus, entropy + nonce is 3/2
+		 * of the strength. The consideration of a nonce is only
+		 * applicable during initial seeding.
+		 */
+		BUG_ON(!entropylen);
+		if (!reseed)
+			entropylen = ((entropylen + 1) / 2) * 3;
+		BUG_ON((entropylen * 2) > sizeof(entropy));
+
 		/* Get seed from in-kernel /dev/urandom */
-		get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
-
-		/* Get seed from Jitter RNG */
-		if (!drbg->jent ||
-		    crypto_rng_get_bytes(drbg->jent,
-					 drbg->seed_buf + drbg->seed_buf_len,
-					 drbg->seed_buf_len)) {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len);
+		get_random_bytes(entropy, entropylen);
+
+		if (!drbg->jent) {
+			drbg_string_fill(&data1, entropy, entropylen);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen);
 		} else {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len * 2);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len * 2);
+			/* Get seed from Jitter RNG */
+			ret = crypto_rng_get_bytes(drbg->jent,
+						   entropy + entropylen,
+						   entropylen);
+			if (ret) {
+				pr_devel("DRBG: jent failed with %d\n", ret);
+				return ret;
+			}
+
+			drbg_string_fill(&data1, entropy, entropylen * 2);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen * 2);
 		}
 	}
 	list_add_tail(&data1.list, &seedlist);
@@ -1146,26 +1179,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 
 	ret = __drbg_seed(drbg, &seedlist, reseed);
 
-	/*
-	 * Clear the initial entropy buffer as the async call may not overwrite
-	 * that buffer for quite some time.
-	 */
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len * 2);
-	if (ret)
-		goto out;
-	/*
-	 * For all subsequent seeding calls, we only need the seed buffer
-	 * equal to the security strength of the DRBG. We undo the calculation
-	 * in drbg_alloc_state.
-	 */
-	if (!reseed)
-		drbg->seed_buf_len = drbg->seed_buf_len / 3 * 2;
-
-	/* Invoke asynchronous seeding unless DRBG is in test mode. */
-	if (!list_empty(&drbg->test_data.list) && !reseed)
-		schedule_work(&drbg->seed_work);
+	memzero_explicit(entropy, entropylen * 2);
 
-out:
 	return ret;
 }
 
@@ -1188,12 +1203,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 	drbg->prev = NULL;
 	drbg->fips_primed = false;
 #endif
-	kzfree(drbg->seed_buf);
-	drbg->seed_buf = NULL;
-	if (drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
 }
 
 /*
@@ -1256,42 +1265,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
 			goto err;
 	}
 
-	/*
-	 * Gather entropy equal to the security strength of the DRBG.
-	 * With a derivation function, a nonce is required in addition
-	 * to the entropy. A nonce must be at least 1/2 of the security
-	 * strength of the DRBG in size. Thus, entropy * nonce is 3/2
-	 * of the strength. The consideration of a nonce is only
-	 * applicable during initial seeding.
-	 */
-	drbg->seed_buf_len = drbg_sec_strength(drbg->core->flags);
-	if (!drbg->seed_buf_len) {
-		ret = -EFAULT;
-		goto err;
-	}
-	/*
-	 * Ensure we have sufficient buffer space for initial seed which
-	 * consists of the seed from get_random_bytes and the Jitter RNG.
-	 */
-	drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
-	drbg->seed_buf = kzalloc(drbg->seed_buf_len * 2, GFP_KERNEL);
-	if (!drbg->seed_buf)
-		goto err;
-
-	INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
-	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
-	if(IS_ERR(drbg->jent))
-	{
-		pr_info("DRBG: could not allocate Jitter RNG handle for seeding\n");
-		/*
-		 * As the Jitter RNG is a module that may not be present, we
-		 * continue with the operation and do not fully tie the DRBG
-		 * to the Jitter RNG.
-		 */
-		drbg->jent = NULL;
-	}
-
 	return 0;
 
 err:
@@ -1467,6 +1440,47 @@ static int drbg_generate_long(struct drbg_state *drbg,
 	return 0;
 }
 
+static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
+{
+	struct drbg_state *drbg = container_of(rdy, struct drbg_state,
+					       random_ready);
+
+	schedule_work(&drbg->seed_work);
+}
+
+static int drbg_prepare_hrng(struct drbg_state *drbg)
+{
+	int err;
+
+	/* We do not need an HRNG in test mode. */
+	if (list_empty(&drbg->test_data.list))
+		return 0;
+
+	INIT_WORK(&drbg->seed_work, drbg_async_seed);
+
+	drbg->random_ready.owner = THIS_MODULE;
+	drbg->random_ready.func = drbg_schedule_async_seed;
+
+	err = add_random_ready_callback(&drbg->random_ready);
+
+	switch (err) {
+	case 0:
+		break;
+
+	case -EALREADY:
+		err = 0;
+		/* fall through */
+
+	default:
+		drbg->random_ready.func = NULL;
+		return err;
+	}
+
+	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+
+	return err;
+}
+
 /*
  * DRBG instantiation function as required by SP800-90A - this function
  * sets up the DRBG handle, performs the initial seeding and all sanity
@@ -1517,15 +1531,23 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
 		if (drbg->d_ops->crypto_init(drbg))
 			goto err;
 
+		ret = drbg_prepare_hrng(drbg);
+		if (ret)
+			goto free_everything;
+
+		if (IS_ERR(drbg->jent)) {
+			ret = PTR_ERR(drbg->jent);
+			drbg->jent = NULL;
+			goto free_everything;
+		}
+
 		reseed = false;
 	}
 
 	ret = drbg_seed(drbg, pers, reseed);
 
-	if (ret && !reseed) {
-		drbg->d_ops->crypto_fini(drbg);
-		goto err;
-	}
+	if (ret && !reseed)
+		goto free_everything;
 
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
@@ -1535,6 +1557,11 @@ err:
 unlock:
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
+
+free_everything:
+	mutex_unlock(&drbg->drbg_mutex);
+	drbg_uninstantiate(drbg);
+	return ret;
 }
 
 /*
@@ -1548,7 +1575,13 @@ unlock:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-	cancel_work_sync(&drbg->seed_work);
+	if (drbg->random_ready.func) {
+		del_random_ready_callback(&drbg->random_ready);
+		cancel_work_sync(&drbg->seed_work);
+		crypto_free_rng(drbg->jent);
+		drbg->jent = NULL;
+	}
+
 	if (drbg->d_ops)
 		drbg->d_ops->crypto_fini(drbg);
 	drbg_dealloc_state(drbg);
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index c3f208d..fad6450 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -121,12 +121,11 @@ struct drbg_state {
 	unsigned char *prev;	/* FIPS 140-2 continuous test value */
 #endif
 	struct work_struct seed_work;	/* asynchronous seeding support */
-	u8 *seed_buf;			/* buffer holding the seed */
-	size_t seed_buf_len;
 	struct crypto_rng *jent;
 	const struct drbg_state_ops *d_ops;
 	const struct drbg_core *core;
 	struct drbg_string test_data;
+	struct random_ready_callback random_ready;
 };
 
 static inline __u8 drbg_statelen(struct drbg_state *drbg)

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] crypto: drbg - Use callback API for random readiness
  2015-06-09 10:19     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
@ 2015-06-09 12:23       ` Stephan Mueller
  2015-06-09 13:24         ` Herbert Xu
  0 siblings, 1 reply; 10+ messages in thread
From: Stephan Mueller @ 2015-06-09 12:23 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Ted Tso, andreas.steffen, sandyinchina, linux-crypto, linux-kernel

Am Dienstag, 9. Juni 2015, 18:19:41 schrieb Herbert Xu:

Hi Herbert,

first of all, thanks a lot for your help. I have tested the patch set.

...

>  /*
>   * DRBG instantiation function as required by SP800-90A - this function
>   * sets up the DRBG handle, performs the initial seeding and all sanity
> @@ -1517,15 +1531,23 @@ static int drbg_instantiate(struct drbg_state *drbg,
> struct drbg_string *pers, if (drbg->d_ops->crypto_init(drbg))
>  			goto err;
> 
> +		ret = drbg_prepare_hrng(drbg);
> +		if (ret)
> +			goto free_everything;
> +
> +		if (IS_ERR(drbg->jent)) {
> +			ret = PTR_ERR(drbg->jent);
> +			drbg->jent = NULL;
> +			goto free_everything;

I am wondering about the error here. The Jitter RNG has in its init function a 
test to see whether the RNG really works on the hardware as there are still 
systems out there that have no high-res timer (e.g. I have seen that on old 
Android phones). If the Jitter RNG detects that the system is not appropriate, 
it will not register.

On such systems, the error here would imply that the DRBG does not instantiate 
and we have no stdrng.

> +		}
> +
>  		reseed = false;
>  	}
> 
>  	ret = drbg_seed(drbg, pers, reseed);
> 
> -	if (ret && !reseed) {
> -		drbg->d_ops->crypto_fini(drbg);
> -		goto err;
> -	}
> +	if (ret && !reseed)
> +		goto free_everything;
> 
>  	mutex_unlock(&drbg->drbg_mutex);
>  	return ret;
> @@ -1535,6 +1557,11 @@ err:
>  unlock:
>  	mutex_unlock(&drbg->drbg_mutex);
>  	return ret;
> +
> +free_everything:
> +	mutex_unlock(&drbg->drbg_mutex);
> +	drbg_uninstantiate(drbg);
> +	return ret;
>  }
> 

-- 
Ciao
Stephan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] crypto: drbg - Use callback API for random readiness
  2015-06-09 12:23       ` Stephan Mueller
@ 2015-06-09 13:24         ` Herbert Xu
  0 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 13:24 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Ted Tso, andreas.steffen, sandyinchina, linux-crypto, linux-kernel

On Tue, Jun 09, 2015 at 02:23:39PM +0200, Stephan Mueller wrote:
>
> I am wondering about the error here. The Jitter RNG has in its init function a 
> test to see whether the RNG really works on the hardware as there are still 
> systems out there that have no high-res timer (e.g. I have seen that on old 
> Android phones). If the Jitter RNG detects that the system is not appropriate, 
> it will not register.

If we have no jent and the pool isn't ready then we should at least
fail in FIPS mode.  If we weren't in FIPS mode we could block but
for now I'm going to go with the current behaviour of simply
continuing.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/3] crypto: drbg - Use callback API for random readiness
  2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
                       ` (3 preceding siblings ...)
  2015-06-09 10:21     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
@ 2015-06-09 13:55     ` Herbert Xu
  4 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2015-06-09 13:55 UTC (permalink / raw)
  To: Stephan Mueller, Ted Tso, andreas.steffen, sandyinchina,
	linux-crypto, linux-kernel

From: Stephan Mueller <smueller@chronox.de>

The get_blocking_random_bytes API is broken because the wait can
be arbitrarily long (potentially forever) so there is no safe way
of calling it from within the kernel.

This patch replaces it with the new callback API which does not
have this problem.

The patch also removes the entropy buffer registered with the DRBG
handle in favor of stack variables to hold the seed data.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 crypto/drbg.c         |  217 +++++++++++++++++++++++++++++---------------------
 include/crypto/drbg.h |    3 
 2 files changed, 127 insertions(+), 93 deletions(-)

diff --git a/crypto/drbg.c b/crypto/drbg.c
index 04836b4..c6cbf13 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -98,6 +98,7 @@
  */
 
 #include <crypto/drbg.h>
+#include <linux/kernel.h>
 
 /***************************************************************
  * Backend cipher definitions available to DRBG
@@ -190,6 +191,8 @@ static const struct drbg_core drbg_cores[] = {
 #endif /* CONFIG_CRYPTO_DRBG_HMAC */
 };
 
+static int drbg_uninstantiate(struct drbg_state *drbg);
+
 /******************************************************************
  * Generic helper functions
  ******************************************************************/
@@ -1062,20 +1065,32 @@ static void drbg_async_seed(struct work_struct *work)
 	LIST_HEAD(seedlist);
 	struct drbg_state *drbg = container_of(work, struct drbg_state,
 					       seed_work);
-	int ret;
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
+	unsigned char entropy[32];
 
-	get_blocking_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
+	BUG_ON(!entropylen);
+	BUG_ON(entropylen > sizeof(entropy));
+	get_random_bytes(entropy, entropylen);
 
-	drbg_string_fill(&data, drbg->seed_buf, drbg->seed_buf_len);
+	drbg_string_fill(&data, entropy, entropylen);
 	list_add_tail(&data.list, &seedlist);
+
 	mutex_lock(&drbg->drbg_mutex);
-	ret = __drbg_seed(drbg, &seedlist, true);
-	if (!ret && drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len);
+
+	/* If nonblocking pool is initialized, deactivate Jitter RNG */
+	crypto_free_rng(drbg->jent);
+	drbg->jent = NULL;
+
+	/* Set seeded to false so that if __drbg_seed fails the
+	 * next generate call will trigger a reseed.
+	 */
+	drbg->seeded = false;
+
+	__drbg_seed(drbg, &seedlist, true);
+
 	mutex_unlock(&drbg->drbg_mutex);
+
+	memzero_explicit(entropy, entropylen);
 }
 
 /*
@@ -1092,7 +1107,9 @@ static void drbg_async_seed(struct work_struct *work)
 static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 		     bool reseed)
 {
-	int ret = 0;
+	int ret;
+	unsigned char entropy[((32 + 16) * 2)];
+	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
 	struct drbg_string data1;
 	LIST_HEAD(seedlist);
 
@@ -1108,23 +1125,39 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 				 drbg->test_data.len);
 		pr_devel("DRBG: using test entropy\n");
 	} else {
+		/*
+		 * Gather entropy equal to the security strength of the DRBG.
+		 * With a derivation function, a nonce is required in addition
+		 * to the entropy. A nonce must be at least 1/2 of the security
+		 * strength of the DRBG in size. Thus, entropy + nonce is 3/2
+		 * of the strength. The consideration of a nonce is only
+		 * applicable during initial seeding.
+		 */
+		BUG_ON(!entropylen);
+		if (!reseed)
+			entropylen = ((entropylen + 1) / 2) * 3;
+		BUG_ON((entropylen * 2) > sizeof(entropy));
+
 		/* Get seed from in-kernel /dev/urandom */
-		get_random_bytes(drbg->seed_buf, drbg->seed_buf_len);
-
-		/* Get seed from Jitter RNG */
-		if (!drbg->jent ||
-		    crypto_rng_get_bytes(drbg->jent,
-					 drbg->seed_buf + drbg->seed_buf_len,
-					 drbg->seed_buf_len)) {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len);
+		get_random_bytes(entropy, entropylen);
+
+		if (!drbg->jent) {
+			drbg_string_fill(&data1, entropy, entropylen);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen);
 		} else {
-			drbg_string_fill(&data1, drbg->seed_buf,
-					 drbg->seed_buf_len * 2);
-			pr_devel("DRBG: (re)seeding with %zu bytes of entropy\n",
-				 drbg->seed_buf_len * 2);
+			/* Get seed from Jitter RNG */
+			ret = crypto_rng_get_bytes(drbg->jent,
+						   entropy + entropylen,
+						   entropylen);
+			if (ret) {
+				pr_devel("DRBG: jent failed with %d\n", ret);
+				return ret;
+			}
+
+			drbg_string_fill(&data1, entropy, entropylen * 2);
+			pr_devel("DRBG: (re)seeding with %u bytes of entropy\n",
+				 entropylen * 2);
 		}
 	}
 	list_add_tail(&data1.list, &seedlist);
@@ -1146,26 +1179,8 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
 
 	ret = __drbg_seed(drbg, &seedlist, reseed);
 
-	/*
-	 * Clear the initial entropy buffer as the async call may not overwrite
-	 * that buffer for quite some time.
-	 */
-	memzero_explicit(drbg->seed_buf, drbg->seed_buf_len * 2);
-	if (ret)
-		goto out;
-	/*
-	 * For all subsequent seeding calls, we only need the seed buffer
-	 * equal to the security strength of the DRBG. We undo the calculation
-	 * in drbg_alloc_state.
-	 */
-	if (!reseed)
-		drbg->seed_buf_len = drbg->seed_buf_len / 3 * 2;
-
-	/* Invoke asynchronous seeding unless DRBG is in test mode. */
-	if (!list_empty(&drbg->test_data.list) && !reseed)
-		schedule_work(&drbg->seed_work);
+	memzero_explicit(entropy, entropylen * 2);
 
-out:
 	return ret;
 }
 
@@ -1188,12 +1203,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
 	drbg->prev = NULL;
 	drbg->fips_primed = false;
 #endif
-	kzfree(drbg->seed_buf);
-	drbg->seed_buf = NULL;
-	if (drbg->jent) {
-		crypto_free_rng(drbg->jent);
-		drbg->jent = NULL;
-	}
 }
 
 /*
@@ -1256,42 +1265,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
 			goto err;
 	}
 
-	/*
-	 * Gather entropy equal to the security strength of the DRBG.
-	 * With a derivation function, a nonce is required in addition
-	 * to the entropy. A nonce must be at least 1/2 of the security
-	 * strength of the DRBG in size. Thus, entropy * nonce is 3/2
-	 * of the strength. The consideration of a nonce is only
-	 * applicable during initial seeding.
-	 */
-	drbg->seed_buf_len = drbg_sec_strength(drbg->core->flags);
-	if (!drbg->seed_buf_len) {
-		ret = -EFAULT;
-		goto err;
-	}
-	/*
-	 * Ensure we have sufficient buffer space for initial seed which
-	 * consists of the seed from get_random_bytes and the Jitter RNG.
-	 */
-	drbg->seed_buf_len = ((drbg->seed_buf_len + 1) / 2) * 3;
-	drbg->seed_buf = kzalloc(drbg->seed_buf_len * 2, GFP_KERNEL);
-	if (!drbg->seed_buf)
-		goto err;
-
-	INIT_WORK(&drbg->seed_work, drbg_async_seed);
-
-	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
-	if(IS_ERR(drbg->jent))
-	{
-		pr_info("DRBG: could not allocate Jitter RNG handle for seeding\n");
-		/*
-		 * As the Jitter RNG is a module that may not be present, we
-		 * continue with the operation and do not fully tie the DRBG
-		 * to the Jitter RNG.
-		 */
-		drbg->jent = NULL;
-	}
-
 	return 0;
 
 err:
@@ -1467,6 +1440,47 @@ static int drbg_generate_long(struct drbg_state *drbg,
 	return 0;
 }
 
+static void drbg_schedule_async_seed(struct random_ready_callback *rdy)
+{
+	struct drbg_state *drbg = container_of(rdy, struct drbg_state,
+					       random_ready);
+
+	schedule_work(&drbg->seed_work);
+}
+
+static int drbg_prepare_hrng(struct drbg_state *drbg)
+{
+	int err;
+
+	/* We do not need an HRNG in test mode. */
+	if (list_empty(&drbg->test_data.list))
+		return 0;
+
+	INIT_WORK(&drbg->seed_work, drbg_async_seed);
+
+	drbg->random_ready.owner = THIS_MODULE;
+	drbg->random_ready.func = drbg_schedule_async_seed;
+
+	err = add_random_ready_callback(&drbg->random_ready);
+
+	switch (err) {
+	case 0:
+		break;
+
+	case -EALREADY:
+		err = 0;
+		/* fall through */
+
+	default:
+		drbg->random_ready.func = NULL;
+		return err;
+	}
+
+	drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0);
+
+	return err;
+}
+
 /*
  * DRBG instantiation function as required by SP800-90A - this function
  * sets up the DRBG handle, performs the initial seeding and all sanity
@@ -1517,15 +1531,25 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers,
 		if (drbg->d_ops->crypto_init(drbg))
 			goto err;
 
+		ret = drbg_prepare_hrng(drbg);
+		if (ret)
+			goto free_everything;
+
+		if (IS_ERR(drbg->jent)) {
+			ret = PTR_ERR(drbg->jent);
+			drbg->jent = NULL;
+			if (fips_enabled || ret != -ENOENT)
+				goto free_everything;
+			pr_info("DRBG: Continuing without Jitter RNG\n");
+		}
+
 		reseed = false;
 	}
 
 	ret = drbg_seed(drbg, pers, reseed);
 
-	if (ret && !reseed) {
-		drbg->d_ops->crypto_fini(drbg);
-		goto err;
-	}
+	if (ret && !reseed)
+		goto free_everything;
 
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
@@ -1535,6 +1559,11 @@ err:
 unlock:
 	mutex_unlock(&drbg->drbg_mutex);
 	return ret;
+
+free_everything:
+	mutex_unlock(&drbg->drbg_mutex);
+	drbg_uninstantiate(drbg);
+	return ret;
 }
 
 /*
@@ -1548,7 +1577,13 @@ unlock:
  */
 static int drbg_uninstantiate(struct drbg_state *drbg)
 {
-	cancel_work_sync(&drbg->seed_work);
+	if (drbg->random_ready.func) {
+		del_random_ready_callback(&drbg->random_ready);
+		cancel_work_sync(&drbg->seed_work);
+		crypto_free_rng(drbg->jent);
+		drbg->jent = NULL;
+	}
+
 	if (drbg->d_ops)
 		drbg->d_ops->crypto_fini(drbg);
 	drbg_dealloc_state(drbg);
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index c3f208d..fad6450 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -121,12 +121,11 @@ struct drbg_state {
 	unsigned char *prev;	/* FIPS 140-2 continuous test value */
 #endif
 	struct work_struct seed_work;	/* asynchronous seeding support */
-	u8 *seed_buf;			/* buffer holding the seed */
-	size_t seed_buf_len;
 	struct crypto_rng *jent;
 	const struct drbg_state_ops *d_ops;
 	const struct drbg_core *core;
 	struct drbg_string test_data;
+	struct random_ready_callback random_ready;
 };
 
 static inline __u8 drbg_statelen(struct drbg_state *drbg)

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-06-09 13:55 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-06  2:16 [PATCH] crypto: use list to stage async seeding requests Stephan Mueller
2015-06-09  6:49 ` Herbert Xu
2015-06-09 10:18   ` [PATCH 0/3] random: Replace kernel blocking API with callback API Herbert Xu
2015-06-09 10:19     ` [PATCH 1/3] random: Add callback API for random pool readiness Herbert Xu
2015-06-09 10:19     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
2015-06-09 12:23       ` Stephan Mueller
2015-06-09 13:24         ` Herbert Xu
2015-06-09 10:19     ` [PATCH 3/3] random: Remove kernel blocking API Herbert Xu
2015-06-09 10:21     ` [PATCH 2/3] crypto: drbg - Use callback API for random readiness Herbert Xu
2015-06-09 13:55     ` Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).