diff options
-rw-r--r-- | arch/x86/Kconfig | 14 | ||||
-rw-r--r-- | arch/x86/boot/compressed/aslr.c | 73 |
2 files changed, 65 insertions, 22 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 51f439953d23..596cd9edeb9c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1735,13 +1735,17 @@ config RANDOMIZE_BASE | |||
1735 | deters exploit attempts relying on knowledge of the location | 1735 | deters exploit attempts relying on knowledge of the location |
1736 | of kernel internals. | 1736 | of kernel internals. |
1737 | 1737 | ||
1738 | Entropy is generated using the RDRAND instruction if it | 1738 | Entropy is generated using the RDRAND instruction if it is |
1739 | is supported. If not, then RDTSC is used, if supported. If | 1739 | supported. If RDTSC is supported, it is used as well. If |
1740 | neither RDRAND nor RDTSC are supported, then no randomness | 1740 | neither RDRAND nor RDTSC are supported, then randomness is |
1741 | is introduced. | 1741 | read from the i8254 timer. |
1742 | 1742 | ||
1743 | The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET, | 1743 | The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET, |
1744 | and aligned according to PHYSICAL_ALIGN. | 1744 | and aligned according to PHYSICAL_ALIGN. Since the kernel is |
1745 | built using 2GiB addressing, and PHYSICAL_ALGIN must be at a | ||
1746 | minimum of 2MiB, only 10 bits of entropy is theoretically | ||
1747 | possible. At best, due to page table layouts, 64-bit can use | ||
1748 | 9 bits of entropy and 32-bit uses 8 bits. | ||
1745 | 1749 | ||
1746 | config RANDOMIZE_BASE_MAX_OFFSET | 1750 | config RANDOMIZE_BASE_MAX_OFFSET |
1747 | hex "Maximum ASLR offset allowed" | 1751 | hex "Maximum ASLR offset allowed" |
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 | ||