diff mbox series

[3/4] random: get_source_long() function

Message ID CACXcFm=whnpd3v5gJAoTJ-pL27NOOkMKvD3W_RQXy1kj2B6p=g@mail.gmail.com (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show
Series random: change usage of arch_get_random_long() | expand

Commit Message

Sandy Harris Feb. 10, 2022, 2:41 p.m. UTC
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 <sandyinchina@gmail.com>
---
 drivers/char/random.c | 74 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

Comments

Greg KH Feb. 10, 2022, 2:55 p.m. UTC | #1
On Thu, Feb 10, 2022 at 10:41:53PM +0800, Sandy Harris wrote:
> 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 <sandyinchina@gmail.com>
> ---
>  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 ;
> +

Hi,

This is the friendly patch-bot of Greg Kroah-Hartman.  You have sent him
a patch that has triggered this response.  He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created.  Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.

You are receiving this message because of the following common error(s)
as indicated below:

- Your patch contains warnings and/or errors noticed by the
  scripts/checkpatch.pl tool.

- Your patch is malformed (tabs converted to spaces, linewrapped, etc.)
  and can not be applied.  Please read the file,
  Documentation/email-clients.txt in order to fix this.


If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.

thanks,

greg k-h's patch email bot
Theodore Ts'o Feb. 10, 2022, 3:42 p.m. UTC | #2
On Thu, Feb 10, 2022 at 10:41:53PM +0800, Sandy Harris wrote:
> +/**************************************************************************
> + * 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 isn't quite right.  First of all arch_get_random is as much a
hardware RNG as a arch_get_random_seed.  So trying to distinguish the
two here is confusing and blurs what is going on.

Secondly, arch_get_random_seed, on those platforms that have it, is
strictly better than arch_get_random.  It takes more CPU cycles, and
has different security properties[1], but there's no good reason to
add complexity to alternate between the two.   

[1] "RDSEED is intended for seeding a software PRNG of arbitrary
    width. RDRAND is intended for applications that merely require
    high-quality random numbers." --- Intel documentation

Finally, arch_get_random_seed and arch_get_random work in VM's, so
talking about "emulating HWRNG in a VM" doesn't make any sense.  And
as I've mentioned in my comment on the previous patch, using a CRNG to
help seed a CRNG doesn't make any sense, and isn't worth the extra
complexity.

Also, note that as the code is currently situated there isn't any
extra "work" if CONFIG_ARCH_RANDOM is disabled.  That's because
config_get_random_seed and friends are inline functions, and if it is
disabled, it will return false unconditionally, and the compiler will
optimize away the call.  Also, note that on CPU architectures which
have CPU instructions ala RDREAD and RDSEED, it's rarely disabled
since it's on by default and to disable it you need to be in
CONFIG_EXPERT mode.

Cheers,

					- Ted
diff mbox series

Patch

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