drivers/char/random.c | 50 +++++++++++++++++++++++++++++++++++++-------- include/uapi/linux/random.h | 12 +++++++++-- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 5d5ea4ce1442..c14fa4780066 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -2123,23 +2123,57 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, { int ret; - if (flags & ~(GRND_NONBLOCK|GRND_RANDOM)) + if (flags & ~(GRND_NONBLOCK|GRND_WAIT_ENTROPY|GRND_EXPLICIT)) return -EINVAL; - if (count > INT_MAX) - count = INT_MAX; + count = min_t(size_t, count, INT_MAX >> (ENTROPY_SHIFT + 3)); - if (flags & GRND_RANDOM) + switch (flags) { + case GRND_SECURE: + ret = wait_for_random_bytes(); + if (ret) + return ret; + break; + + case GRND_SECURE | GRND_NONBLOCK: + if (!crng_ready()) + return -EAGAIN; + break; + + case GRND_INSECURE: + break; + + default: + return -EINVAL; + + /* BAD. Legacy flags. */ + case GRND_RANDOM | GRND_NONBLOCK: + case GRND_RANDOM: return _random_read(flags & GRND_NONBLOCK, buf, count); - if (!crng_ready()) { - if (flags & GRND_NONBLOCK) + case GRND_NONBLOCK: + if (!crng_ready()) return -EAGAIN; + break; + + /* + * People are really confused about whether + * this is secure or insecure. Traditional + * behavior is secure, but there are users + * who clearly didn't want that, and just + * never thought about it. + */ + case 0: ret = wait_for_random_bytes(); - if (unlikely(ret)) + if (ret) return ret; + break; } - return urandom_read(NULL, buf, count, NULL); + + /* equivalent to urandom_read() without the crazy */ + ret = extract_crng_user(buf, count); + trace_urandom_read(8 * count, 0, ENTROPY_BITS(&input_pool)); + return ret; } /******************************************************************** diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index 26ee91300e3e..f933f2a843c0 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h @@ -48,9 +48,17 @@ struct rand_pool_info { * Flags for getrandom(2) * * GRND_NONBLOCK Don't block and return EAGAIN instead - * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom + * GRND_WAIT_ENTROPY Explicitly wait for entropy + * GRND_EXPLICIT Make it clear you know what you are doing */ -#define GRND_NONBLOCK 0x0001 +#define GRND_NONBLOCK 0x0001 +#define GRND_WAIT_ENTROPY 0x0002 +#define GRND_EXPLICIT 0x0004 + +#define GRND_SECURE (GRND_EXPLICIT | GRND_WAIT_ENTROPY) +#define GRND_INSECURE (GRND_EXPLICIT | GRND_NONBLOCK) + +/* Nobody wants /dev/random behavior, nobody should use it */ #define GRND_RANDOM 0x0002 #endif /* _UAPI_LINUX_RANDOM_H */