mbox series

[kvmtool,0/2] Fix virtio/rng handling in low entropy situations

Message ID 20230413165757.1728800-1-andre.przywara@arm.com (mailing list archive)
Headers show
Series Fix virtio/rng handling in low entropy situations | expand

Message

Andre Przywara April 13, 2023, 4:57 p.m. UTC
At the moment kvmtool uses the /dev/random device to back the randomness
provided by our virtio/rng implementation. We run it in non-blocking
mode, so are not affected by the nasty "can block indefinitely"
behaviour of that file. However:
- If /dev/random WOULD block, it returns EAGAIN, and we reflect that by
  adding 0 bytes of entropy to the virtio queue. However the virtio 1.x
  spec clearly says this is not allowed, and that we should always provide
  at least one random byte.
- If the guest is waiting for the random numbers, we still run into an
  effective blocking situation, because the buffer will only be filled
  very slowly, effectively stalling or blocking the guest. EDK II shows
  that behaviour, when servicing the EFI_RNG_PROTOCOL runtime service
  call, called by the kernel very early on boot.

Those two patches fix those problems, and allow to boot a Linux kernel
MUCH quicker when the host lacks good entropy sources. On a particular
system the kernel took 10 minutes to boot because of /dev/random
effectively blocking, this runs now in full speed.

The block is avoided by using /dev/urandom, there is a proper rabbit
hole in the internet out there why this is safe, even for cryptographic
applications.

I am not sure we now really need patch 2 anymore (originally I had this
one before I switched to /dev/urandom). I *think* even a read from
/dev/urandom can return early (because of a signal, for instance), so
a return with 0 bytes read seems possible.

Please have a look!

Cheers,
Andre


Andre Przywara (2):
  virtio/rng: switch to using /dev/urandom
  virtio/rng: return at least one byte of entropy

 virtio/rng.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

Comments

Jean-Philippe Brucker April 19, 2023, 1:58 p.m. UTC | #1
On Thu, Apr 13, 2023 at 05:57:55PM +0100, Andre Przywara wrote:
> I am not sure we now really need patch 2 anymore (originally I had this
> one before I switched to /dev/urandom). I *think* even a read from
> /dev/urandom can return early (because of a signal, for instance), so
> a return with 0 bytes read seems possible.

Given that this should be very rare, maybe a simple loop would be better
than switching the blocking mode?  It's certainly a good idea to apply the
"MUST" requirements from virtio.

Thanks,
Jean
Jean-Philippe Brucker April 19, 2023, 3:10 p.m. UTC | #2
On Wed, Apr 19, 2023 at 02:58:32PM +0100, Jean-Philippe Brucker wrote:
> On Thu, Apr 13, 2023 at 05:57:55PM +0100, Andre Przywara wrote:
> > I am not sure we now really need patch 2 anymore (originally I had this
> > one before I switched to /dev/urandom). I *think* even a read from
> > /dev/urandom can return early (because of a signal, for instance), so
> > a return with 0 bytes read seems possible.
> 
> Given that this should be very rare, maybe a simple loop would be better
> than switching the blocking mode?  It's certainly a good idea to apply the
> "MUST" requirements from virtio.

Digging a bit more, the manpage [1] is helpful:

	The O_NONBLOCK flag has no effect when opening /dev/urandom.
	When calling read(2) for the device /dev/urandom, reads of up to
	256 bytes will return as many bytes as are requested and will not
	be interrupted by a signal handler. Reads with a buffer over
	this limit may return less than the requested number of bytes or
	fail with the error EINTR, if interrupted by a signal handler.

So I guess you can also drop the O_NONBLOCK flag in patch 1. And for the
second one, maybe we could fallback to a 256 bytes read if the first one
fails

Thanks,
Jean

[1] https://man7.org/linux/man-pages/man4/urandom.4.html
Andre Przywara April 19, 2023, 3:31 p.m. UTC | #3
On Wed, 19 Apr 2023 16:10:13 +0100
Jean-Philippe Brucker <jean-philippe@linaro.org> wrote:

Hi Jean-Philippe,

thanks for having a look!

> On Wed, Apr 19, 2023 at 02:58:32PM +0100, Jean-Philippe Brucker wrote:
> > On Thu, Apr 13, 2023 at 05:57:55PM +0100, Andre Przywara wrote:  
> > > I am not sure we now really need patch 2 anymore (originally I had this
> > > one before I switched to /dev/urandom). I *think* even a read from
> > > /dev/urandom can return early (because of a signal, for instance), so
> > > a return with 0 bytes read seems possible.  
> > 
> > Given that this should be very rare, maybe a simple loop would be better
> > than switching the blocking mode?  It's certainly a good idea to apply the
> > "MUST" requirements from virtio.  

So originally I had this patch 2/2 on its own, still using /dev/random.
And there a read() on the O_NONBLOCKed fd would return -EAGAIN immediately
for the next 30 seconds straight, so doing this in a loop sounds very
wrong. After all blocking fd's are there to solve exactly that problem.

But indeed with /dev/urandom being much nicer to us already, and with the
below mentioned special behaviour, just a simple second try (no loop) is
sufficient.

> Digging a bit more, the manpage [1] is helpful:
> 
> 	The O_NONBLOCK flag has no effect when opening /dev/urandom.
> 	When calling read(2) for the device /dev/urandom, reads of up to
> 	256 bytes will return as many bytes as are requested and will not
> 	be interrupted by a signal handler. Reads with a buffer over
> 	this limit may return less than the requested number of bytes or
> 	fail with the error EINTR, if interrupted by a signal handler.

Right, I saw references to that behaviour on the Internet(TM), but missed
the manpage stanza. It still feels a bit awkward since this seems to rely
on some Linux implementation detail, but that's certainly fine for kvmtool
(being Linux only anyway).

> So I guess you can also drop the O_NONBLOCK flag in patch 1. And for the
> second one, maybe we could fallback to a 256 bytes read if the first one
> fails

Yes, that's certainly better and simplifies that patch.

Thanks for digging this out!

Cheers,
Andre

> 
> [1] https://man7.org/linux/man-pages/man4/urandom.4.html
>