2022-02-12 00:06:03

by Sandy Harris

[permalink] [raw]
Subject: [PATCH 3/4] random: get_source_long() function

This function gets random data from the best available source

The current code has a sequence in several places that calls one or
more of arch_get_random_long() or related functions, checks the
return value(s) and on failure falls back to random_get_entropy().
get_source long() is intended to replace all such sequences.

This is better in several ways. In the fallback case it gives
much more random output than random_get_entropy(). It never
wastes effort by calling arch_get_random_long() et al. when
the relevant config variables are not set. When it does use
arch_get_random_long(), it does not deliver raw output from
that function but masks it by mixing with stored random data.

Signed-off-by: Sandy Harris <[email protected]>
---
drivers/char/random.c | 74 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 9edf65ad4259..6c77fd056f66 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1031,6 +1031,80 @@ static void xtea_rekey(void)
xtea_iterations = 0 ;
}

+/**************************************************************************
+ * Load a 64-bit word with data from whatever source we have
+ *
+ * arch_get_random_long()
+ * hardware RNG
+ * emulated HWRNG in a VM
+ *
+ * When there are two sources, alternate.
+ * If you have no better source, or if one fails,
+ * fall back to get_xtea_long()
+ *
+ * This function always succeeds, which allows some
+ * simplifications elsewhere in the code.
+ *
+ * This is intended only for use inside the kernel.
+ * Any data sent to user space should come from the
+ * chacha-based crng construction.
+ ***************************************************************************/
+
+static int load_count = 0;
+#define COUNT_RESTART 128
+
+/*
+ * Add a mask variable so we can avoid using data
+ * from any source directly as output.
+ */
+static unsigned long source_mask ;
+
+/*
+ * Use xtea sometimes even if we have a good source
+ * Avoids trusting the source completely
+ */
+#define MIX_MASK 15
+
+static void get_source_long(unsigned long *x)
+{
+ int a, b ;
+ int ret = 0 ;
+
+ if (load_count >= COUNT_RESTART)
+ load_count = 0 ;
+ if (load_count == 0)
+ get_xtea_long(&source_mask) ;
+
+ a = IS_ENABLED(CONFIG_ARCH_RANDOM) ;
+ b = IS_ENABLED(CONFIG_HW_RANDOM) ;
+
+ if (a && b) {
+ if (load_count & 1)
+ ret = arch_get_random_long(x) ;
+ else ret = get_hw_long(x) ;
+ }
+ if (a && !b) {
+ if (load_count&MIX_MASK)
+ ret = arch_get_random_long(x) ;
+ }
+ if (!a && b) {
+ if (load_count&MIX_MASK)
+ ret = get_hw_long(x) ;
+ }
+ /*
+ * no source configured
+ * or configured one failed
+ *
+ * or it is just time for tea,
+ * (load_count&MIX_MASK) == 0
+ */
+ if (!ret)
+ get_xtea_long(x) ;
+
+ *x += source_mask ;
+ load_count++ ;
+}
+
/*********************************************************************
*
* CRNG using CHACHA20
--
2.25.1