diff --git a/src/basic/missing_random.h b/src/basic/missing_random.h index 2e76031b32..17af87a3ae 100644 --- a/src/basic/missing_random.h +++ b/src/basic/missing_random.h @@ -14,3 +14,7 @@ #ifndef GRND_RANDOM #define GRND_RANDOM 0x0002 #endif + +#ifndef GRND_INSECURE +#define GRND_INSECURE 0x0004 +#endif diff --git a/src/basic/random-util.c b/src/basic/random-util.c index c32e6e2aac..73cc7272db 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -208,7 +208,9 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) { if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) { for (;;) { - r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK); + r = getrandom(p, n, + (FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) | + (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0)); if (r > 0) { have_syscall = true; @@ -264,6 +266,18 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) { /* Use /dev/urandom instead */ break; + + } else if (errno == EINVAL) { + + /* Most likely: unknown flag. We know that GRND_INSECURE might cause this, + * hence try without. */ + + if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) { + flags = flags &~ RANDOM_ALLOW_INSECURE; + continue; + } + + return -errno; } else return -errno; } @@ -395,7 +409,7 @@ void random_bytes(void *p, size_t n) { * This function is hence not useful for generating UUIDs or cryptographic key material. */ - if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0) + if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0) return; /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */ diff --git a/src/basic/random-util.h b/src/basic/random-util.h index facc11b976..d8e067d96e 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -10,6 +10,7 @@ typedef enum RandomFlags { RANDOM_BLOCK = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */ RANDOM_MAY_FAIL = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */ RANDOM_ALLOW_RDRAND = 1 << 3, /* Allow usage of the CPU RNG */ + RANDOM_ALLOW_INSECURE = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */ } RandomFlags; int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */ diff --git a/src/test/test-random-util.c b/src/test/test-random-util.c index 94c431f7e6..ad5bc72a4e 100644 --- a/src/test/test-random-util.c +++ b/src/test/test-random-util.c @@ -58,6 +58,7 @@ int main(int argc, char **argv) { test_genuine_random_bytes(0); test_genuine_random_bytes(RANDOM_BLOCK); test_genuine_random_bytes(RANDOM_ALLOW_RDRAND); + test_genuine_random_bytes(RANDOM_ALLOW_INSECURE); test_pseudo_random_bytes();