linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "H. Peter Anvin" <hpa@zytor.com>
To: linux-kernel@vger.kernel.org, "Theodore T'so" <tytso@mit.edu>,
	Linus Torvalds <torvalds@linux-foundation.org>
Cc: Ingo Molnar <mingo@kernel.org>,
	w@1wt.edu, ewust@umich.edu, zakir@umich.edu, greg@kroah.com,
	mpm@selenic.com, nadiah@cs.ucsd.edu, jhalderm@umich.edu,
	tglx@linutronix.de, davem@davemloft.net, stable@vger.kernel.org,
	DJ Johnston <dj.johnston@intel.com>,
	"H. Peter Anvin" <hpa@linux.intel.com>
Subject: [PATCH] random: mix in architectural randomness in extract_buf()
Date: Wed, 25 Jul 2012 10:37:02 -0700	[thread overview]
Message-ID: <1343237822-7789-1-git-send-email-hpa@zytor.com> (raw)
In-Reply-To: <20120725151000.GA30996@thunk.org>

From: "H. Peter Anvin" <hpa@linux.intel.com>

RDRAND is so much faster than the Linux pool system that we can
always just mix in architectural randomness.

Doing this in extract_buf() lets us do this in one convenient
place, unfortunately the output size (10 bytes) is maximally
awkward.  That, plus the fact that every output byte will have
passed through extract_buf() twice means we are not being very
efficient with the RDRAND use.

Measurements show that RDRAND is 12-15 times faster than the Linux
pool system.  Doing the math shows this corresponds to about an
11.5% slowdown which is confirmed by measurements.

Users who are very performance- or power-sensitive could definitely
still benefit from being allowed to use RDRAND directly, but I
believe this version should satisfy even the most hyper-paranoid
crowd.

[ v2: changed the final memcpy() from hash.w to hash in order to
  make it more obvious that mucking with hash.l doesn't leave
  hash.w unmodified.  This doesn't have any impact on the final
  code as the Linux kernel is alwasy compiled with -fno-strict-aliasing
  but it might make it more obvious to the human reader who might get
  confused and think it is a structure. ]

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Acked-by: Ingo Molnar <mingo@kernel.org>
Cc: DJ Johnston <dj.johnston@intel.com>
---
 drivers/char/random.c | 56 +++++++++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 24 deletions(-)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 9793b40..7bc0b36 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -277,6 +277,8 @@
 #define SEC_XFER_SIZE 512
 #define EXTRACT_SIZE 10
 
+#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
+
 /*
  * The minimum number of bits of entropy before we wake up a read on
  * /dev/random.  Should be enough to do a significant reseed.
@@ -813,11 +815,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
  */
 static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 {
-	union {
-		__u32	tmp[OUTPUT_POOL_WORDS];
-		long	hwrand[4];
-	} u;
-	int	i;
+	__u32	tmp[OUTPUT_POOL_WORDS];
 
 	if (r->pull && r->entropy_count < nbytes * 8 &&
 	    r->entropy_count < r->poolinfo->POOLBITS) {
@@ -828,23 +826,17 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 		/* pull at least as many as BYTES as wakeup BITS */
 		bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
 		/* but never more than the buffer size */
-		bytes = min_t(int, bytes, sizeof(u.tmp));
+		bytes = min_t(int, bytes, sizeof(tmp));
 
 		DEBUG_ENT("going to reseed %s with %d bits "
 			  "(%d of %d requested)\n",
 			  r->name, bytes * 8, nbytes * 8, r->entropy_count);
 
-		bytes = extract_entropy(r->pull, u.tmp, bytes,
+		bytes = extract_entropy(r->pull, tmp, bytes,
 					random_read_wakeup_thresh / 8, rsvd);
-		mix_pool_bytes(r, u.tmp, bytes, NULL);
+		mix_pool_bytes(r, tmp, bytes, NULL);
 		credit_entropy_bits(r, bytes*8);
 	}
-	kmemcheck_mark_initialized(&u.hwrand, sizeof(u.hwrand));
-	for (i = 0; i < 4; i++)
-		if (arch_get_random_long(&u.hwrand[i]))
-			break;
-	if (i)
-		mix_pool_bytes(r, &u.hwrand, sizeof(u.hwrand), 0);
 }
 
 /*
@@ -901,15 +893,19 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
 static void extract_buf(struct entropy_store *r, __u8 *out)
 {
 	int i;
-	__u32 hash[5], workspace[SHA_WORKSPACE_WORDS];
+	union {
+		__u32 w[5];
+		unsigned long l[LONGS(EXTRACT_SIZE)];
+	} hash;
+	__u32 workspace[SHA_WORKSPACE_WORDS];
 	__u8 extract[64];
 	unsigned long flags;
 
 	/* Generate a hash across the pool, 16 words (512 bits) at a time */
-	sha_init(hash);
+	sha_init(hash.w);
 	spin_lock_irqsave(&r->lock, flags);
 	for (i = 0; i < r->poolinfo->poolwords; i += 16)
-		sha_transform(hash, (__u8 *)(r->pool + i), workspace);
+		sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
 
 	/*
 	 * We mix the hash back into the pool to prevent backtracking
@@ -920,14 +916,14 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
 	 * brute-forcing the feedback as hard as brute-forcing the
 	 * hash.
 	 */
-	__mix_pool_bytes(r, hash, sizeof(hash), extract);
+	__mix_pool_bytes(r, hash.w, sizeof(hash.w), extract);
 	spin_unlock_irqrestore(&r->lock, flags);
 
 	/*
 	 * To avoid duplicates, we atomically extract a portion of the
 	 * pool while mixing, and hash one final time.
 	 */
-	sha_transform(hash, extract, workspace);
+	sha_transform(hash.w, extract, workspace);
 	memset(extract, 0, sizeof(extract));
 	memset(workspace, 0, sizeof(workspace));
 
@@ -936,11 +932,23 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
 	 * pattern, we fold it in half. Thus, we always feed back
 	 * twice as much data as we output.
 	 */
-	hash[0] ^= hash[3];
-	hash[1] ^= hash[4];
-	hash[2] ^= rol32(hash[2], 16);
-	memcpy(out, hash, EXTRACT_SIZE);
-	memset(hash, 0, sizeof(hash));
+	hash.w[0] ^= hash.w[3];
+	hash.w[1] ^= hash.w[4];
+	hash.w[2] ^= rol32(hash.w[2], 16);
+
+	/*
+	 * If we have a architectural hardware random number
+	 * generator, mix that in, too.
+	 */
+	for (i = 0; i < LONGS(EXTRACT_SIZE); i++) {
+		unsigned long v;
+		if (!arch_get_random_long(&v))
+			break;
+		hash.l[i] ^= v;
+	}
+
+	memcpy(out, &hash, EXTRACT_SIZE);
+	memset(&hash, 0, sizeof(hash));
 }
 
 static ssize_t extract_entropy(struct entropy_store *r, void *buf,
-- 
1.7.11.2


  parent reply	other threads:[~2012-07-25 17:37 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-05 18:12 [PATCH 00/10] /dev/random fixups Theodore Ts'o
2012-07-05 18:12 ` [PATCH 01/10] random: make 'add_interrupt_randomness()' do something sane Theodore Ts'o
2012-07-05 18:47   ` Matt Mackall
2012-07-05 18:52     ` Linus Torvalds
2012-07-05 21:39       ` Matt Mackall
2012-07-05 21:47         ` Linus Torvalds
2012-07-05 22:00           ` Theodore Ts'o
2012-07-05 22:21             ` Linus Torvalds
2012-07-05 22:31               ` Matt Mackall
2012-07-05 22:35                 ` Linus Torvalds
2012-07-05 23:21                 ` Theodore Ts'o
2012-07-06  2:59                   ` Linus Torvalds
2012-07-06 13:01                     ` Theodore Ts'o
2012-07-06 16:24                       ` Linus Torvalds
2012-07-06 16:52                         ` Theodore Ts'o
2012-07-09 19:15                           ` Matt Mackall
2012-07-25 18:43                         ` Thomas Gleixner
     [not found]   ` <CAGsuqq2MWuFnY7PMb_2ddBNNJr80xB_JW+Wryq3mhhmQuEojpg@mail.gmail.com>
2012-07-06 21:59     ` Theodore Ts'o
2012-07-05 18:12 ` [PATCH 02/10] random: use lockless techniques when mixing entropy pools Theodore Ts'o
2012-07-05 18:18   ` Linus Torvalds
2012-07-05 18:19   ` Greg KH
2012-07-05 23:09     ` Theodore Ts'o
2012-07-05 19:10   ` Matt Mackall
2012-07-05 19:47     ` Theodore Ts'o
2012-07-05 20:45       ` Matt Mackall
2012-07-05 18:12 ` [PATCH 03/10] random: create add_device_randomness() interface Theodore Ts'o
2012-07-05 18:12 ` [PATCH 04/10] usb: feed USB device information to the /dev/random driver Theodore Ts'o
2012-07-05 18:12 ` [PATCH 05/10] net: feed /dev/random with the MAC address when registering a device Theodore Ts'o
2012-07-05 18:12 ` [PATCH 06/10] random: use the arch-specific rng in xfer_secondary_pool Theodore Ts'o
2012-07-05 18:49   ` Linus Torvalds
2012-07-05 18:12 ` [PATCH 07/10] random: add new get_random_bytes_arch() function Theodore Ts'o
2012-07-05 18:35   ` Linus Torvalds
2012-07-05 19:50     ` Theodore Ts'o
2012-07-05 21:45     ` Matt Mackall
2012-07-25  3:37   ` H. Peter Anvin
2012-07-25  7:22     ` Ingo Molnar
2012-07-25 15:10     ` Theodore Ts'o
2012-07-25 15:19       ` H. Peter Anvin
2012-07-25 17:37       ` H. Peter Anvin [this message]
2012-07-25 23:50         ` [PATCH] random: mix in architectural randomness in extract_buf() Ben Hutchings
2012-07-26  0:32           ` H. Peter Anvin
2012-07-28  2:39         ` Theodore Ts'o
2012-07-28  2:48           ` H. Peter Anvin
2012-07-26  3:16       ` [PATCH 07/10] random: add new get_random_bytes_arch() function H. Peter Anvin
2012-07-26  3:24         ` H. Peter Anvin
2012-07-05 18:12 ` [PATCH 08/10] random: unify mix_pool_bytes() and mix_pool_bytes_entropy() Theodore Ts'o
2012-07-05 18:12 ` [PATCH 09/10] random: add tracepoints for easier debugging and verification Theodore Ts'o
2012-07-05 18:12 ` [PATCH 10/10] MAINTAINERS: Theodore Ts'o is taking over the random driver Theodore Ts'o
2012-07-06 11:40 ` [PATCH 00/10] /dev/random fixups Fengguang Wu
2012-07-06 12:44   ` Theodore Ts'o
2012-07-20 20:15 ` [PATCH] dmi: Feed DMI table to /dev/random driver Tony Luck
2012-07-20 21:03   ` Matt Mackall
2012-07-21  0:56   ` Theodore Ts'o
2012-07-21  1:19     ` Tony Luck
2012-07-21  2:02       ` Theodore Ts'o
2012-07-23 16:47         ` [PATCH] random: Add comment to random_initialize() Tony Luck

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=1343237822-7789-1-git-send-email-hpa@zytor.com \
    --to=hpa@zytor.com \
    --cc=davem@davemloft.net \
    --cc=dj.johnston@intel.com \
    --cc=ewust@umich.edu \
    --cc=greg@kroah.com \
    --cc=hpa@linux.intel.com \
    --cc=jhalderm@umich.edu \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=mpm@selenic.com \
    --cc=nadiah@cs.ucsd.edu \
    --cc=stable@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    --cc=tytso@mit.edu \
    --cc=w@1wt.edu \
    --cc=zakir@umich.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).