Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86, kaslr: Provide randomness functions

Adds potential sources of randomness: RDRAND, RDTSC, or the i8254.

This moves the pre-alternatives inline rdrand function into the header so
both pieces of code can use it. Availability of RDRAND is then controlled
by CONFIG_ARCH_RANDOM, if someone wants to disable it even for kASLR.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1381450698-28710-4-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by

Kees Cook and committed by
H. Peter Anvin
5bfce5ef 8ab3820f

+76 -14
+53
arch/x86/boot/compressed/aslr.c
··· 1 1 #include "misc.h" 2 2 3 3 #ifdef CONFIG_RANDOMIZE_BASE 4 + #include <asm/msr.h> 5 + #include <asm/archrandom.h> 6 + 7 + #define I8254_PORT_CONTROL 0x43 8 + #define I8254_PORT_COUNTER0 0x40 9 + #define I8254_CMD_READBACK 0xC0 10 + #define I8254_SELECT_COUNTER0 0x02 11 + #define I8254_STATUS_NOTREADY 0x40 12 + static inline u16 i8254(void) 13 + { 14 + u16 status, timer; 15 + 16 + do { 17 + outb(I8254_PORT_CONTROL, 18 + I8254_CMD_READBACK | I8254_SELECT_COUNTER0); 19 + status = inb(I8254_PORT_COUNTER0); 20 + timer = inb(I8254_PORT_COUNTER0); 21 + timer |= inb(I8254_PORT_COUNTER0) << 8; 22 + } while (status & I8254_STATUS_NOTREADY); 23 + 24 + return timer; 25 + } 26 + 27 + static unsigned long get_random_long(void) 28 + { 29 + unsigned long random; 30 + 31 + if (has_cpuflag(X86_FEATURE_RDRAND)) { 32 + debug_putstr("KASLR using RDRAND...\n"); 33 + if (rdrand_long(&random)) 34 + return random; 35 + } 36 + 37 + if (has_cpuflag(X86_FEATURE_TSC)) { 38 + uint32_t raw; 39 + 40 + debug_putstr("KASLR using RDTSC...\n"); 41 + rdtscl(raw); 42 + 43 + /* Only use the low bits of rdtsc. */ 44 + random = raw & 0xffff; 45 + } else { 46 + debug_putstr("KASLR using i8254...\n"); 47 + random = i8254(); 48 + } 49 + 50 + /* Extend timer bits poorly... */ 51 + random |= (random << 16); 52 + #ifdef CONFIG_X86_64 53 + random |= (random << 32); 54 + #endif 55 + return random; 56 + } 4 57 5 58 unsigned char *choose_kernel_location(unsigned char *input, 6 59 unsigned long input_size,
+2
arch/x86/boot/compressed/misc.h
··· 52 52 unsigned long input_size, 53 53 unsigned char *output, 54 54 unsigned long output_size); 55 + /* cpuflags.c */ 56 + bool has_cpuflag(int flag); 55 57 #else 56 58 static inline 57 59 unsigned char *choose_kernel_location(unsigned char *input,
+21
arch/x86/include/asm/archrandom.h
··· 39 39 40 40 #ifdef CONFIG_ARCH_RANDOM 41 41 42 + /* Instead of arch_get_random_long() when alternatives haven't run. */ 43 + static inline int rdrand_long(unsigned long *v) 44 + { 45 + int ok; 46 + asm volatile("1: " RDRAND_LONG "\n\t" 47 + "jc 2f\n\t" 48 + "decl %0\n\t" 49 + "jnz 1b\n\t" 50 + "2:" 51 + : "=r" (ok), "=a" (*v) 52 + : "0" (RDRAND_RETRY_LOOPS)); 53 + return ok; 54 + } 55 + 42 56 #define GET_RANDOM(name, type, rdrand, nop) \ 43 57 static inline int name(type *v) \ 44 58 { \ ··· 81 67 GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); 82 68 83 69 #endif /* CONFIG_X86_64 */ 70 + 71 + #else 72 + 73 + static inline int rdrand_long(unsigned long *v) 74 + { 75 + return 0; 76 + } 84 77 85 78 #endif /* CONFIG_ARCH_RANDOM */ 86 79
-14
arch/x86/kernel/cpu/rdrand.c
··· 31 31 } 32 32 __setup("nordrand", x86_rdrand_setup); 33 33 34 - /* We can't use arch_get_random_long() here since alternatives haven't run */ 35 - static inline int rdrand_long(unsigned long *v) 36 - { 37 - int ok; 38 - asm volatile("1: " RDRAND_LONG "\n\t" 39 - "jc 2f\n\t" 40 - "decl %0\n\t" 41 - "jnz 1b\n\t" 42 - "2:" 43 - : "=r" (ok), "=a" (*v) 44 - : "0" (RDRAND_RETRY_LOOPS)); 45 - return ok; 46 - } 47 - 48 34 /* 49 35 * Force a reseed cycle; we are architecturally guaranteed a reseed 50 36 * after no more than 512 128-bit chunks of random data. This also