linux-crypto.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Stephan Mueller <smueller@chronox.de>
To: herbert@gondor.apana.org.au
Cc: pebolle@tiscali.nl, andreas.steffen@strongswan.org,
	tytso@mit.edu, sandyinchina@gmail.com,
	linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org
Subject: [PATCH v3 2/6] random: Async and sync API for accessing kernel_pool
Date: Tue, 28 Apr 2015 04:58:42 +0200	[thread overview]
Message-ID: <3084751.ujJM0DBhCD@myon.chronox.de> (raw)
In-Reply-To: <11175802.HG0pHJfshY@myon.chronox.de>

The kernel_pool is intended to be the in-kernel equivalent to the
blocking_pool, i.e. requests for random data may be blocked if
insufficient entropy is present.

The added API calls provide a synchronous function call
get_blocking_random_bytes where the caller is blocked.

In addition, an asynchronous API call of get_blocking_random_bytes_cb
is provided which returns immediately to the caller after submitting
the request for random data. The caller-provided buffer that shall be
filled with random data is filled up as available entropy permits. The
caller may provide a callback function that is invoked once the
request is completed.

A third API call, get_blocking_random_bytes_cancel, is provided to
cancel the random number gathering operation.

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>
---
 drivers/char/random.c  | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/random.h |  20 +++++++++
 2 files changed, 136 insertions(+)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 0b139dc..30d39ba 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1804,3 +1804,119 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
 	credit_entropy_bits(poolp, entropy);
 }
 EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
+
+static bool get_blocking_random_bytes_term(bool *cancel)
+{
+	if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits)
+		return true;
+	return *cancel;
+}
+
+/*
+ * Equivalent function to get_random_bytes with the difference that this
+ * function blocks the request in a similar fashion as random_read(),
+ * implementing a /dev/random device for in-kernel users.
+ *
+ * This function may sleep.
+ *
+ * @buf caller allocated buffer filled with random data
+ * @nbytes requested number of bytes -- buffer should be at least as big
+ * @cancel pointer to variable that can be used to cancel the collection
+ *	   operation. If this boolean is set to true, the collection operation
+ *	   is terminated immediately. When it is set to true during the
+ *	   collection loop, the collection is terminated immediately.
+ *
+ * return: positive value: obtained number of bytes on successful
+ *	   negative value: error code on error
+ */
+ssize_t get_blocking_random_bytes(void *buf, ssize_t nbytes, bool *cancel)
+{
+	ssize_t ret = 0;
+
+	if (nbytes <= 0)
+		return nbytes;
+	BUG_ON(!buf);
+
+	while (ret < nbytes) {
+		ssize_t round = 0;
+		ssize_t pull = min_t(ssize_t, (nbytes - ret), SEC_XFER_SIZE);
+
+		if (*cancel)
+			return ret;
+		round = extract_entropy(&kernel_pool, (buf + ret), pull, 0, 0);
+		if (0 > round)
+			return round;
+		if (0 == round)
+			wait_event_interruptible(random_kernel_wait,
+				get_blocking_random_bytes_term(cancel));
+		ret += round;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(get_blocking_random_bytes);
+
+/*
+ * Immediate canceling the collection operation for the random_work
+ */
+void get_blocking_random_bytes_cancel(struct random_work *rw)
+{
+	rw->cancel = true;
+	wake_up_interruptible(&random_kernel_wait);
+
+}
+EXPORT_SYMBOL(get_blocking_random_bytes_cancel);
+
+static void get_blocking_random_bytes_work(struct work_struct *work)
+{
+	struct random_work *rw = container_of(work, struct random_work,
+					      rw_work);
+	ssize_t ret;
+
+	ret = get_blocking_random_bytes(rw->rw_buf, rw->rw_len, &rw->cancel);
+	if (rw->rw_cb)
+		rw->rw_cb(rw->rw_buf, ret, rw->private);
+}
+
+/*
+ * Asynchronous invocation of the blocking interface. The function
+ * queues the request in either the private work queue supplied with the
+ * wq argument or in the general work queue framework if wq is NULL.
+ * Once the request is completed or upon receiving an error, the callback
+ * function of cb is called, if not NULL, to inform the caller about the
+ * completion of its operation.
+ *
+ * If a caller wants to cancel the work (e.g. in the module_exit function),
+ * simply call
+ *	get_blocking_random_bytes_cancel(&my_random_work);
+ *	cancel_work_sync(&my_random_work.rw_work);
+ *
+ * @wq pointer to private work queue or NULL - input
+ * @rw handle to the work queue frame - output
+ * @buf allocated buffer where random numbers are to be stored
+ * @nbytes size of buf and implicitly number of bytes requested
+ * @private pointer to data that is not processed by here, but handed to the
+ *	    callback function to allow the caller to maintain a state
+ * @cb callback function where
+ *	* buf holds the pointer to buf will be supplied
+ *	* buflen holds the length of the gathered random numbers or error code
+ *	  of the generation function.
+ *	* private provides a reference to the private data pointer
+ */
+void get_blocking_random_bytes_cb(struct workqueue_struct *wq,
+				  struct random_work *rw,
+				  u8 *buf, ssize_t nbytes, void *private,
+				  void (*cb)(void *buf, ssize_t buflen,
+					     void *private))
+{
+	rw->rw_buf = buf;
+	rw->rw_len = nbytes;
+	rw->private = private;
+	rw->rw_cb = cb;
+	rw->cancel = false;
+	INIT_WORK(&rw->rw_work, get_blocking_random_bytes_work);
+	if (wq)
+		queue_work(wq, &rw->rw_work);
+	else
+		schedule_work(&rw->rw_work);
+}
+EXPORT_SYMBOL(get_blocking_random_bytes_cb);
diff --git a/include/linux/random.h b/include/linux/random.h
index b05856e..960803b 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -7,6 +7,7 @@
 #define _LINUX_RANDOM_H
 
 #include <uapi/linux/random.h>
+#include <linux/workqueue.h>
 
 extern void add_device_randomness(const void *, unsigned int);
 extern void add_input_randomness(unsigned int type, unsigned int code,
@@ -112,4 +113,23 @@ static inline u32 next_pseudo_random32(u32 seed)
 	return seed * 1664525 + 1013904223;
 }
 
+/* API for asynchronous in-kernel operation */
+struct random_work {
+	struct work_struct	rw_work;
+	u8			*rw_buf;
+	ssize_t			rw_len;
+	void			*private;
+	void			(*rw_cb)(void *buf, ssize_t buflen,
+					 void *private);
+	bool			cancel;
+};
+
+ssize_t get_blocking_random_bytes(void *buf, ssize_t nbytes, bool *cancel);
+void get_blocking_random_bytes_cancel(struct random_work *rw);
+void get_blocking_random_bytes_cb(struct workqueue_struct *wq,
+				  struct random_work *rw,
+				  u8 *buf, ssize_t nbytes, void *private,
+				  void (*cb)(void *buf, ssize_t buflen,
+					     void *private));
+
 #endif /* _LINUX_RANDOM_H */
-- 
2.1.0

  parent reply	other threads:[~2015-04-28  2:58 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-28  2:53 [PATCH v3 0/6] Seeding DRBG with more entropy Stephan Mueller
2015-04-28  2:54 ` [PATCH v3 1/6] random: Addition of kernel_pool Stephan Mueller
2015-04-28  2:58 ` Stephan Mueller [this message]
2015-04-28  2:59 ` [PATCH v3 3/6] crypto: drbg - prepare for async seeding Stephan Mueller
2015-04-28  3:00 ` [PATCH v3 4/6] crypto: drbg - add async seeding operation Stephan Mueller
2015-05-01  3:13   ` Herbert Xu
2015-05-01  4:15     ` Stephan Mueller
2015-04-28  3:00 ` [PATCH v3 5/6] crypto: drbg - use Jitter RNG to obtain seed Stephan Mueller
2015-04-28  3:01 ` [PATCH v3 6/6] crypto: add jitterentropy RNG Stephan Mueller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3084751.ujJM0DBhCD@myon.chronox.de \
    --to=smueller@chronox.de \
    --cc=andreas.steffen@strongswan.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pebolle@tiscali.nl \
    --cc=sandyinchina@gmail.com \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).