diff options
| -rw-r--r-- | arch/x86/boot/compressed/aslr.c | 53 | ||||
| -rw-r--r-- | arch/x86/boot/compressed/misc.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/archrandom.h | 21 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/rdrand.c | 14 |
4 files changed, 76 insertions, 14 deletions
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index b73cc66d201e..14b24e0e5496 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c | |||
| @@ -1,6 +1,59 @@ | |||
| 1 | #include "misc.h" | 1 | #include "misc.h" |
| 2 | 2 | ||
| 3 | #ifdef CONFIG_RANDOMIZE_BASE | 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 | unsigned char *choose_kernel_location(unsigned char *input, | 58 | unsigned char *choose_kernel_location(unsigned char *input, |
| 6 | unsigned long input_size, | 59 | unsigned long input_size, |
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 9077af7fd0b8..0782eb0b6e30 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h | |||
| @@ -52,6 +52,8 @@ unsigned char *choose_kernel_location(unsigned char *input, | |||
| 52 | unsigned long input_size, | 52 | unsigned long input_size, |
| 53 | unsigned char *output, | 53 | unsigned char *output, |
| 54 | unsigned long output_size); | 54 | unsigned long output_size); |
| 55 | /* cpuflags.c */ | ||
| 56 | bool has_cpuflag(int flag); | ||
| 55 | #else | 57 | #else |
| 56 | static inline | 58 | static inline |
| 57 | unsigned char *choose_kernel_location(unsigned char *input, | 59 | unsigned char *choose_kernel_location(unsigned char *input, |
diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index 0d9ec770f2f8..e6a92455740e 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h | |||
| @@ -39,6 +39,20 @@ | |||
| 39 | 39 | ||
| 40 | #ifdef CONFIG_ARCH_RANDOM | 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 | #define GET_RANDOM(name, type, rdrand, nop) \ | 56 | #define GET_RANDOM(name, type, rdrand, nop) \ |
| 43 | static inline int name(type *v) \ | 57 | static inline int name(type *v) \ |
| 44 | { \ | 58 | { \ |
| @@ -68,6 +82,13 @@ GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); | |||
| 68 | 82 | ||
| 69 | #endif /* CONFIG_X86_64 */ | 83 | #endif /* CONFIG_X86_64 */ |
| 70 | 84 | ||
| 85 | #else | ||
| 86 | |||
| 87 | static inline int rdrand_long(unsigned long *v) | ||
| 88 | { | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 71 | #endif /* CONFIG_ARCH_RANDOM */ | 92 | #endif /* CONFIG_ARCH_RANDOM */ |
| 72 | 93 | ||
| 73 | extern void x86_init_rdrand(struct cpuinfo_x86 *c); | 94 | extern void x86_init_rdrand(struct cpuinfo_x86 *c); |
diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c index 88db010845cb..384df5105fbc 100644 --- a/arch/x86/kernel/cpu/rdrand.c +++ b/arch/x86/kernel/cpu/rdrand.c | |||
| @@ -31,20 +31,6 @@ static int __init x86_rdrand_setup(char *s) | |||
| 31 | } | 31 | } |
| 32 | __setup("nordrand", x86_rdrand_setup); | 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 | * Force a reseed cycle; we are architecturally guaranteed a reseed | 35 | * Force a reseed cycle; we are architecturally guaranteed a reseed |
| 50 | * after no more than 512 128-bit chunks of random data. This also | 36 | * after no more than 512 128-bit chunks of random data. This also |
