Opened 6 years ago
Closed 2 years ago
#14937 closed bug (fixed)
Tiny chunks of entropy from /dev/urandom when using virtio RNG
Reported by: | kallisti5 | Owned by: | nobody |
---|---|---|---|
Priority: | normal | Milestone: | R1/beta4 |
Component: | Drivers | Version: | R1/Development |
Keywords: | urandom | Cc: | |
Blocked By: | Blocking: | ||
Platform: | All |
Description (last modified by )
/dev/urandom on Haiku seems to only offer up small 16 byte chunks of entropy. This behaviour differs from other platforms. I saw this while working on WireGuard under Haiku.
#include <errno.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <inttypes.h> int main() { int len = 128; int ret = 0; uint8_t key[len]; int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { fprintf(stderr, "Unable to open /dev/urandom!"); return fd; } int attempts = 0; while (ret < len) { ssize_t remaining = len - ret; ssize_t got = read(fd, key + ret, remaining); ret += got; if (attempts > 512) { fprintf(stderr, "Unable to get enough entropy from /dev/urandom!"); close(fd); return -1; } fprintf(stdout, "Attempt %d: Got %d, giving %d total!\n", attempts, got, ret); attempts++; } close(fd); return ret; }
Result on Haiku:
~> ./a.out Attempt 0: Got 8, giving 8 total! Attempt 1: Got 16, giving 24 total! Attempt 2: Got 16, giving 40 total! Attempt 3: Got 16, giving 56 total! Attempt 4: Got 16, giving 72 total! Attempt 5: Got 16, giving 88 total! Attempt 6: Got 16, giving 104 total! Attempt 7: Got 16, giving 120 total! Attempt 8: Got 8, giving 128 total!
Result on Linux:
$ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total! $ ./a.out Attempt 0: Got 128, giving 128 total!
Change History (10)
comment:1 by , 6 years ago
Description: | modified (diff) |
---|
comment:2 by , 6 years ago
comment:3 by , 6 years ago
We need to finish an arc4random implementation (we have a WIP one in Gerrit but it needs to be actually connected to entropy sources) and then we can easily use that for feeding the devices.
comment:4 by , 6 years ago
No, this is only for userland. The kernel random device behaves differently than this in the BSDs for a reason. For one, random and urandom behave the same way, and they both block only during the boot before the pool has been seeded. That way entropy is never "exhausted" like on Linux.
comment:5 by , 5 years ago
rng-tools offers some neat test programs for random sources of data's... randomness.
Here are a few examples from my linux machine...
[root@eris ~]# cat /dev/hwrng | rngtest -t 10 rngtest 6.9 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... rngtest: bits received from input: 500040032 rngtest: FIPS 140-2 successes: 24987 rngtest: FIPS 140-2 failures: 15 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 3 rngtest: FIPS 140-2(2001-10-10) Runs: 7 rngtest: FIPS 140-2(2001-10-10) Long run: 5 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=992.744; avg=71153.961; max=19531250.000)Kibits/s rngtest: FIPS tests speed: (min=58.869; avg=152.150; max=185.179)Mibits/s rngtest: Program run time: 10016917 microseconds
[root@eris ~]# cat /dev/random | rngtest -t 10 rngtest 6.9 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... rngtest: bits received from input: 72700032 rngtest: FIPS 140-2 successes: 3632 rngtest: FIPS 140-2 failures: 3 rngtest: FIPS 140-2(2001-10-10) Monobit: 1 rngtest: FIPS 140-2(2001-10-10) Poker: 1 rngtest: FIPS 140-2(2001-10-10) Runs: 1 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=2.064; avg=7.433; max=8.504)Mibits/s rngtest: FIPS tests speed: (min=56.936; avg=103.244; max=183.399)Mibits/s rngtest: Program run time: 10000423 microseconds
[root@eris ~]# cat /dev/urandom | rngtest -t 10 rngtest 6.9 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... rngtest: bits received from input: 1788660032 rngtest: FIPS 140-2 successes: 89373 rngtest: FIPS 140-2 failures: 60 rngtest: FIPS 140-2(2001-10-10) Monobit: 9 rngtest: FIPS 140-2(2001-10-10) Poker: 12 rngtest: FIPS 140-2(2001-10-10) Runs: 18 rngtest: FIPS 140-2(2001-10-10) Long run: 21 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=476.837; avg=20203.708; max=19073.486)Mibits/s rngtest: FIPS tests speed: (min=68.857; avg=172.168; max=185.179)Mibits/s rngtest: Program run time: 10001792 microseconds
And my TrueRNG USB dongle.
[root@eris ~]# cat /dev/TrueRNG | rngtest -t 10 rngtest 6.9 Copyright (c) 2004 by Henrique de Moraes Holschuh This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. rngtest: starting FIPS tests... rngtest: bits received from input: 3360032 rngtest: FIPS 140-2 successes: 168 rngtest: FIPS 140-2 failures: 0 rngtest: FIPS 140-2(2001-10-10) Monobit: 0 rngtest: FIPS 140-2(2001-10-10) Poker: 0 rngtest: FIPS 140-2(2001-10-10) Runs: 0 rngtest: FIPS 140-2(2001-10-10) Long run: 0 rngtest: FIPS 140-2(2001-10-10) Continuous run: 0 rngtest: input channel speed: (min=325.570; avg=329.150; max=335.508)Kibits/s rngtest: FIPS tests speed: (min=70.905; avg=97.157; max=174.986)Mibits/s rngtest: Program run time: 10003878 microseconds
comment:6 by , 4 years ago
Looking at our random implementation, by default we use the Yarrow random number generator which will always fill the passed buffer completely.
It looks like we also have a virtio driver, which will get randomness from the host (added in 8d2bf6953e851d431fc67de1bc970c40afa79e9f). The commit message mentions that "this can have the undesired effect of rendering /dev/urandom slow".
Were you using that when you made this test? Because I tried to run your code and did not reproduce your problem without enabling virtio random. Then I tried enabling virtio random in qemu (using the command line from the commit message) and I got a SMAP violation on boot. Apparently the virtio random driver was never updated to use user_memcpy?
I think the virtio random should be used as an additional or alternative entropy source for the Yarrow RNG, and not replace it completely.
comment:7 by , 4 years ago
Summary: | Tiny chunks of entropy from /dev/urandom → Tiny chunks of entropy from /dev/urandom when using virtio RNG |
---|
comment:8 by , 4 years ago
We should really just adopt OpenBSD's model, which Linux is now adopting, which is to read a fixed amount of data from the RNG and use it to seed a CSPRNG.
comment:9 by , 4 years ago
OpenBSD implementation for reference: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/dev/rnd.c?rev=1.221&content-type=text/x-cvsweb-markup
Key differences:
- Our CSPRNG is Yarrow (it was used by FreeBSD and Apple, they both switched to Fortuna). OpenBSD uses ChaCha20.
- Our single entropy source is kernel scheduling by calling thread_yield and reading system_time. OpenBSD uses a mix of previous boot randomness (stored on disk and reloaded at boot), randomness from the bootloader, hardware RNG is available, device probing, and interrupt timings
The architecture is otherwise generally the same. I don't know how it took so long for Linux to do it as well. Yet again one thing we got right long before them.
What we need is connect more entropy sources, and perhaps switching to a different CSPRNG algorithm. But we already use the correct model in the default case.
With virtio, however, the way things were done is that we rely completely on the host to provide randomness. We should change that so virtio is only an entropy source used to seed our own CSPRNG.
comment:10 by , 2 years ago
Milestone: | Unscheduled → R1/beta4 |
---|---|
Resolution: | → fixed |
Status: | new → closed |
This seems to be fixed by korli's recent refactors to the random device. At least the test given in the original ticket now matches Linux's behavior. I merged the first patch at least into the beta4 branch.
We should probably replace our /dev/random and /dev/urandom with OpenBSD's, or some variant thereof.