diff options
author | Kees Cook <keescook@chromium.org> | 2013-10-10 20:18:15 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-10-13 06:12:12 -0400 |
commit | 5bfce5ef55cbe78ee2ee6e97f2e26a8a582008f3 (patch) | |
tree | ead4a5281554b6f2e0a334cc7e1d83dccf35e15c /arch/x86 | |
parent | 8ab3820fd5b2896d66da7bb2a906bc382e63e7bc (diff) |
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>
Diffstat (limited to 'arch/x86')
-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 |