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.
This commit is contained in:
Thomas Haller 2022-08-01 10:20:28 +02:00
parent 0f3eb6fabb
commit 3c349ee11b
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -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;