aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-01-06 13:32:01 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-12 06:41:15 -0400
commit7c03613344663982a27c49d5951c80c575714ab8 (patch)
tree714adcd4b689c7a2708bee1d3934e9951e5b220a
parentcddab768d13469d1e254fb8c0e1629f93c8dfaca (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.c84
-rw-r--r--include/linux/random.h1
-rw-r--r--init/main.c1
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
2045static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; 2045struct batched_entropy {
2046 2046 union {
2047int 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
2053static 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 */
2062unsigned int get_random_int(void) 2058static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_long);
2059unsigned 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}
2079EXPORT_SYMBOL(get_random_int); 2076EXPORT_SYMBOL(get_random_long);
2080 2077
2081/* 2078#if BITS_PER_LONG == 32
2082 * Same as get_random_int(), but returns unsigned long. 2079unsigned int get_random_int(void)
2083 */
2084unsigned long get_random_long(void)
2085{ 2080{
2086 __u32 *hash; 2081 return get_random_long();
2087 unsigned long ret; 2082}
2083#else
2084static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_int);
2085unsigned 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}
2101EXPORT_SYMBOL(get_random_long); 2102#endif
2103EXPORT_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);
37extern int add_random_ready_callback(struct random_ready_callback *rdy); 37extern int add_random_ready_callback(struct random_ready_callback *rdy);
38extern void del_random_ready_callback(struct random_ready_callback *rdy); 38extern void del_random_ready_callback(struct random_ready_callback *rdy);
39extern void get_random_bytes_arch(void *buf, int nbytes); 39extern void get_random_bytes_arch(void *buf, int nbytes);
40extern int random_int_secret_init(void);
41 40
42#ifndef MODULE 41#ifndef MODULE
43extern const struct file_operations random_fops, urandom_fops; 42extern 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
874static void __init do_pre_smp_initcalls(void) 873static void __init do_pre_smp_initcalls(void)