diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2017-01-06 13:32:01 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-12 06:41:15 -0400 |
commit | 7c03613344663982a27c49d5951c80c575714ab8 (patch) | |
tree | 714adcd4b689c7a2708bee1d3934e9951e5b220a | |
parent | cddab768d13469d1e254fb8c0e1629f93c8dfaca (diff) |
random: use chacha20 for get_random_int/long
commit f5b98461cb8167ba362ad9f74c41d126b7becea7 upstream.
Now that our crng uses chacha20, we can rely on its speedy
characteristics for replacing MD5, while simultaneously achieving a
higher security guarantee. Before the idea was to use these functions if
you wanted random integers that aren't stupidly insecure but aren't
necessarily secure either, a vague gray zone, that hopefully was "good
enough" for its users. With chacha20, we can strengthen this claim,
since either we're using an rdrand-like instruction, or we're using the
same crng as /dev/urandom. And it's faster than what was before.
We could have chosen to replace this with a SipHash-derived function,
which might be slightly faster, but at the cost of having yet another
RNG construction in the kernel. By moving to chacha20, we have a single
RNG to analyze and verify, and we also already get good performance
improvements on all platforms.
Implementation-wise, rather than use a generic buffer for both
get_random_int/long and memcpy based on the size needs, we use a
specific buffer for 32-bit reads and for 64-bit reads. This way, we're
guaranteed to always have aligned accesses on all platforms. While
slightly more verbose in C, the assembly this generates is a lot
simpler than otherwise.
Finally, on 32-bit platforms where longs and ints are the same size,
we simply alias get_random_int to get_random_long.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Suggested-by: Theodore Ts'o <tytso@mit.edu>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/char/random.c | 84 | ||||
-rw-r--r-- | include/linux/random.h | 1 | ||||
-rw-r--r-- | init/main.c | 1 |
3 files changed, 43 insertions, 43 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index d6876d506220..08d1dd58c0d2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -2042,63 +2042,65 @@ struct ctl_table random_table[] = { | |||
2042 | }; | 2042 | }; |
2043 | #endif /* CONFIG_SYSCTL */ | 2043 | #endif /* CONFIG_SYSCTL */ |
2044 | 2044 | ||
2045 | static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; | 2045 | struct batched_entropy { |
2046 | 2046 | union { | |
2047 | int random_int_secret_init(void) | 2047 | unsigned long entropy_long[CHACHA20_BLOCK_SIZE / sizeof(unsigned long)]; |
2048 | { | 2048 | unsigned int entropy_int[CHACHA20_BLOCK_SIZE / sizeof(unsigned int)]; |
2049 | get_random_bytes(random_int_secret, sizeof(random_int_secret)); | 2049 | }; |
2050 | return 0; | 2050 | unsigned int position; |
2051 | } | 2051 | }; |
2052 | |||
2053 | static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash) | ||
2054 | __aligned(sizeof(unsigned long)); | ||
2055 | 2052 | ||
2056 | /* | 2053 | /* |
2057 | * Get a random word for internal kernel use only. Similar to urandom but | 2054 | * Get a random word for internal kernel use only. The quality of the random |
2058 | * with the goal of minimal entropy pool depletion. As a result, the random | 2055 | * number is either as good as RDRAND or as good as /dev/urandom, with the |
2059 | * value is not cryptographically secure but for several uses the cost of | 2056 | * goal of being quite fast and not depleting entropy. |
2060 | * depleting entropy is too high | ||
2061 | */ | 2057 | */ |
2062 | unsigned int get_random_int(void) | 2058 | static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long); |
2059 | unsigned long get_random_long(void) | ||
2063 | { | 2060 | { |
2064 | __u32 *hash; | 2061 | unsigned long ret; |
2065 | unsigned int ret; | 2062 | struct batched_entropy *batch; |
2066 | 2063 | ||
2067 | if (arch_get_random_int(&ret)) | 2064 | if (arch_get_random_long(&ret)) |
2068 | return ret; | 2065 | return ret; |
2069 | 2066 | ||
2070 | hash = get_cpu_var(get_random_int_hash); | 2067 | batch = &get_cpu_var(batched_entropy_long); |
2071 | 2068 | if (batch->position % ARRAY_SIZE(batch->entropy_long) == 0) { | |
2072 | hash[0] += current->pid + jiffies + random_get_entropy(); | 2069 | extract_crng((u8 *)batch->entropy_long); |
2073 | md5_transform(hash, random_int_secret); | 2070 | batch->position = 0; |
2074 | ret = hash[0]; | 2071 | } |
2075 | put_cpu_var(get_random_int_hash); | 2072 | ret = batch->entropy_long[batch->position++]; |
2076 | 2073 | put_cpu_var(batched_entropy_long); | |
2077 | return ret; | 2074 | return ret; |
2078 | } | 2075 | } |
2079 | EXPORT_SYMBOL(get_random_int); | 2076 | EXPORT_SYMBOL(get_random_long); |
2080 | 2077 | ||
2081 | /* | 2078 | #if BITS_PER_LONG == 32 |
2082 | * Same as get_random_int(), but returns unsigned long. | 2079 | unsigned int get_random_int(void) |
2083 | */ | ||
2084 | unsigned long get_random_long(void) | ||
2085 | { | 2080 | { |
2086 | __u32 *hash; | 2081 | return get_random_long(); |
2087 | unsigned long ret; | 2082 | } |
2083 | #else | ||
2084 | static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int); | ||
2085 | unsigned int get_random_int(void) | ||
2086 | { | ||
2087 | unsigned int ret; | ||
2088 | struct batched_entropy *batch; | ||
2088 | 2089 | ||
2089 | if (arch_get_random_long(&ret)) | 2090 | if (arch_get_random_int(&ret)) |
2090 | return ret; | 2091 | return ret; |
2091 | 2092 | ||
2092 | hash = get_cpu_var(get_random_int_hash); | 2093 | batch = &get_cpu_var(batched_entropy_int); |
2093 | 2094 | if (batch->position % ARRAY_SIZE(batch->entropy_int) == 0) { | |
2094 | hash[0] += current->pid + jiffies + random_get_entropy(); | 2095 | extract_crng((u8 *)batch->entropy_int); |
2095 | md5_transform(hash, random_int_secret); | 2096 | batch->position = 0; |
2096 | ret = *(unsigned long *)hash; | 2097 | } |
2097 | put_cpu_var(get_random_int_hash); | 2098 | ret = batch->entropy_int[batch->position++]; |
2098 | 2099 | put_cpu_var(batched_entropy_int); | |
2099 | return ret; | 2100 | return ret; |
2100 | } | 2101 | } |
2101 | EXPORT_SYMBOL(get_random_long); | 2102 | #endif |
2103 | EXPORT_SYMBOL(get_random_int); | ||
2102 | 2104 | ||
2103 | /** | 2105 | /** |
2104 | * randomize_page - Generate a random, page aligned address | 2106 | * randomize_page - Generate a random, page aligned address |
diff --git a/include/linux/random.h b/include/linux/random.h index 7bd2403e4fef..16ab429735a7 100644 --- a/include/linux/random.h +++ b/include/linux/random.h | |||
@@ -37,7 +37,6 @@ extern void get_random_bytes(void *buf, int nbytes); | |||
37 | extern int add_random_ready_callback(struct random_ready_callback *rdy); | 37 | extern int add_random_ready_callback(struct random_ready_callback *rdy); |
38 | extern void del_random_ready_callback(struct random_ready_callback *rdy); | 38 | extern void del_random_ready_callback(struct random_ready_callback *rdy); |
39 | extern void get_random_bytes_arch(void *buf, int nbytes); | 39 | extern void get_random_bytes_arch(void *buf, int nbytes); |
40 | extern int random_int_secret_init(void); | ||
41 | 40 | ||
42 | #ifndef MODULE | 41 | #ifndef MODULE |
43 | extern const struct file_operations random_fops, urandom_fops; | 42 | extern const struct file_operations random_fops, urandom_fops; |
diff --git a/init/main.c b/init/main.c index 2858be732f6d..ae3996ae9bac 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -868,7 +868,6 @@ static void __init do_basic_setup(void) | |||
868 | do_ctors(); | 868 | do_ctors(); |
869 | usermodehelper_enable(); | 869 | usermodehelper_enable(); |
870 | do_initcalls(); | 870 | do_initcalls(); |
871 | random_int_secret_init(); | ||
872 | } | 871 | } |
873 | 872 | ||
874 | static void __init do_pre_smp_initcalls(void) | 873 | static void __init do_pre_smp_initcalls(void) |