aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2013-10-10 20:18:15 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-10-13 06:12:12 -0400
commit5bfce5ef55cbe78ee2ee6e97f2e26a8a582008f3 (patch)
treeead4a5281554b6f2e0a334cc7e1d83dccf35e15c /arch/x86
parent8ab3820fd5b2896d66da7bb2a906bc382e63e7bc (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.c53
-rw-r--r--arch/x86/boot/compressed/misc.h2
-rw-r--r--arch/x86/include/asm/archrandom.h21
-rw-r--r--arch/x86/kernel/cpu/rdrand.c14
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
12static 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
27static 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
5unsigned char *choose_kernel_location(unsigned char *input, 58unsigned 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 */
56bool has_cpuflag(int flag);
55#else 57#else
56static inline 58static inline
57unsigned char *choose_kernel_location(unsigned char *input, 59unsigned 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. */
43static 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) \
43static inline int name(type *v) \ 57static 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
87static 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
73extern void x86_init_rdrand(struct cpuinfo_x86 *c); 94extern 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 */
35static 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