diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-22 00:20:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-22 00:20:48 -0400 |
commit | 285848b0f4074f04ab606f1e5dca296482033d54 (patch) | |
tree | d807840875deed64561550304e8e1907b7d0b215 | |
parent | 4c50ceae8f3b56e7c13b327f01e973b4127142a2 (diff) | |
parent | d848e5f8e1ebdb227d045db55fe4f825e82965fa (diff) |
Merge tag 'random_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random
Pull /dev/random fixes from Ted Ts'o:
"Fix some bugs in the /dev/random driver which causes getrandom(2) to
unblock earlier than designed.
Thanks to Jann Horn from Google's Project Zero for pointing this out
to me"
* tag 'random_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random:
random: add new ioctl RNDRESEEDCRNG
random: crng_reseed() should lock the crng instance that it is modifying
random: set up the NUMA crng instances after the CRNG is fully initialized
random: use a different mixing algorithm for add_device_randomness()
random: fix crng_ready() test
-rw-r--r-- | drivers/char/random.c | 128 | ||||
-rw-r--r-- | include/uapi/linux/random.h | 3 |
2 files changed, 100 insertions, 31 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index e027e7fa1472..3cd3aae24d6d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -427,8 +427,9 @@ struct crng_state primary_crng = { | |||
427 | * its value (from 0->1->2). | 427 | * its value (from 0->1->2). |
428 | */ | 428 | */ |
429 | static int crng_init = 0; | 429 | static int crng_init = 0; |
430 | #define crng_ready() (likely(crng_init > 0)) | 430 | #define crng_ready() (likely(crng_init > 1)) |
431 | static int crng_init_cnt = 0; | 431 | static int crng_init_cnt = 0; |
432 | static unsigned long crng_global_init_time = 0; | ||
432 | #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) | 433 | #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) |
433 | static void _extract_crng(struct crng_state *crng, | 434 | static void _extract_crng(struct crng_state *crng, |
434 | __u32 out[CHACHA20_BLOCK_WORDS]); | 435 | __u32 out[CHACHA20_BLOCK_WORDS]); |
@@ -787,6 +788,36 @@ static void crng_initialize(struct crng_state *crng) | |||
787 | crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; | 788 | crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; |
788 | } | 789 | } |
789 | 790 | ||
791 | #ifdef CONFIG_NUMA | ||
792 | static void numa_crng_init(void) | ||
793 | { | ||
794 | int i; | ||
795 | struct crng_state *crng; | ||
796 | struct crng_state **pool; | ||
797 | |||
798 | pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); | ||
799 | for_each_online_node(i) { | ||
800 | crng = kmalloc_node(sizeof(struct crng_state), | ||
801 | GFP_KERNEL | __GFP_NOFAIL, i); | ||
802 | spin_lock_init(&crng->lock); | ||
803 | crng_initialize(crng); | ||
804 | pool[i] = crng; | ||
805 | } | ||
806 | mb(); | ||
807 | if (cmpxchg(&crng_node_pool, NULL, pool)) { | ||
808 | for_each_node(i) | ||
809 | kfree(pool[i]); | ||
810 | kfree(pool); | ||
811 | } | ||
812 | } | ||
813 | #else | ||
814 | static void numa_crng_init(void) {} | ||
815 | #endif | ||
816 | |||
817 | /* | ||
818 | * crng_fast_load() can be called by code in the interrupt service | ||
819 | * path. So we can't afford to dilly-dally. | ||
820 | */ | ||
790 | static int crng_fast_load(const char *cp, size_t len) | 821 | static int crng_fast_load(const char *cp, size_t len) |
791 | { | 822 | { |
792 | unsigned long flags; | 823 | unsigned long flags; |
@@ -794,7 +825,7 @@ static int crng_fast_load(const char *cp, size_t len) | |||
794 | 825 | ||
795 | if (!spin_trylock_irqsave(&primary_crng.lock, flags)) | 826 | if (!spin_trylock_irqsave(&primary_crng.lock, flags)) |
796 | return 0; | 827 | return 0; |
797 | if (crng_ready()) { | 828 | if (crng_init != 0) { |
798 | spin_unlock_irqrestore(&primary_crng.lock, flags); | 829 | spin_unlock_irqrestore(&primary_crng.lock, flags); |
799 | return 0; | 830 | return 0; |
800 | } | 831 | } |
@@ -813,6 +844,51 @@ static int crng_fast_load(const char *cp, size_t len) | |||
813 | return 1; | 844 | return 1; |
814 | } | 845 | } |
815 | 846 | ||
847 | /* | ||
848 | * crng_slow_load() is called by add_device_randomness, which has two | ||
849 | * attributes. (1) We can't trust the buffer passed to it is | ||
850 | * guaranteed to be unpredictable (so it might not have any entropy at | ||
851 | * all), and (2) it doesn't have the performance constraints of | ||
852 | * crng_fast_load(). | ||
853 | * | ||
854 | * So we do something more comprehensive which is guaranteed to touch | ||
855 | * all of the primary_crng's state, and which uses a LFSR with a | ||
856 | * period of 255 as part of the mixing algorithm. Finally, we do | ||
857 | * *not* advance crng_init_cnt since buffer we may get may be something | ||
858 | * like a fixed DMI table (for example), which might very well be | ||
859 | * unique to the machine, but is otherwise unvarying. | ||
860 | */ | ||
861 | static int crng_slow_load(const char *cp, size_t len) | ||
862 | { | ||
863 | unsigned long flags; | ||
864 | static unsigned char lfsr = 1; | ||
865 | unsigned char tmp; | ||
866 | unsigned i, max = CHACHA20_KEY_SIZE; | ||
867 | const char * src_buf = cp; | ||
868 | char * dest_buf = (char *) &primary_crng.state[4]; | ||
869 | |||
870 | if (!spin_trylock_irqsave(&primary_crng.lock, flags)) | ||
871 | return 0; | ||
872 | if (crng_init != 0) { | ||
873 | spin_unlock_irqrestore(&primary_crng.lock, flags); | ||
874 | return 0; | ||
875 | } | ||
876 | if (len > max) | ||
877 | max = len; | ||
878 | |||
879 | for (i = 0; i < max ; i++) { | ||
880 | tmp = lfsr; | ||
881 | lfsr >>= 1; | ||
882 | if (tmp & 1) | ||
883 | lfsr ^= 0xE1; | ||
884 | tmp = dest_buf[i % CHACHA20_KEY_SIZE]; | ||
885 | dest_buf[i % CHACHA20_KEY_SIZE] ^= src_buf[i % len] ^ lfsr; | ||
886 | lfsr += (tmp << 3) | (tmp >> 5); | ||
887 | } | ||
888 | spin_unlock_irqrestore(&primary_crng.lock, flags); | ||
889 | return 1; | ||
890 | } | ||
891 | |||
816 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r) | 892 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r) |
817 | { | 893 | { |
818 | unsigned long flags; | 894 | unsigned long flags; |
@@ -831,7 +907,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) | |||
831 | _crng_backtrack_protect(&primary_crng, buf.block, | 907 | _crng_backtrack_protect(&primary_crng, buf.block, |
832 | CHACHA20_KEY_SIZE); | 908 | CHACHA20_KEY_SIZE); |
833 | } | 909 | } |
834 | spin_lock_irqsave(&primary_crng.lock, flags); | 910 | spin_lock_irqsave(&crng->lock, flags); |
835 | for (i = 0; i < 8; i++) { | 911 | for (i = 0; i < 8; i++) { |
836 | unsigned long rv; | 912 | unsigned long rv; |
837 | if (!arch_get_random_seed_long(&rv) && | 913 | if (!arch_get_random_seed_long(&rv) && |
@@ -841,9 +917,10 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) | |||
841 | } | 917 | } |
842 | memzero_explicit(&buf, sizeof(buf)); | 918 | memzero_explicit(&buf, sizeof(buf)); |
843 | crng->init_time = jiffies; | 919 | crng->init_time = jiffies; |
844 | spin_unlock_irqrestore(&primary_crng.lock, flags); | 920 | spin_unlock_irqrestore(&crng->lock, flags); |
845 | if (crng == &primary_crng && crng_init < 2) { | 921 | if (crng == &primary_crng && crng_init < 2) { |
846 | invalidate_batched_entropy(); | 922 | invalidate_batched_entropy(); |
923 | numa_crng_init(); | ||
847 | crng_init = 2; | 924 | crng_init = 2; |
848 | process_random_ready_list(); | 925 | process_random_ready_list(); |
849 | wake_up_interruptible(&crng_init_wait); | 926 | wake_up_interruptible(&crng_init_wait); |
@@ -856,8 +933,9 @@ static void _extract_crng(struct crng_state *crng, | |||
856 | { | 933 | { |
857 | unsigned long v, flags; | 934 | unsigned long v, flags; |
858 | 935 | ||
859 | if (crng_init > 1 && | 936 | if (crng_ready() && |
860 | time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) | 937 | (time_after(crng_global_init_time, crng->init_time) || |
938 | time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))) | ||
861 | crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); | 939 | crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); |
862 | spin_lock_irqsave(&crng->lock, flags); | 940 | spin_lock_irqsave(&crng->lock, flags); |
863 | if (arch_get_random_long(&v)) | 941 | if (arch_get_random_long(&v)) |
@@ -981,10 +1059,8 @@ void add_device_randomness(const void *buf, unsigned int size) | |||
981 | unsigned long time = random_get_entropy() ^ jiffies; | 1059 | unsigned long time = random_get_entropy() ^ jiffies; |
982 | unsigned long flags; | 1060 | unsigned long flags; |
983 | 1061 | ||
984 | if (!crng_ready()) { | 1062 | if (!crng_ready() && size) |
985 | crng_fast_load(buf, size); | 1063 | crng_slow_load(buf, size); |
986 | return; | ||
987 | } | ||
988 | 1064 | ||
989 | trace_add_device_randomness(size, _RET_IP_); | 1065 | trace_add_device_randomness(size, _RET_IP_); |
990 | spin_lock_irqsave(&input_pool.lock, flags); | 1066 | spin_lock_irqsave(&input_pool.lock, flags); |
@@ -1139,7 +1215,7 @@ void add_interrupt_randomness(int irq, int irq_flags) | |||
1139 | fast_mix(fast_pool); | 1215 | fast_mix(fast_pool); |
1140 | add_interrupt_bench(cycles); | 1216 | add_interrupt_bench(cycles); |
1141 | 1217 | ||
1142 | if (!crng_ready()) { | 1218 | if (unlikely(crng_init == 0)) { |
1143 | if ((fast_pool->count >= 64) && | 1219 | if ((fast_pool->count >= 64) && |
1144 | crng_fast_load((char *) fast_pool->pool, | 1220 | crng_fast_load((char *) fast_pool->pool, |
1145 | sizeof(fast_pool->pool))) { | 1221 | sizeof(fast_pool->pool))) { |
@@ -1680,28 +1756,10 @@ static void init_std_data(struct entropy_store *r) | |||
1680 | */ | 1756 | */ |
1681 | static int rand_initialize(void) | 1757 | static int rand_initialize(void) |
1682 | { | 1758 | { |
1683 | #ifdef CONFIG_NUMA | ||
1684 | int i; | ||
1685 | struct crng_state *crng; | ||
1686 | struct crng_state **pool; | ||
1687 | #endif | ||
1688 | |||
1689 | init_std_data(&input_pool); | 1759 | init_std_data(&input_pool); |
1690 | init_std_data(&blocking_pool); | 1760 | init_std_data(&blocking_pool); |
1691 | crng_initialize(&primary_crng); | 1761 | crng_initialize(&primary_crng); |
1692 | 1762 | crng_global_init_time = jiffies; | |
1693 | #ifdef CONFIG_NUMA | ||
1694 | pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); | ||
1695 | for_each_online_node(i) { | ||
1696 | crng = kmalloc_node(sizeof(struct crng_state), | ||
1697 | GFP_KERNEL | __GFP_NOFAIL, i); | ||
1698 | spin_lock_init(&crng->lock); | ||
1699 | crng_initialize(crng); | ||
1700 | pool[i] = crng; | ||
1701 | } | ||
1702 | mb(); | ||
1703 | crng_node_pool = pool; | ||
1704 | #endif | ||
1705 | return 0; | 1763 | return 0; |
1706 | } | 1764 | } |
1707 | early_initcall(rand_initialize); | 1765 | early_initcall(rand_initialize); |
@@ -1875,6 +1933,14 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
1875 | input_pool.entropy_count = 0; | 1933 | input_pool.entropy_count = 0; |
1876 | blocking_pool.entropy_count = 0; | 1934 | blocking_pool.entropy_count = 0; |
1877 | return 0; | 1935 | return 0; |
1936 | case RNDRESEEDCRNG: | ||
1937 | if (!capable(CAP_SYS_ADMIN)) | ||
1938 | return -EPERM; | ||
1939 | if (crng_init < 2) | ||
1940 | return -ENODATA; | ||
1941 | crng_reseed(&primary_crng, NULL); | ||
1942 | crng_global_init_time = jiffies - 1; | ||
1943 | return 0; | ||
1878 | default: | 1944 | default: |
1879 | return -EINVAL; | 1945 | return -EINVAL; |
1880 | } | 1946 | } |
@@ -2212,7 +2278,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, | |||
2212 | { | 2278 | { |
2213 | struct entropy_store *poolp = &input_pool; | 2279 | struct entropy_store *poolp = &input_pool; |
2214 | 2280 | ||
2215 | if (!crng_ready()) { | 2281 | if (unlikely(crng_init == 0)) { |
2216 | crng_fast_load(buffer, count); | 2282 | crng_fast_load(buffer, count); |
2217 | return; | 2283 | return; |
2218 | } | 2284 | } |
diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index c34f4490d025..26ee91300e3e 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h | |||
@@ -35,6 +35,9 @@ | |||
35 | /* Clear the entropy pool and associated counters. (Superuser only.) */ | 35 | /* Clear the entropy pool and associated counters. (Superuser only.) */ |
36 | #define RNDCLEARPOOL _IO( 'R', 0x06 ) | 36 | #define RNDCLEARPOOL _IO( 'R', 0x06 ) |
37 | 37 | ||
38 | /* Reseed CRNG. (Superuser only.) */ | ||
39 | #define RNDRESEEDCRNG _IO( 'R', 0x07 ) | ||
40 | |||
38 | struct rand_pool_info { | 41 | struct rand_pool_info { |
39 | int entropy_count; | 42 | int entropy_count; |
40 | int buf_size; | 43 | int buf_size; |