diff options
author | Theodore Ts'o <tytso@mit.edu> | 2018-04-11 14:58:27 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2018-04-14 11:59:09 -0400 |
commit | dc12baacb95f205948f64dc936a47d89ee110117 (patch) | |
tree | 1e2e7e65b48e21064e337dae6f4e4a93fa7ce54a /drivers/char/random.c | |
parent | 43838a23a05fbd13e47d750d3dfd77001536dd33 (diff) |
random: use a different mixing algorithm for add_device_randomness()
add_device_randomness() use of crng_fast_load() was highly
problematic. Some callers of add_device_randomness() can pass in a
large amount of static information. This would immediately promote
the crng_init state from 0 to 1, without really doing much to
initialize the primary_crng's internal state with something even
vaguely unpredictable.
Since we don't have the speed constraints of add_interrupt_randomness(),
we can do a better job mixing in the what unpredictability a device
driver or architecture maintainer might see fit to give us, and do it
in a way which does not bump the crng_init_cnt variable.
Also, since add_device_randomness() doesn't bump any entropy
accounting in crng_init state 0, mix the device randomness into the
input_pool entropy pool as well. This is related to CVE-2018-1108.
Reported-by: Jann Horn <jannh@google.com>
Fixes: ee7998c50c26 ("random: do not ignore early device randomness")
Cc: stable@kernel.org # 4.13+
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r-- | drivers/char/random.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index c8ec1e70abde..6baa828c0493 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -787,6 +787,10 @@ static void crng_initialize(struct crng_state *crng) | |||
787 | crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; | 787 | crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; |
788 | } | 788 | } |
789 | 789 | ||
790 | /* | ||
791 | * crng_fast_load() can be called by code in the interrupt service | ||
792 | * path. So we can't afford to dilly-dally. | ||
793 | */ | ||
790 | static int crng_fast_load(const char *cp, size_t len) | 794 | static int crng_fast_load(const char *cp, size_t len) |
791 | { | 795 | { |
792 | unsigned long flags; | 796 | unsigned long flags; |
@@ -813,6 +817,51 @@ static int crng_fast_load(const char *cp, size_t len) | |||
813 | return 1; | 817 | return 1; |
814 | } | 818 | } |
815 | 819 | ||
820 | /* | ||
821 | * crng_slow_load() is called by add_device_randomness, which has two | ||
822 | * attributes. (1) We can't trust the buffer passed to it is | ||
823 | * guaranteed to be unpredictable (so it might not have any entropy at | ||
824 | * all), and (2) it doesn't have the performance constraints of | ||
825 | * crng_fast_load(). | ||
826 | * | ||
827 | * So we do something more comprehensive which is guaranteed to touch | ||
828 | * all of the primary_crng's state, and which uses a LFSR with a | ||
829 | * period of 255 as part of the mixing algorithm. Finally, we do | ||
830 | * *not* advance crng_init_cnt since buffer we may get may be something | ||
831 | * like a fixed DMI table (for example), which might very well be | ||
832 | * unique to the machine, but is otherwise unvarying. | ||
833 | */ | ||
834 | static int crng_slow_load(const char *cp, size_t len) | ||
835 | { | ||
836 | unsigned long flags; | ||
837 | static unsigned char lfsr = 1; | ||
838 | unsigned char tmp; | ||
839 | unsigned i, max = CHACHA20_KEY_SIZE; | ||
840 | const char * src_buf = cp; | ||
841 | char * dest_buf = (char *) &primary_crng.state[4]; | ||
842 | |||
843 | if (!spin_trylock_irqsave(&primary_crng.lock, flags)) | ||
844 | return 0; | ||
845 | if (crng_init != 0) { | ||
846 | spin_unlock_irqrestore(&primary_crng.lock, flags); | ||
847 | return 0; | ||
848 | } | ||
849 | if (len > max) | ||
850 | max = len; | ||
851 | |||
852 | for (i = 0; i < max ; i++) { | ||
853 | tmp = lfsr; | ||
854 | lfsr >>= 1; | ||
855 | if (tmp & 1) | ||
856 | lfsr ^= 0xE1; | ||
857 | tmp = dest_buf[i % CHACHA20_KEY_SIZE]; | ||
858 | dest_buf[i % CHACHA20_KEY_SIZE] ^= src_buf[i % len] ^ lfsr; | ||
859 | lfsr += (tmp << 3) | (tmp >> 5); | ||
860 | } | ||
861 | spin_unlock_irqrestore(&primary_crng.lock, flags); | ||
862 | return 1; | ||
863 | } | ||
864 | |||
816 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r) | 865 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r) |
817 | { | 866 | { |
818 | unsigned long flags; | 867 | unsigned long flags; |
@@ -981,10 +1030,8 @@ void add_device_randomness(const void *buf, unsigned int size) | |||
981 | unsigned long time = random_get_entropy() ^ jiffies; | 1030 | unsigned long time = random_get_entropy() ^ jiffies; |
982 | unsigned long flags; | 1031 | unsigned long flags; |
983 | 1032 | ||
984 | if (!crng_ready()) { | 1033 | if (!crng_ready() && size) |
985 | crng_fast_load(buf, size); | 1034 | crng_slow_load(buf, size); |
986 | return; | ||
987 | } | ||
988 | 1035 | ||
989 | trace_add_device_randomness(size, _RET_IP_); | 1036 | trace_add_device_randomness(size, _RET_IP_); |
990 | spin_lock_irqsave(&input_pool.lock, flags); | 1037 | spin_lock_irqsave(&input_pool.lock, flags); |