diff options
author | Kees Cook <keescook@chromium.org> | 2013-11-11 17:28:39 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2013-11-12 01:29:44 -0500 |
commit | a653f3563c51c7bb7de63d607bef09d3baddaeb8 (patch) | |
tree | bb431f947a59f2301aa81e9f347dc8b531b524b4 /arch/x86/boot | |
parent | aec58bafaf89279522c44ec8ca9211eabb2b6976 (diff) |
x86, kaslr: Mix entropy sources together as needed
Depending on availability, mix the RDRAND and RDTSC entropy together with
XOR. Only when neither is available should the i8254 be used. Update
the Kconfig documentation to reflect this. Additionally, since bits
used for entropy is masked elsewhere, drop the needless masking in
the get_random_long(). Similarly, use the entire TSC, not just the low
32 bits.
Finally, to improve the starting entropy, do a simple hashing of a
build-time versions string and the boot-time boot_params structure for
some additional level of unpredictability.
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/20131111222839.GA28616@www.outflux.net
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/boot')
-rw-r--r-- | arch/x86/boot/compressed/aslr.c | 73 |
1 files changed, 56 insertions, 17 deletions
diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index 05957986d123..8746487fa916 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c | |||
@@ -5,6 +5,17 @@ | |||
5 | #include <asm/archrandom.h> | 5 | #include <asm/archrandom.h> |
6 | #include <asm/e820.h> | 6 | #include <asm/e820.h> |
7 | 7 | ||
8 | #include <generated/compile.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/uts.h> | ||
11 | #include <linux/utsname.h> | ||
12 | #include <generated/utsrelease.h> | ||
13 | #include <linux/version.h> | ||
14 | |||
15 | /* Simplified build-specific string for starting entropy. */ | ||
16 | static const char *build_str = UTS_RELEASE " (" LINUX_COMPILE_BY "@" | ||
17 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; | ||
18 | |||
8 | #define I8254_PORT_CONTROL 0x43 | 19 | #define I8254_PORT_CONTROL 0x43 |
9 | #define I8254_PORT_COUNTER0 0x40 | 20 | #define I8254_PORT_COUNTER0 0x40 |
10 | #define I8254_CMD_READBACK 0xC0 | 21 | #define I8254_CMD_READBACK 0xC0 |
@@ -25,34 +36,62 @@ static inline u16 i8254(void) | |||
25 | return timer; | 36 | return timer; |
26 | } | 37 | } |
27 | 38 | ||
39 | static unsigned long rotate_xor(unsigned long hash, const void *area, | ||
40 | size_t size) | ||
41 | { | ||
42 | size_t i; | ||
43 | unsigned long *ptr = (unsigned long *)area; | ||
44 | |||
45 | for (i = 0; i < size / sizeof(hash); i++) { | ||
46 | /* Rotate by odd number of bits and XOR. */ | ||
47 | hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7); | ||
48 | hash ^= ptr[i]; | ||
49 | } | ||
50 | |||
51 | return hash; | ||
52 | } | ||
53 | |||
54 | /* Attempt to create a simple but unpredictable starting entropy. */ | ||
55 | static unsigned long get_random_boot(void) | ||
56 | { | ||
57 | unsigned long hash = 0; | ||
58 | |||
59 | hash = rotate_xor(hash, build_str, sizeof(build_str)); | ||
60 | hash = rotate_xor(hash, real_mode, sizeof(*real_mode)); | ||
61 | |||
62 | return hash; | ||
63 | } | ||
64 | |||
28 | static unsigned long get_random_long(void) | 65 | static unsigned long get_random_long(void) |
29 | { | 66 | { |
30 | unsigned long random; | 67 | unsigned long raw, random = get_random_boot(); |
68 | bool use_i8254 = true; | ||
69 | |||
70 | debug_putstr("KASLR using"); | ||
31 | 71 | ||
32 | if (has_cpuflag(X86_FEATURE_RDRAND)) { | 72 | if (has_cpuflag(X86_FEATURE_RDRAND)) { |
33 | debug_putstr("KASLR using RDRAND...\n"); | 73 | debug_putstr(" RDRAND"); |
34 | if (rdrand_long(&random)) | 74 | if (rdrand_long(&raw)) { |
35 | return random; | 75 | random ^= raw; |
76 | use_i8254 = false; | ||
77 | } | ||
36 | } | 78 | } |
37 | 79 | ||
38 | if (has_cpuflag(X86_FEATURE_TSC)) { | 80 | if (has_cpuflag(X86_FEATURE_TSC)) { |
39 | uint32_t raw; | 81 | debug_putstr(" RDTSC"); |
82 | rdtscll(raw); | ||
40 | 83 | ||
41 | debug_putstr("KASLR using RDTSC...\n"); | 84 | random ^= raw; |
42 | rdtscl(raw); | 85 | use_i8254 = false; |
86 | } | ||
43 | 87 | ||
44 | /* Only use the low bits of rdtsc. */ | 88 | if (use_i8254) { |
45 | random = raw & 0xffff; | 89 | debug_putstr(" i8254"); |
46 | } else { | 90 | random ^= i8254(); |
47 | debug_putstr("KASLR using i8254...\n"); | ||
48 | random = i8254(); | ||
49 | } | 91 | } |
50 | 92 | ||
51 | /* Extend timer bits poorly... */ | 93 | debug_putstr("...\n"); |
52 | random |= (random << 16); | 94 | |
53 | #ifdef CONFIG_X86_64 | ||
54 | random |= (random << 32); | ||
55 | #endif | ||
56 | return random; | 95 | return random; |
57 | } | 96 | } |
58 | 97 | ||