summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKarel Zak2017-08-14 10:33:06 +0200
committerKarel Zak2017-08-14 10:33:06 +0200
commit5264aebb4f822fa9147ee576562a4961ca97261d (patch)
tree1a4aac80fe48add7395e9cf1e8cb093ce0dc3e26 /lib
parentlosetup: add info about lazy detach to manpage (diff)
downloadkernel-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.c64
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;