Alex Xu
2016-Jul-28 22:07 UTC
getrandom waits for a long time when /dev/random is insufficiently read from
Linux 4.6, also tried 4.7, qemu 2.6, using this C program: #include <fcntl.h> #include <stdlib.h> #include <syscall.h> #include <unistd.h> int main(int argc, char *argv[]) { char buf[16]; int fd; if (argc != 2) return 1; for (int i = 0; i < atoi(argv[1]); i++) { sleep(1); if ((fd = open("/dev/random", O_RDONLY)) == -1) return 2; if (read(fd, buf, sizeof(buf)) < 1) return 3; if (close(fd) == -1) return 4; } sleep(2); if (syscall(SYS_getrandom, buf, sizeof(buf), 0) == -1) return 5; return 0; } $ qemu-system-x86_64 -nodefaults -machine q35,accel=kvm -nographic -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -kernel linux-4.7/arch/x86/boot/bzImage -fsdev local,path="$PWD/root",security_model=none,id=root -device virtio-9p-pci,fsdev=root,mount_tag=/dev/root -device virtio-serial -chardev stdio,id=stdio -device virtconsole,chardev=stdio -monitor none -append "root=/dev/root rw rootfstype=9p rootflags=trans=virtio console=hvc0 init=/strace /test 2" execve("/test", ["/test", "2"], [/* 2 vars */]) = 0 arch_prctl(ARCH_SET_FS, 0x601098) = 0 set_tid_address(0x6010d0) = 29 nanosleep({1, 0}, 0x7ffcdb7ea6b0) = 0 open("/dev/random", O_RDONLY) = 3 read(3, "P'\333\362\352\247\212\272\357E?\343", 16) = 12 close(3) = 0 nanosleep({1, 0}, 0x7ffcdb7ea6b0) = 0 open("/dev/random", O_RDONLY) = 3 read(3, ">>9\252]\332T\322dL\203\231C\255\303\376", 16) = 16 close(3) = 0 nanosleep({2, 0}, 0x7ffcdb7ea6e0) = 0 getrandom(<some time later>[ 89.166661] random: nonblocking pool is initialized "\217\0\206\220\36t\3\353\t\227\377\356\315\320\2452", 16, 0) = 16 exit_group(0) = ? +++ exited with 0 +++ Identical command but replaced 2 iterations with 3: $ qemu-system-x86_64 -nodefaults -machine q35,accel=kvm -nographic -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -kernel linux-4.7/arch/x86/boot/bzImage -fsdev local,path="$PWD/root",security_model=none,id=root -device virtio-9p-pci,fsdev=root,mount_tag=/dev/root -device virtio-serial -chardev stdio,id=stdio -device virtconsole,chardev=stdio -monitor none -append "root=/dev/root rw rootfstype=9p rootflags=trans=virtio console=hvc0 init=/strace /test 3" execve("/test", ["/test", "3"], [/* 2 vars */]) = 0 arch_prctl(ARCH_SET_FS, 0x601098) = 0 set_tid_address(0x6010d0) = 29 nanosleep({1, 0}, 0x7ffc9e13fb70) = 0 open("/dev/random", O_RDONLY) = 3 read(3, ">\202\264\350\226\364\364\320'-\200\16", 16) = 12 close(3) = 0 nanosleep({1, 0}, 0x7ffc9e13fb70) = 0 open("/dev/random", O_RDONLY) = 3 read(3, "\377:\2076\213q0E\307\377\\\234\217\"g\254", 16) = 16 close(3) = 0 nanosleep({1, 0}, 0x7ffc9e13fb70) = 0 open("/dev/random", O_RDONLY) = 3 read(3, [ 3.312266] random: nonblocking pool is initialized "O\2112g\375\25]\270\347\v\34XP", 16) = 13 close(3) = 0 nanosleep({2, 0}, 0x7ffc9e13fba0) = 0 getrandom("\215\317\207/\324\6\300\216\332zN\351a\323\231\36", 16, 0) = 16 exit_group(0) = ? +++ exited with 0 +++ (irrelevant kernel messages have been removed for clarity) Removing the calls to "sleep" produces similar results except without sleeping or the corresponding strace output. Running both commands repeatedly also produces similar results; the timing of the getrandom return and "random: nonblocking pool is initialized" message is different for each run, but it always takes 90-100 seconds. Sorry if these aren't the right lists or if this is a known issue. Please CC me on replies.
Stephan Mueller
2016-Jul-29 05:40 UTC
getrandom waits for a long time when /dev/random is insufficiently read from
Am Donnerstag, 28. Juli 2016, 18:07:32 CEST schrieb Alex Xu: Hi Alex,> Linux 4.6, also tried 4.7, qemu 2.6, using this C program:I am not sure what problem you are referring to, but that is an expected behavior. You get partial reads when reading from /dev/random with a minimum of 64 bits. On the other hand getrandom(2) is woken up after the input_pool received 128 bits of entropy. In you strace you see that after reading 16 bytes from /dev/random, the getrandom unblocks and starts delivering. Note, in virtualized environments the current Linux /dev/random implementation collects massively less entropy compared to a bare-metal system. Hence the long wait time of your 90 to 100 secs until getrandom unblocks. Besides, even without reading from /dev/random, your getrandom will wait that long. 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); ... Ciao Stephan
Nikos Mavrogiannopoulos
2016-Jul-29 10:24 UTC
getrandom waits for a long time when /dev/random is insufficiently read from
On Fri, Jul 29, 2016 at 7:40 AM, Stephan Mueller <smueller at chronox.de> 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
Maybe Matching Threads
- getrandom waits for a long time when /dev/random is insufficiently read from
- getrandom waits for a long time when /dev/random is insufficiently read from
- getrandom waits for a long time when /dev/random is insufficiently read from
- getrandom waits for a long time when /dev/random is insufficiently read from
- getrandom waits for a long time when /dev/random is insufficiently read from