Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f80fb3a3 AB |
2 | /* |
3 | * Copyright (C) 2016 Linaro Ltd <ard.biesheuvel@linaro.org> | |
f80fb3a3 AB |
4 | */ |
5 | ||
5a9e3e15 | 6 | #include <linux/cache.h> |
f80fb3a3 AB |
7 | #include <linux/crc32.h> |
8 | #include <linux/init.h> | |
9 | #include <linux/libfdt.h> | |
10 | #include <linux/mm_types.h> | |
11 | #include <linux/sched.h> | |
12 | #include <linux/types.h> | |
65fddcfc | 13 | #include <linux/pgtable.h> |
58552408 | 14 | #include <linux/random.h> |
f80fb3a3 | 15 | |
1598ecda | 16 | #include <asm/cacheflush.h> |
f80fb3a3 AB |
17 | #include <asm/fixmap.h> |
18 | #include <asm/kernel-pgtable.h> | |
19 | #include <asm/memory.h> | |
20 | #include <asm/mmu.h> | |
f80fb3a3 | 21 | #include <asm/sections.h> |
f6f0c436 | 22 | #include <asm/setup.h> |
f80fb3a3 | 23 | |
294a9ddd MB |
24 | enum kaslr_status { |
25 | KASLR_ENABLED, | |
26 | KASLR_DISABLED_CMDLINE, | |
27 | KASLR_DISABLED_NO_SEED, | |
28 | KASLR_DISABLED_FDT_REMAP, | |
29 | }; | |
30 | ||
2203e1ad | 31 | static enum kaslr_status __initdata kaslr_status; |
5a9e3e15 | 32 | u64 __ro_after_init module_alloc_base; |
c031a421 | 33 | u16 __initdata memstart_offset_seed; |
f80fb3a3 AB |
34 | |
35 | static __init u64 get_kaslr_seed(void *fdt) | |
36 | { | |
37 | int node, len; | |
67831edf | 38 | fdt64_t *prop; |
f80fb3a3 AB |
39 | u64 ret; |
40 | ||
41 | node = fdt_path_offset(fdt, "/chosen"); | |
42 | if (node < 0) | |
43 | return 0; | |
44 | ||
45 | prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len); | |
46 | if (!prop || len != sizeof(u64)) | |
47 | return 0; | |
48 | ||
49 | ret = fdt64_to_cpu(*prop); | |
50 | *prop = 0; | |
51 | return ret; | |
52 | } | |
53 | ||
a762f4ff | 54 | struct arm64_ftr_override kaslr_feature_override __initdata; |
f80fb3a3 | 55 | |
f80fb3a3 AB |
56 | /* |
57 | * This routine will be executed with the kernel mapped at its default virtual | |
58 | * address, and if it returns successfully, the kernel will be remapped, and | |
59 | * start_kernel() will be executed from a randomized virtual offset. The | |
60 | * relocation will result in all absolute references (e.g., static variables | |
61 | * containing function pointers) to be reinitialized, and zero-initialized | |
62 | * .bss variables will be reset to 0. | |
63 | */ | |
f6f0c436 | 64 | u64 __init kaslr_early_init(void) |
f80fb3a3 AB |
65 | { |
66 | void *fdt; | |
67 | u64 seed, offset, mask, module_range; | |
9bceb80b | 68 | unsigned long raw; |
f80fb3a3 AB |
69 | |
70 | /* | |
71 | * Set a reasonable default for module_alloc_base in case | |
72 | * we end up running with module randomization disabled. | |
73 | */ | |
74 | module_alloc_base = (u64)_etext - MODULES_VSIZE; | |
fade9c2c | 75 | dcache_clean_inval_poc((unsigned long)&module_alloc_base, |
814b1860 FT |
76 | (unsigned long)&module_alloc_base + |
77 | sizeof(module_alloc_base)); | |
f80fb3a3 AB |
78 | |
79 | /* | |
80 | * Try to map the FDT early. If this fails, we simply bail, | |
81 | * and proceed with KASLR disabled. We will make another | |
82 | * attempt at mapping the FDT in setup_machine() | |
83 | */ | |
f6f0c436 | 84 | fdt = get_early_fdt_ptr(); |
294a9ddd MB |
85 | if (!fdt) { |
86 | kaslr_status = KASLR_DISABLED_FDT_REMAP; | |
f80fb3a3 | 87 | return 0; |
294a9ddd | 88 | } |
f80fb3a3 AB |
89 | |
90 | /* | |
91 | * Retrieve (and wipe) the seed from the FDT | |
92 | */ | |
93 | seed = get_kaslr_seed(fdt); | |
f80fb3a3 AB |
94 | |
95 | /* | |
96 | * Check if 'nokaslr' appears on the command line, and | |
97 | * return 0 if that is the case. | |
98 | */ | |
a762f4ff | 99 | if (kaslr_feature_override.val & kaslr_feature_override.mask & 0xf) { |
294a9ddd | 100 | kaslr_status = KASLR_DISABLED_CMDLINE; |
f80fb3a3 | 101 | return 0; |
294a9ddd | 102 | } |
f80fb3a3 | 103 | |
2e8e1ea8 | 104 | /* |
9bceb80b GR |
105 | * Mix in any entropy obtainable architecturally if enabled |
106 | * and supported. | |
2e8e1ea8 | 107 | */ |
2e8e1ea8 | 108 | |
9bceb80b GR |
109 | if (arch_get_random_seed_long_early(&raw)) |
110 | seed ^= raw; | |
2e8e1ea8 | 111 | |
2203e1ad MB |
112 | if (!seed) { |
113 | kaslr_status = KASLR_DISABLED_NO_SEED; | |
114 | return 0; | |
115 | } | |
116 | ||
f80fb3a3 AB |
117 | /* |
118 | * OK, so we are proceeding with KASLR enabled. Calculate a suitable | |
119 | * kernel image offset from the seed. Let's place the kernel in the | |
90ec95cd | 120 | * middle half of the VMALLOC area (VA_BITS_MIN - 2), and stay clear of |
f2b9ba87 AB |
121 | * the lower and upper quarters to avoid colliding with other |
122 | * allocations. | |
f80fb3a3 AB |
123 | * Even if we could randomize at page granularity for 16k and 64k pages, |
124 | * let's always round to 2 MB so we don't interfere with the ability to | |
125 | * map using contiguous PTEs | |
126 | */ | |
90ec95cd SC |
127 | mask = ((1UL << (VA_BITS_MIN - 2)) - 1) & ~(SZ_2M - 1); |
128 | offset = BIT(VA_BITS_MIN - 3) + (seed & mask); | |
f80fb3a3 | 129 | |
c031a421 AB |
130 | /* use the top 16 bits to randomize the linear region */ |
131 | memstart_offset_seed = seed >> 48; | |
132 | ||
31d02e7a LC |
133 | if (!IS_ENABLED(CONFIG_KASAN_VMALLOC) && |
134 | (IS_ENABLED(CONFIG_KASAN_GENERIC) || | |
135 | IS_ENABLED(CONFIG_KASAN_SW_TAGS))) | |
f80fb3a3 | 136 | /* |
31d02e7a LC |
137 | * KASAN without KASAN_VMALLOC does not expect the module region |
138 | * to intersect the vmalloc region, since shadow memory is | |
139 | * allocated for each module at load time, whereas the vmalloc | |
140 | * region is shadowed by KASAN zero pages. So keep modules | |
141 | * out of the vmalloc region if KASAN is enabled without | |
142 | * KASAN_VMALLOC, and put the kernel well within 4 GB of the | |
143 | * module region. | |
f80fb3a3 | 144 | */ |
f2b9ba87 | 145 | return offset % SZ_2G; |
f80fb3a3 AB |
146 | |
147 | if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) { | |
148 | /* | |
b2eed9b5 | 149 | * Randomize the module region over a 2 GB window covering the |
f2b9ba87 | 150 | * kernel. This reduces the risk of modules leaking information |
f80fb3a3 AB |
151 | * about the address of the kernel itself, but results in |
152 | * branches between modules and the core kernel that are | |
153 | * resolved via PLTs. (Branches between modules will be | |
154 | * resolved normally.) | |
155 | */ | |
b2eed9b5 AB |
156 | module_range = SZ_2G - (u64)(_end - _stext); |
157 | module_alloc_base = max((u64)_end + offset - SZ_2G, | |
f2b9ba87 | 158 | (u64)MODULES_VADDR); |
f80fb3a3 AB |
159 | } else { |
160 | /* | |
161 | * Randomize the module region by setting module_alloc_base to | |
162 | * a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE, | |
163 | * _stext) . This guarantees that the resulting region still | |
164 | * covers [_stext, _etext], and that all relative branches can | |
f9c4ff2a BS |
165 | * be resolved without veneers unless this region is exhausted |
166 | * and we fall back to a larger 2GB window in module_alloc() | |
167 | * when ARM64_MODULE_PLTS is enabled. | |
f80fb3a3 AB |
168 | */ |
169 | module_range = MODULES_VSIZE - (u64)(_etext - _stext); | |
170 | module_alloc_base = (u64)_etext + offset - MODULES_VSIZE; | |
171 | } | |
172 | ||
173 | /* use the lower 21 bits to randomize the base of the module region */ | |
174 | module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21; | |
175 | module_alloc_base &= PAGE_MASK; | |
176 | ||
fade9c2c | 177 | dcache_clean_inval_poc((unsigned long)&module_alloc_base, |
814b1860 FT |
178 | (unsigned long)&module_alloc_base + |
179 | sizeof(module_alloc_base)); | |
fade9c2c | 180 | dcache_clean_inval_poc((unsigned long)&memstart_offset_seed, |
814b1860 FT |
181 | (unsigned long)&memstart_offset_seed + |
182 | sizeof(memstart_offset_seed)); | |
1598ecda | 183 | |
f80fb3a3 AB |
184 | return offset; |
185 | } | |
294a9ddd MB |
186 | |
187 | static int __init kaslr_init(void) | |
188 | { | |
189 | switch (kaslr_status) { | |
190 | case KASLR_ENABLED: | |
191 | pr_info("KASLR enabled\n"); | |
192 | break; | |
193 | case KASLR_DISABLED_CMDLINE: | |
194 | pr_info("KASLR disabled on command line\n"); | |
195 | break; | |
196 | case KASLR_DISABLED_NO_SEED: | |
197 | pr_warn("KASLR disabled due to lack of seed\n"); | |
198 | break; | |
199 | case KASLR_DISABLED_FDT_REMAP: | |
200 | pr_warn("KASLR disabled due to FDT remapping failure\n"); | |
201 | break; | |
202 | } | |
203 | ||
204 | return 0; | |
205 | } | |
206 | core_initcall(kaslr_init) |