1
2
3
4
5
6
7
8
9#include <linux/cache.h>
10#include <linux/crc32.h>
11#include <linux/init.h>
12#include <linux/libfdt.h>
13#include <linux/mm_types.h>
14#include <linux/sched.h>
15#include <linux/types.h>
16
17#include <asm/cacheflush.h>
18#include <asm/fixmap.h>
19#include <asm/kernel-pgtable.h>
20#include <asm/memory.h>
21#include <asm/mmu.h>
22#include <asm/pgtable.h>
23#include <asm/sections.h>
24
25u64 __ro_after_init module_alloc_base;
26u16 __initdata memstart_offset_seed;
27
28static __init u64 get_kaslr_seed(void *fdt)
29{
30 int node, len;
31 fdt64_t *prop;
32 u64 ret;
33
34 node = fdt_path_offset(fdt, "/chosen");
35 if (node < 0)
36 return 0;
37
38 prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
39 if (!prop || len != sizeof(u64))
40 return 0;
41
42 ret = fdt64_to_cpu(*prop);
43 *prop = 0;
44 return ret;
45}
46
47static __init const u8 *kaslr_get_cmdline(void *fdt)
48{
49 static __initconst const u8 default_cmdline[] = CONFIG_CMDLINE;
50
51 if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) {
52 int node;
53 const u8 *prop;
54
55 node = fdt_path_offset(fdt, "/chosen");
56 if (node < 0)
57 goto out;
58
59 prop = fdt_getprop(fdt, node, "bootargs", NULL);
60 if (!prop)
61 goto out;
62 return prop;
63 }
64out:
65 return default_cmdline;
66}
67
68extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
69 pgprot_t prot);
70
71
72
73
74
75
76
77
78
79u64 __init kaslr_early_init(u64 dt_phys)
80{
81 void *fdt;
82 u64 seed, offset, mask, module_range;
83 const u8 *cmdline, *str;
84 int size;
85
86
87
88
89
90 module_alloc_base = (u64)_etext - MODULES_VSIZE;
91 __flush_dcache_area(&module_alloc_base, sizeof(module_alloc_base));
92
93
94
95
96
97
98 early_fixmap_init();
99 fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
100 if (!fdt)
101 return 0;
102
103
104
105
106 seed = get_kaslr_seed(fdt);
107 if (!seed)
108 return 0;
109
110
111
112
113
114 cmdline = kaslr_get_cmdline(fdt);
115 str = strstr(cmdline, "nokaslr");
116 if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
117 return 0;
118
119
120
121
122
123
124
125
126
127
128
129 mask = ((1UL << (VA_BITS - 2)) - 1) & ~(SZ_2M - 1);
130 offset = BIT(VA_BITS - 3) + (seed & mask);
131
132
133 memstart_offset_seed = seed >> 48;
134
135 if (IS_ENABLED(CONFIG_KASAN))
136
137
138
139
140
141
142
143
144 return offset % SZ_2G;
145
146 if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) {
147
148
149
150
151
152
153
154
155 module_range = SZ_4G - (u64)(_end - _stext);
156 module_alloc_base = max((u64)_end + offset - SZ_4G,
157 (u64)MODULES_VADDR);
158 } else {
159
160
161
162
163
164
165
166 module_range = MODULES_VSIZE - (u64)(_etext - _stext);
167 module_alloc_base = (u64)_etext + offset - MODULES_VSIZE;
168 }
169
170
171 module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21;
172 module_alloc_base &= PAGE_MASK;
173
174 __flush_dcache_area(&module_alloc_base, sizeof(module_alloc_base));
175 __flush_dcache_area(&memstart_offset_seed, sizeof(memstart_offset_seed));
176
177 return offset;
178}
179