From 3c349ee11bee6a1e3515f9a2ada3963c1153edd4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 1 Aug 2022 10:20:28 +0200 Subject: [PATCH] glib-aux: reseed state for "bad" random bytes every time nm_utils_random_bytes() is supposed to give us good random number from kernel. It guarantees to always provide some bytes, and it has a boolean return value that estimates whether the bytes are good randomness. In practice, most callers ignore that return value, because what would they do about it anyway? Of course, we want to primarily use getrandom() (or "/dev/urandom"). But if we fail to get random bytes from them, we have a fallback path that tries to generate "random" bytes. It does so, by initializing a global seed from various sources, and keep sha256 hashing the buffer in a loop. That's certainly not efficient nor elegant, but we already are in a fallback path. Still, we can do slightly better. Instead of just using the global state and keep updating it (entirely deterministically), every time also mix in the results from getrandom() and a current timestamp. The idea is that if you have a virtual machine that gets cloned, we don't want that our global state keeps giving the same random numbers. In particular, because getrandom() might handle that case, even if it doesn't have good entropy. --- src/libnm-glib-aux/nm-random-utils.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libnm-glib-aux/nm-random-utils.c b/src/libnm-glib-aux/nm-random-utils.c index 3a8ba64f71..9c44b9b8c0 100644 --- a/src/libnm-glib-aux/nm-random-utils.c +++ b/src/libnm-glib-aux/nm-random-utils.c @@ -72,6 +72,10 @@ typedef struct _nm_packed { guint8 u8[NM_UTILS_CHECKSUM_LENGTH_SHA256 / 2]; guint32 u32[((NM_UTILS_CHECKSUM_LENGTH_SHA256 / 2) + 3) / 4]; } rand_vals; +#if HAVE_GETRANDOM + guint8 rand_vals_getrandom[16]; +#endif + gint16 rand_vals_timestamp; GRand *rand; } BadRandState; @@ -168,6 +172,21 @@ _bad_random_bytes(guint8 *buf, gsize n) nm_utils_checksum_get_digest(sum, gl_state.sha_digest.full); } +#if HAVE_GETRANDOM + { + ssize_t r; + + /* This is likely to fail, because we already failed a moment earlier. Still, give + * it a try. */ + r = getrandom(gl_state.rand_vals_getrandom, + sizeof(gl_state.rand_vals_getrandom), + GRND_INSECURE | GRND_NONBLOCK); + (void) r; + } +#endif + + gl_state.rand_vals_timestamp = nm_utils_clock_gettime_nsec(CLOCK_BOOTTIME); + while (TRUE) { int i;