diff options
author | Karel Zak | 2017-08-14 10:33:06 +0200 |
---|---|---|
committer | Karel Zak | 2017-08-14 10:33:06 +0200 |
commit | 5264aebb4f822fa9147ee576562a4961ca97261d (patch) | |
tree | 1a4aac80fe48add7395e9cf1e8cb093ce0dc3e26 /lib | |
parent | losetup: add info about lazy detach to manpage (diff) | |
download | kernel-qcow2-util-linux-5264aebb4f822fa9147ee576562a4961ca97261d.tar.gz kernel-qcow2-util-linux-5264aebb4f822fa9147ee576562a4961ca97261d.tar.xz kernel-qcow2-util-linux-5264aebb4f822fa9147ee576562a4961ca97261d.zip |
lib/randutils: improve getrandom() usage
The getrandom() does not have to return all requested bytes (missing
entropy or when interrupted by signal). The current implementation in
util-linux stupidly asks for all random data again, rather than only
for missing bytes.
The current code also does not care if we repeat our requests for
ever; that's bad.
This patch uses the same way as we already use for reading from
/dev/urandom. It means:
* repeat getrandom() for only missing bytes
* limit number of unsuccessful request (16 times)
* fallback to /dev/urandom on ENOSYS (old kernel or so...)
Addresses: https://github.com/karelzak/util-linux/issues/496
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/randutils.c | 64 |
1 files changed, 46 insertions, 18 deletions
diff --git a/lib/randutils.c b/lib/randutils.c index 7d85dc841..5cd1c9976 100644 --- a/lib/randutils.c +++ b/lib/randutils.c @@ -95,27 +95,39 @@ int random_get_fd(void) */ void random_get_bytes(void *buf, size_t nbytes) { - size_t i; unsigned char *cp = (unsigned char *)buf; + size_t i, n = nbytes; + int lose_counter = 0; #ifdef HAVE_GETRANDOM - errno = 0; - while (getrandom(buf, nbytes, 0) != (ssize_t)nbytes) { - if (errno == EINTR) + while (n > 0) { + int x; + + errno = 0; + x = getrandom(cp, n, 0); + if (x > 0) { /* success */ + n -= x; + cp += x; + lose_counter = 0; + } else if (errno == ENOSYS) { /* kernel without getrandom() */ + break; + } else { + if (lose_counter++ > 16) /* entropy problem? */ + break; continue; - break; + } } + if (errno == ENOSYS) +#endif + /* - * We've been built against headers that support getrandom, - * but the running kernel does not. - * Fallback to reading from /dev/{u,}random as before + * We've been built against headers that support getrandom, but the + * running kernel does not. Fallback to reading from /dev/{u,}random + * as before */ -#endif { - size_t n = nbytes; int fd = random_get_fd(); - int lose_counter = 0; if (fd >= 0) { while (n > 0) { @@ -153,7 +165,6 @@ void random_get_bytes(void *buf, size_t nbytes) sizeof(ul_jrand_seed)-sizeof(unsigned short)); } #endif - return; } @@ -181,15 +192,32 @@ const char *random_tell_source(void) } #ifdef TEST_PROGRAM_RANDUTILS -int main(int argc __attribute__ ((__unused__)), - char *argv[] __attribute__ ((__unused__))) +int main(int argc, char *argv[]) { - unsigned int v, i; + size_t i, n; + int64_t *vp, v; + char *buf; + size_t bufsz; + + n = argc == 1 ? 16 : atoi(argv[1]); - /* generate and print 10 random numbers */ - for (i = 0; i < 10; i++) { + printf("Multiple random calls:\n"); + for (i = 0; i < n; i++) { random_get_bytes(&v, sizeof(v)); - printf("%d\n", v); + printf("#%02zu: %25ju\n", i, v); + } + + + printf("One random call:\n"); + bufsz = n * sizeof(*vp); + buf = malloc(bufsz); + if (!buf) + err(EXIT_FAILURE, "failed to allocate buffer"); + + random_get_bytes(buf, bufsz); + for (i = 0; i < n; i++) { + vp = (int64_t *) (buf + (i * sizeof(*vp))); + printf("#%02zu: %25ju\n", i, *vp); } return EXIT_SUCCESS; |