diff options
author | Thomas Garnier <thgarnie@google.com> | 2016-06-21 20:46:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-07-08 11:33:45 -0400 |
commit | d899a7d146a2ed8a7e6c2f61bcd232908bcbaabc (patch) | |
tree | 3ee4dd7bca76a3b0d51a96b15edcd84bdb14a1a8 | |
parent | 9e7f7f5425e6d1492109a537ee88c99b29580655 (diff) |
x86/mm: Refactor KASLR entropy functions
Move the KASLR entropy functions into arch/x86/lib to be used in early
kernel boot for KASLR memory randomization.
Signed-off-by: Thomas Garnier <thgarnie@google.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Alexander Kuleshov <kuleshovmail@gmail.com>
Cc: Alexander Popov <alpopov@ptsecurity.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bp@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jan Beulich <JBeulich@suse.com>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Lv Zheng <lv.zheng@intel.com>
Cc: Mark Salter <msalter@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Toshi Kani <toshi.kani@hpe.com>
Cc: Xiao Guangrong <guangrong.xiao@linux.intel.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: kernel-hardening@lists.openwall.com
Cc: linux-doc@vger.kernel.org
Link: http://lkml.kernel.org/r/1466556426-32664-2-git-send-email-keescook@chromium.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/boot/compressed/kaslr.c | 76 | ||||
-rw-r--r-- | arch/x86/include/asm/kaslr.h | 6 | ||||
-rw-r--r-- | arch/x86/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/lib/kaslr.c | 90 |
4 files changed, 102 insertions, 71 deletions
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 010ea16e5f77..a66854d99ee1 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c | |||
@@ -12,10 +12,6 @@ | |||
12 | #include "misc.h" | 12 | #include "misc.h" |
13 | #include "error.h" | 13 | #include "error.h" |
14 | 14 | ||
15 | #include <asm/msr.h> | ||
16 | #include <asm/archrandom.h> | ||
17 | #include <asm/e820.h> | ||
18 | |||
19 | #include <generated/compile.h> | 15 | #include <generated/compile.h> |
20 | #include <linux/module.h> | 16 | #include <linux/module.h> |
21 | #include <linux/uts.h> | 17 | #include <linux/uts.h> |
@@ -26,26 +22,6 @@ | |||
26 | static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" | 22 | static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@" |
27 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; | 23 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION; |
28 | 24 | ||
29 | #define I8254_PORT_CONTROL 0x43 | ||
30 | #define I8254_PORT_COUNTER0 0x40 | ||
31 | #define I8254_CMD_READBACK 0xC0 | ||
32 | #define I8254_SELECT_COUNTER0 0x02 | ||
33 | #define I8254_STATUS_NOTREADY 0x40 | ||
34 | static inline u16 i8254(void) | ||
35 | { | ||
36 | u16 status, timer; | ||
37 | |||
38 | do { | ||
39 | outb(I8254_PORT_CONTROL, | ||
40 | I8254_CMD_READBACK | I8254_SELECT_COUNTER0); | ||
41 | status = inb(I8254_PORT_COUNTER0); | ||
42 | timer = inb(I8254_PORT_COUNTER0); | ||
43 | timer |= inb(I8254_PORT_COUNTER0) << 8; | ||
44 | } while (status & I8254_STATUS_NOTREADY); | ||
45 | |||
46 | return timer; | ||
47 | } | ||
48 | |||
49 | static unsigned long rotate_xor(unsigned long hash, const void *area, | 25 | static unsigned long rotate_xor(unsigned long hash, const void *area, |
50 | size_t size) | 26 | size_t size) |
51 | { | 27 | { |
@@ -62,7 +38,7 @@ static unsigned long rotate_xor(unsigned long hash, const void *area, | |||
62 | } | 38 | } |
63 | 39 | ||
64 | /* Attempt to create a simple but unpredictable starting entropy. */ | 40 | /* Attempt to create a simple but unpredictable starting entropy. */ |
65 | static unsigned long get_random_boot(void) | 41 | static unsigned long get_boot_seed(void) |
66 | { | 42 | { |
67 | unsigned long hash = 0; | 43 | unsigned long hash = 0; |
68 | 44 | ||
@@ -72,50 +48,8 @@ static unsigned long get_random_boot(void) | |||
72 | return hash; | 48 | return hash; |
73 | } | 49 | } |
74 | 50 | ||
75 | static unsigned long get_random_long(const char *purpose) | 51 | #define KASLR_COMPRESSED_BOOT |
76 | { | 52 | #include "../../lib/kaslr.c" |
77 | #ifdef CONFIG_X86_64 | ||
78 | const unsigned long mix_const = 0x5d6008cbf3848dd3UL; | ||
79 | #else | ||
80 | const unsigned long mix_const = 0x3f39e593UL; | ||
81 | #endif | ||
82 | unsigned long raw, random = get_random_boot(); | ||
83 | bool use_i8254 = true; | ||
84 | |||
85 | debug_putstr(purpose); | ||
86 | debug_putstr(" KASLR using"); | ||
87 | |||
88 | if (has_cpuflag(X86_FEATURE_RDRAND)) { | ||
89 | debug_putstr(" RDRAND"); | ||
90 | if (rdrand_long(&raw)) { | ||
91 | random ^= raw; | ||
92 | use_i8254 = false; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (has_cpuflag(X86_FEATURE_TSC)) { | ||
97 | debug_putstr(" RDTSC"); | ||
98 | raw = rdtsc(); | ||
99 | |||
100 | random ^= raw; | ||
101 | use_i8254 = false; | ||
102 | } | ||
103 | |||
104 | if (use_i8254) { | ||
105 | debug_putstr(" i8254"); | ||
106 | random ^= i8254(); | ||
107 | } | ||
108 | |||
109 | /* Circular multiply for better bit diffusion */ | ||
110 | asm("mul %3" | ||
111 | : "=a" (random), "=d" (raw) | ||
112 | : "a" (random), "rm" (mix_const)); | ||
113 | random += raw; | ||
114 | |||
115 | debug_putstr("...\n"); | ||
116 | |||
117 | return random; | ||
118 | } | ||
119 | 53 | ||
120 | struct mem_vector { | 54 | struct mem_vector { |
121 | unsigned long start; | 55 | unsigned long start; |
@@ -349,7 +283,7 @@ static unsigned long slots_fetch_random(void) | |||
349 | if (slot_max == 0) | 283 | if (slot_max == 0) |
350 | return 0; | 284 | return 0; |
351 | 285 | ||
352 | slot = get_random_long("Physical") % slot_max; | 286 | slot = kaslr_get_random_long("Physical") % slot_max; |
353 | 287 | ||
354 | for (i = 0; i < slot_area_index; i++) { | 288 | for (i = 0; i < slot_area_index; i++) { |
355 | if (slot >= slot_areas[i].num) { | 289 | if (slot >= slot_areas[i].num) { |
@@ -479,7 +413,7 @@ static unsigned long find_random_virt_addr(unsigned long minimum, | |||
479 | slots = (KERNEL_IMAGE_SIZE - minimum - image_size) / | 413 | slots = (KERNEL_IMAGE_SIZE - minimum - image_size) / |
480 | CONFIG_PHYSICAL_ALIGN + 1; | 414 | CONFIG_PHYSICAL_ALIGN + 1; |
481 | 415 | ||
482 | random_addr = get_random_long("Virtual") % slots; | 416 | random_addr = kaslr_get_random_long("Virtual") % slots; |
483 | 417 | ||
484 | return random_addr * CONFIG_PHYSICAL_ALIGN + minimum; | 418 | return random_addr * CONFIG_PHYSICAL_ALIGN + minimum; |
485 | } | 419 | } |
diff --git a/arch/x86/include/asm/kaslr.h b/arch/x86/include/asm/kaslr.h new file mode 100644 index 000000000000..5547438db5ea --- /dev/null +++ b/arch/x86/include/asm/kaslr.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _ASM_KASLR_H_ | ||
2 | #define _ASM_KASLR_H_ | ||
3 | |||
4 | unsigned long kaslr_get_random_long(const char *purpose); | ||
5 | |||
6 | #endif | ||
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 72a576752a7e..cfa6d076f4f2 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile | |||
@@ -24,6 +24,7 @@ lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o | |||
24 | lib-y += memcpy_$(BITS).o | 24 | lib-y += memcpy_$(BITS).o |
25 | lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o | 25 | lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o |
26 | lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o | 26 | lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o |
27 | lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o | ||
27 | 28 | ||
28 | obj-y += msr.o msr-reg.o msr-reg-export.o | 29 | obj-y += msr.o msr-reg.o msr-reg-export.o |
29 | 30 | ||
diff --git a/arch/x86/lib/kaslr.c b/arch/x86/lib/kaslr.c new file mode 100644 index 000000000000..f7dfeda83e5c --- /dev/null +++ b/arch/x86/lib/kaslr.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Entropy functions used on early boot for KASLR base and memory | ||
3 | * randomization. The base randomization is done in the compressed | ||
4 | * kernel and memory randomization is done early when the regular | ||
5 | * kernel starts. This file is included in the compressed kernel and | ||
6 | * normally linked in the regular. | ||
7 | */ | ||
8 | #include <asm/kaslr.h> | ||
9 | #include <asm/msr.h> | ||
10 | #include <asm/archrandom.h> | ||
11 | #include <asm/e820.h> | ||
12 | #include <asm/io.h> | ||
13 | |||
14 | /* | ||
15 | * When built for the regular kernel, several functions need to be stubbed out | ||
16 | * or changed to their regular kernel equivalent. | ||
17 | */ | ||
18 | #ifndef KASLR_COMPRESSED_BOOT | ||
19 | #include <asm/cpufeature.h> | ||
20 | #include <asm/setup.h> | ||
21 | |||
22 | #define debug_putstr(v) early_printk(v) | ||
23 | #define has_cpuflag(f) boot_cpu_has(f) | ||
24 | #define get_boot_seed() kaslr_offset() | ||
25 | #endif | ||
26 | |||
27 | #define I8254_PORT_CONTROL 0x43 | ||
28 | #define I8254_PORT_COUNTER0 0x40 | ||
29 | #define I8254_CMD_READBACK 0xC0 | ||
30 | #define I8254_SELECT_COUNTER0 0x02 | ||
31 | #define I8254_STATUS_NOTREADY 0x40 | ||
32 | static inline u16 i8254(void) | ||
33 | { | ||
34 | u16 status, timer; | ||
35 | |||
36 | do { | ||
37 | outb(I8254_PORT_CONTROL, | ||
38 | I8254_CMD_READBACK | I8254_SELECT_COUNTER0); | ||
39 | status = inb(I8254_PORT_COUNTER0); | ||
40 | timer = inb(I8254_PORT_COUNTER0); | ||
41 | timer |= inb(I8254_PORT_COUNTER0) << 8; | ||
42 | } while (status & I8254_STATUS_NOTREADY); | ||
43 | |||
44 | return timer; | ||
45 | } | ||
46 | |||
47 | unsigned long kaslr_get_random_long(const char *purpose) | ||
48 | { | ||
49 | #ifdef CONFIG_X86_64 | ||
50 | const unsigned long mix_const = 0x5d6008cbf3848dd3UL; | ||
51 | #else | ||
52 | const unsigned long mix_const = 0x3f39e593UL; | ||
53 | #endif | ||
54 | unsigned long raw, random = get_boot_seed(); | ||
55 | bool use_i8254 = true; | ||
56 | |||
57 | debug_putstr(purpose); | ||
58 | debug_putstr(" KASLR using"); | ||
59 | |||
60 | if (has_cpuflag(X86_FEATURE_RDRAND)) { | ||
61 | debug_putstr(" RDRAND"); | ||
62 | if (rdrand_long(&raw)) { | ||
63 | random ^= raw; | ||
64 | use_i8254 = false; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | if (has_cpuflag(X86_FEATURE_TSC)) { | ||
69 | debug_putstr(" RDTSC"); | ||
70 | raw = rdtsc(); | ||
71 | |||
72 | random ^= raw; | ||
73 | use_i8254 = false; | ||
74 | } | ||
75 | |||
76 | if (use_i8254) { | ||
77 | debug_putstr(" i8254"); | ||
78 | random ^= i8254(); | ||
79 | } | ||
80 | |||
81 | /* Circular multiply for better bit diffusion */ | ||
82 | asm("mul %3" | ||
83 | : "=a" (random), "=d" (raw) | ||
84 | : "a" (random), "rm" (mix_const)); | ||
85 | random += raw; | ||
86 | |||
87 | debug_putstr("...\n"); | ||
88 | |||
89 | return random; | ||
90 | } | ||