diff mbox series

um: seed rng using host OS rng

Message ID 20220712232738.77737-1-Jason@zx2c4.com
State Superseded
Headers show
Series um: seed rng using host OS rng | expand

Commit Message

Jason A. Donenfeld July 12, 2022, 11:27 p.m. UTC
UML generally does not provide access to special CPU instructions like
RDRAND, and execution tends to be rather deterministic, with no real
hardware interrupts, making good randomness really very hard, if not
all together impossible. Not only is this a security eyebrow raiser, but
it's also quite annoying when trying to do various pieces of UML-based
automation that takes a long time to boot, if ever.

Fix this by trivially calling getrandom() in the host and using that
seed as "bootloader randomness", which initializes the rng immediately
at UML boot.

The old behavior can be restored the same way as on any other arch, by
way of CONFIG_TRUST_BOOTLOADER_RANDOMNESS=n or
random.trust_bootloader=0. So seen from that perspective, this just
makes UML act like other archs, which is positive in its own right.

Cc: stable@vger.kernel.org
Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 arch/um/include/shared/os.h | 7 +++++++
 arch/um/kernel/um_arch.c    | 8 ++++++++
 arch/um/os-Linux/util.c     | 6 ++++++
 3 files changed, 21 insertions(+)

Comments

Anton Ivanov July 13, 2022, 6:58 a.m. UTC | #1
On 13/07/2022 00:27, Jason A. Donenfeld wrote:
> UML generally does not provide access to special CPU instructions like
> RDRAND, and execution tends to be rather deterministic, with no real
> hardware interrupts, making good randomness really very hard, if not
> all together impossible. Not only is this a security eyebrow raiser, but
> it's also quite annoying when trying to do various pieces of UML-based
> automation that takes a long time to boot, if ever.
> 
> Fix this by trivially calling getrandom() in the host and using that
> seed as "bootloader randomness", which initializes the rng immediately
> at UML boot.
> 
> The old behavior can be restored the same way as on any other arch, by
> way of CONFIG_TRUST_BOOTLOADER_RANDOMNESS=n or
> random.trust_bootloader=0. So seen from that perspective, this just
> makes UML act like other archs, which is positive in its own right.
> 
> Cc: stable@vger.kernel.org
> Cc: Johannes Berg <johannes@sipsolutions.net>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> ---
>   arch/um/include/shared/os.h | 7 +++++++
>   arch/um/kernel/um_arch.c    | 8 ++++++++
>   arch/um/os-Linux/util.c     | 6 ++++++
>   3 files changed, 21 insertions(+)
> 
> diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
> index fafde1d5416e..79644dd88d58 100644
> --- a/arch/um/include/shared/os.h
> +++ b/arch/um/include/shared/os.h
> @@ -11,6 +11,12 @@
>   #include <irq_user.h>
>   #include <longjmp.h>
>   #include <mm_id.h>
> +/* This is to get size_t */
> +#ifndef __UM_HOST__
> +#include <linux/types.h>
> +#else
> +#include <stddef.h>
> +#endif
>   
>   #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
>   
> @@ -243,6 +249,7 @@ extern void stack_protections(unsigned long address);
>   extern int raw(int fd);
>   extern void setup_machinename(char *machine_out);
>   extern void setup_hostinfo(char *buf, int len);
> +extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
>   extern void os_dump_core(void) __attribute__ ((noreturn));
>   extern void um_early_printk(const char *s, unsigned int n);
>   extern void os_fix_helper_signals(void);
> diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
> index 0760e24f2eba..74f3efd96bd4 100644
> --- a/arch/um/kernel/um_arch.c
> +++ b/arch/um/kernel/um_arch.c
> @@ -16,6 +16,7 @@
>   #include <linux/sched/task.h>
>   #include <linux/kmsg_dump.h>
>   #include <linux/suspend.h>
> +#include <linux/random.h>
>   
>   #include <asm/processor.h>
>   #include <asm/cpufeature.h>
> @@ -406,6 +407,8 @@ int __init __weak read_initrd(void)
>   
>   void __init setup_arch(char **cmdline_p)
>   {
> +	u8 rng_seed[32];
> +
>   	stack_protections((unsigned long) &init_thread_info);
>   	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
>   	mem_total_pages(physmem_size, iomem_size, highmem);
> @@ -416,6 +419,11 @@ void __init setup_arch(char **cmdline_p)
>   	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
>   	*cmdline_p = command_line;
>   	setup_hostinfo(host_info, sizeof host_info);
> +
> +	if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
> +		add_bootloader_randomness(rng_seed, sizeof(rng_seed));
> +		memzero_explicit(rng_seed, sizeof(rng_seed));
> +	}
>   }
>   
>   void __init check_bugs(void)
> diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
> index 41297ec404bf..fc0f2a9dee5a 100644
> --- a/arch/um/os-Linux/util.c
> +++ b/arch/um/os-Linux/util.c
> @@ -14,6 +14,7 @@
>   #include <sys/wait.h>
>   #include <sys/mman.h>
>   #include <sys/utsname.h>
> +#include <sys/random.h>
>   #include <init.h>
>   #include <os.h>
>   
> @@ -96,6 +97,11 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
>   			exit(127);
>   }
>   
> +ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
> +{
> +	return getrandom(buf, len, flags);
> +}
> +
>   /*
>    * UML helper threads must not handle SIGWINCH/INT/TERM
>    */

I am probably missing something here.

IIRC UML RNG device reads directly from host.

If you are using UMLs own /dev/random you are effectively using the host 
one.

So unless I am mistaken, you need extra randomness only if you do not 
have UMLs /dev/random compiled in.

Apologies for possible duplicates - I initially did not reply-all by 
mistake.
Johannes Berg July 13, 2022, 7:03 a.m. UTC | #2
On Wed, 2022-07-13 at 07:58 +0100, Anton Ivanov wrote:
> 
> IIRC UML RNG device reads directly from host.

Yes, but that's a /dev/hwrng device, so you still need some userspace to
feed entropy from that into /dev/random.

> If you are using UMLs own /dev/random you are effectively using the host 
> one.

> So unless I am mistaken, you need extra randomness only if you do not 
> have UMLs /dev/random compiled in.

No, neither of those is true.

johannes
Johannes Berg July 13, 2022, 7:05 a.m. UTC | #3
On Wed, 2022-07-13 at 01:27 +0200, Jason A. Donenfeld wrote:
> 
> +++ b/arch/um/include/shared/os.h
> @@ -11,6 +11,12 @@
>  #include <irq_user.h>
>  #include <longjmp.h>
>  #include <mm_id.h>
> +/* This is to get size_t */
> +#ifndef __UM_HOST__
> +#include <linux/types.h>
> +#else
> +#include <stddef.h>
> +#endif
>  
>  #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
>  
> @@ -243,6 +249,7 @@ extern void stack_protections(unsigned long address);
>  extern int raw(int fd);
>  extern void setup_machinename(char *machine_out);
>  extern void setup_hostinfo(char *buf, int len);
> +extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);

For me, this doesn't compile, and per the man-page on my system, ssize_t
requires <sys/types.h>, not <stddef.h>?

johannes
Anton Ivanov July 13, 2022, 7:05 a.m. UTC | #4
On 13/07/2022 08:03, Johannes Berg wrote:
> On Wed, 2022-07-13 at 07:58 +0100, Anton Ivanov wrote:
>> IIRC UML RNG device reads directly from host.
> Yes, but that's a /dev/hwrng device, so you still need some userspace to
> feed entropy from that into /dev/random.
>
>> If you are using UMLs own /dev/random you are effectively using the host
>> one.
>> So unless I am mistaken, you need extra randomness only if you do not
>> have UMLs /dev/random compiled in.
> No, neither of those is true.

OK, Cool.

>
> johannes
>
>
>
> _______________________________________________
> linux-um mailing list
> linux-um@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-um
>
Anton Ivanov July 13, 2022, 7:06 a.m. UTC | #5
On 13/07/2022 00:27, Jason A. Donenfeld wrote:
> UML generally does not provide access to special CPU instructions like
> RDRAND, and execution tends to be rather deterministic, with no real
> hardware interrupts, making good randomness really very hard, if not
> all together impossible. Not only is this a security eyebrow raiser, but
> it's also quite annoying when trying to do various pieces of UML-based
> automation that takes a long time to boot, if ever.
> 
> Fix this by trivially calling getrandom() in the host and using that
> seed as "bootloader randomness", which initializes the rng immediately
> at UML boot.
> 
> The old behavior can be restored the same way as on any other arch, by
> way of CONFIG_TRUST_BOOTLOADER_RANDOMNESS=n or
> random.trust_bootloader=0. So seen from that perspective, this just
> makes UML act like other archs, which is positive in its own right.
> 
> Cc: stable@vger.kernel.org
> Cc: Johannes Berg <johannes@sipsolutions.net>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> ---
>   arch/um/include/shared/os.h | 7 +++++++
>   arch/um/kernel/um_arch.c    | 8 ++++++++
>   arch/um/os-Linux/util.c     | 6 ++++++
>   3 files changed, 21 insertions(+)
> 
> diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
> index fafde1d5416e..79644dd88d58 100644
> --- a/arch/um/include/shared/os.h
> +++ b/arch/um/include/shared/os.h
> @@ -11,6 +11,12 @@
>   #include <irq_user.h>
>   #include <longjmp.h>
>   #include <mm_id.h>
> +/* This is to get size_t */
> +#ifndef __UM_HOST__
> +#include <linux/types.h>
> +#else
> +#include <stddef.h>
> +#endif
>   
>   #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
>   
> @@ -243,6 +249,7 @@ extern void stack_protections(unsigned long address);
>   extern int raw(int fd);
>   extern void setup_machinename(char *machine_out);
>   extern void setup_hostinfo(char *buf, int len);
> +extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
>   extern void os_dump_core(void) __attribute__ ((noreturn));
>   extern void um_early_printk(const char *s, unsigned int n);
>   extern void os_fix_helper_signals(void);
> diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
> index 0760e24f2eba..74f3efd96bd4 100644
> --- a/arch/um/kernel/um_arch.c
> +++ b/arch/um/kernel/um_arch.c
> @@ -16,6 +16,7 @@
>   #include <linux/sched/task.h>
>   #include <linux/kmsg_dump.h>
>   #include <linux/suspend.h>
> +#include <linux/random.h>
>   
>   #include <asm/processor.h>
>   #include <asm/cpufeature.h>
> @@ -406,6 +407,8 @@ int __init __weak read_initrd(void)
>   
>   void __init setup_arch(char **cmdline_p)
>   {
> +	u8 rng_seed[32];
> +
>   	stack_protections((unsigned long) &init_thread_info);
>   	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
>   	mem_total_pages(physmem_size, iomem_size, highmem);
> @@ -416,6 +419,11 @@ void __init setup_arch(char **cmdline_p)
>   	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
>   	*cmdline_p = command_line;
>   	setup_hostinfo(host_info, sizeof host_info);
> +
> +	if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
> +		add_bootloader_randomness(rng_seed, sizeof(rng_seed));
> +		memzero_explicit(rng_seed, sizeof(rng_seed));
> +	}
>   }
>   
>   void __init check_bugs(void)
> diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
> index 41297ec404bf..fc0f2a9dee5a 100644
> --- a/arch/um/os-Linux/util.c
> +++ b/arch/um/os-Linux/util.c
> @@ -14,6 +14,7 @@
>   #include <sys/wait.h>
>   #include <sys/mman.h>
>   #include <sys/utsname.h>
> +#include <sys/random.h>
>   #include <init.h>
>   #include <os.h>
>   
> @@ -96,6 +97,11 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
>   			exit(127);
>   }
>   
> +ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
> +{
> +	return getrandom(buf, len, flags);
> +}
> +
>   /*
>    * UML helper threads must not handle SIGWINCH/INT/TERM
>    */

Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com>
Jason A. Donenfeld July 13, 2022, 9:53 a.m. UTC | #6
Hi Johannes,

Thanks for the review.

On Wed, Jul 13, 2022 at 09:05:03AM +0200, Johannes Berg wrote:
> On Wed, 2022-07-13 at 01:27 +0200, Jason A. Donenfeld wrote:
> > 
> > +++ b/arch/um/include/shared/os.h
> > @@ -11,6 +11,12 @@
> >  #include <irq_user.h>
> >  #include <longjmp.h>
> >  #include <mm_id.h>
> > +/* This is to get size_t */
> > +#ifndef __UM_HOST__
> > +#include <linux/types.h>
> > +#else
> > +#include <stddef.h>
> > +#endif
> >  
> >  #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
> >  
> > @@ -243,6 +249,7 @@ extern void stack_protections(unsigned long address);
> >  extern int raw(int fd);
> >  extern void setup_machinename(char *machine_out);
> >  extern void setup_hostinfo(char *buf, int len);
> > +extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
> 
> For me, this doesn't compile, and per the man-page on my system, ssize_t
> requires <sys/types.h>, not <stddef.h>?

What you say about types.h strikes me as true from how libc programming
usually works everywhere else. But I actually copy and pasted that
snippet, including the comment, from user.h. So I guess user.h doesn't
break because of something else. Anyway, I'll change it to sys/types.h
and send a v2.

Jason
diff mbox series

Patch

diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index fafde1d5416e..79644dd88d58 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -11,6 +11,12 @@ 
 #include <irq_user.h>
 #include <longjmp.h>
 #include <mm_id.h>
+/* This is to get size_t */
+#ifndef __UM_HOST__
+#include <linux/types.h>
+#else
+#include <stddef.h>
+#endif
 
 #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
 
@@ -243,6 +249,7 @@  extern void stack_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
+extern ssize_t os_getrandom(void *buf, size_t len, unsigned int flags);
 extern void os_dump_core(void) __attribute__ ((noreturn));
 extern void um_early_printk(const char *s, unsigned int n);
 extern void os_fix_helper_signals(void);
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 0760e24f2eba..74f3efd96bd4 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -16,6 +16,7 @@ 
 #include <linux/sched/task.h>
 #include <linux/kmsg_dump.h>
 #include <linux/suspend.h>
+#include <linux/random.h>
 
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
@@ -406,6 +407,8 @@  int __init __weak read_initrd(void)
 
 void __init setup_arch(char **cmdline_p)
 {
+	u8 rng_seed[32];
+
 	stack_protections((unsigned long) &init_thread_info);
 	setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
 	mem_total_pages(physmem_size, iomem_size, highmem);
@@ -416,6 +419,11 @@  void __init setup_arch(char **cmdline_p)
 	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
 	setup_hostinfo(host_info, sizeof host_info);
+
+	if (os_getrandom(rng_seed, sizeof(rng_seed), 0) == sizeof(rng_seed)) {
+		add_bootloader_randomness(rng_seed, sizeof(rng_seed));
+		memzero_explicit(rng_seed, sizeof(rng_seed));
+	}
 }
 
 void __init check_bugs(void)
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 41297ec404bf..fc0f2a9dee5a 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -14,6 +14,7 @@ 
 #include <sys/wait.h>
 #include <sys/mman.h>
 #include <sys/utsname.h>
+#include <sys/random.h>
 #include <init.h>
 #include <os.h>
 
@@ -96,6 +97,11 @@  static inline void __attribute__ ((noreturn)) uml_abort(void)
 			exit(127);
 }
 
+ssize_t os_getrandom(void *buf, size_t len, unsigned int flags)
+{
+	return getrandom(buf, len, flags);
+}
+
 /*
  * UML helper threads must not handle SIGWINCH/INT/TERM
  */