random: add backtracking protection to the CRNG

Signed-off-by: Theodore Ts'o <tytso@mit.edu>

+49 -5
+49 -5
drivers/char/random.c
··· 438 #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) 439 static void _extract_crng(struct crng_state *crng, 440 __u8 out[CHACHA20_BLOCK_SIZE]); 441 - static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]); 442 static void process_random_ready_list(void); 443 444 /********************************************************************** ··· 827 num = extract_entropy(r, &buf, 32, 16, 0); 828 if (num == 0) 829 return; 830 - } else 831 _extract_crng(&primary_crng, buf.block); 832 spin_lock_irqsave(&primary_crng.lock, flags); 833 for (i = 0; i < 8; i++) { 834 unsigned long rv; ··· 893 _extract_crng(crng, out); 894 } 895 896 static ssize_t extract_crng_user(void __user *buf, size_t nbytes) 897 { 898 - ssize_t ret = 0, i; 899 __u8 tmp[CHACHA20_BLOCK_SIZE]; 900 int large_request = (nbytes > 256); 901 ··· 957 buf += i; 958 ret += i; 959 } 960 961 /* Wipe data just written to memory */ 962 memzero_explicit(tmp, sizeof(tmp)); ··· 1515 if (nbytes > 0) { 1516 extract_crng(tmp); 1517 memcpy(buf, tmp, nbytes); 1518 - memzero_explicit(tmp, nbytes); 1519 - } 1520 } 1521 EXPORT_SYMBOL(get_random_bytes); 1522
··· 438 #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) 439 static void _extract_crng(struct crng_state *crng, 440 __u8 out[CHACHA20_BLOCK_SIZE]); 441 + static void _crng_backtrack_protect(struct crng_state *crng, 442 + __u8 tmp[CHACHA20_BLOCK_SIZE], int used); 443 static void process_random_ready_list(void); 444 445 /********************************************************************** ··· 826 num = extract_entropy(r, &buf, 32, 16, 0); 827 if (num == 0) 828 return; 829 + } else { 830 _extract_crng(&primary_crng, buf.block); 831 + _crng_backtrack_protect(&primary_crng, buf.block, 832 + CHACHA20_KEY_SIZE); 833 + } 834 spin_lock_irqsave(&primary_crng.lock, flags); 835 for (i = 0; i < 8; i++) { 836 unsigned long rv; ··· 889 _extract_crng(crng, out); 890 } 891 892 + /* 893 + * Use the leftover bytes from the CRNG block output (if there is 894 + * enough) to mutate the CRNG key to provide backtracking protection. 895 + */ 896 + static void _crng_backtrack_protect(struct crng_state *crng, 897 + __u8 tmp[CHACHA20_BLOCK_SIZE], int used) 898 + { 899 + unsigned long flags; 900 + __u32 *s, *d; 901 + int i; 902 + 903 + used = round_up(used, sizeof(__u32)); 904 + if (used + CHACHA20_KEY_SIZE > CHACHA20_BLOCK_SIZE) { 905 + extract_crng(tmp); 906 + used = 0; 907 + } 908 + spin_lock_irqsave(&crng->lock, flags); 909 + s = (__u32 *) &tmp[used]; 910 + d = &crng->state[4]; 911 + for (i=0; i < 8; i++) 912 + *d++ ^= *s++; 913 + spin_unlock_irqrestore(&crng->lock, flags); 914 + } 915 + 916 + static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used) 917 + { 918 + struct crng_state *crng = NULL; 919 + 920 + #ifdef CONFIG_NUMA 921 + if (crng_node_pool) 922 + crng = crng_node_pool[numa_node_id()]; 923 + if (crng == NULL) 924 + #endif 925 + crng = &primary_crng; 926 + _crng_backtrack_protect(crng, tmp, used); 927 + } 928 + 929 static ssize_t extract_crng_user(void __user *buf, size_t nbytes) 930 { 931 + ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE; 932 __u8 tmp[CHACHA20_BLOCK_SIZE]; 933 int large_request = (nbytes > 256); 934 ··· 916 buf += i; 917 ret += i; 918 } 919 + crng_backtrack_protect(tmp, i); 920 921 /* Wipe data just written to memory */ 922 memzero_explicit(tmp, sizeof(tmp)); ··· 1473 if (nbytes > 0) { 1474 extract_crng(tmp); 1475 memcpy(buf, tmp, nbytes); 1476 + crng_backtrack_protect(tmp, nbytes); 1477 + } else 1478 + crng_backtrack_protect(tmp, CHACHA20_BLOCK_SIZE); 1479 + memzero_explicit(tmp, sizeof(tmp)); 1480 } 1481 EXPORT_SYMBOL(get_random_bytes); 1482