Re: getrandom waits for a long time when /dev/random is insufficiently read from

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am Freitag, 29. Juli 2016, 09:03:45 CEST schrieb Alex Xu:

Hi Alex,

> On Fri, 29 Jul 2016 12:24:27 +0200
> 
> Nikos Mavrogiannopoulos <nmav@xxxxxxxxxx> wrote:
> > On Fri, Jul 29, 2016 at 7:40 AM, Stephan Mueller
> > 
> > <smueller@xxxxxxxxxx> wrote:
> > > And finally, you have a coding error that is very very common but
> > > fatal when reading from /dev/random: you do not account for short
> > > reads which implies that your loop continues even in the case of
> > > short reads.
> > > 
> > > Fix your code with something like the following:
> > > int read_random(char *buf, size_t buflen)
> > > {
> > > 
> > >         int fd = 0;
> > >         ssize_t ret = 0;
> > >         size_t len = 0;
> > >         
> > >         fd = open("/dev/random", O_RDONLY|O_CLOEXEC);
> > >         if(0 > fd)
> > >         
> > >                 return fd;
> > >         
> > >         do {
> > >         
> > >                 ret = read(fd, (buf + len), (buflen - len));
> > >                 if (0 < ret)
> > >                 
> > >                         len += ret;
> > >         
> > >         } while ((0 < ret || EINTR == errno || ERESTART == errno)
> > >         
> > >                  && buflen > len);
> > 
> > Unless there is a documentation error, the same is required when using
> > getrandom(). It can also return short as well as to be interrupted.
> > 
> > regards,
> > Nikos
> 
> I am aware that (according to the documentation) both random(4) and
> getrandom(2) may not return the full size of the read. However, that is
> (as far as I know) not relevant to the point that I am making.
> 
> What I am saying is that based on my understanding of random(4) and
> getrandom(2), at boot, given the same buffer size, reading
> from /dev/random should have the same behavior as calling getrandom
> passing no flags.

/dev/random can return after at least 64 bits received in the input_pool 
whereas getrandom waits for 128 bits.
> 
> The buffer size can also be set to 1 with similar results, but the
> iteration number for success must be then increased to a large number.
> IME 30 worked consistently while 29 hung; your results may vary.
> 
> The interesting thing is though, if GRND_RANDOM is passed to getrandom,
> then it does not hang and returns 1 byte immediately (whether or not
> GRND_NONBLOCK is set).

Sure, because there is one byte in the input_pool at the time user space 
boots. Note again, /dev/random waits until having 64 bits.

> 
> 1, 2..29: reads all return 1 byte, getrandom pauses for 90-110 secs then
> returns 1 byte
> 30+: reads all return 1 byte, getrandom immediately returns 1 byte
> -r 0: getrandom immediately returns 1 byte
> -r 1, -r 2, -r 128, -r 256: reads all return 1 byte, getrandom
> immediately returns 1 byte
> 
I would say that this is expected.

> Moving the open and close calls outside of the loop produces the same
> results. Writing 4096 bytes to /dev/urandom also has no effect.

Sure, it does not update the input_pool. Only the IOCTL can update the 
input_pool from user space.
> 
> In my opinion, assuming I am not doing something terribly wrong, this
> constitutes a bug in the kernel's handling of getrandom calls at boot,
> possibly only when the primary source of entropy is virtio.

Nope, I do not think that this is true:

- /dev/random returns one byte for one byte of entropy received, but it has a 
lower limit of 64 bits

- getrandom behaves like /dev/urandom (i.e. nonblocking) except during boot 
where it waits until the RNG has collected 128 bits before operating like a 
DRNG that is seeded once in a while when entropy comes in.


Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux