aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/Kconfig5
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c40
-rw-r--r--drivers/firmware/efi/libstub/arm64-stub.c78
-rw-r--r--drivers/firmware/efi/libstub/fdt.c14
4 files changed, 102 insertions, 35 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 968fa13cc25b..b6460911dd92 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -810,6 +810,11 @@ config RANDOMIZE_BASE
810 It is the bootloader's job to provide entropy, by passing a 810 It is the bootloader's job to provide entropy, by passing a
811 random u64 value in /chosen/kaslr-seed at kernel entry. 811 random u64 value in /chosen/kaslr-seed at kernel entry.
812 812
813 When booting via the UEFI stub, it will invoke the firmware's
814 EFI_RNG_PROTOCOL implementation (if available) to supply entropy
815 to the kernel proper. In addition, it will randomise the physical
816 location of the kernel Image as well.
817
813 If unsure, say N. 818 If unsure, say N.
814 819
815config RANDOMIZE_MODULE_REGION_FULL 820config RANDOMIZE_MODULE_REGION_FULL
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 3397902e4040..4deb3e7faa0e 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -18,6 +18,8 @@
18 18
19#include "efistub.h" 19#include "efistub.h"
20 20
21bool __nokaslr;
22
21static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg) 23static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg)
22{ 24{
23 static efi_guid_t const var_guid = EFI_GLOBAL_VARIABLE_GUID; 25 static efi_guid_t const var_guid = EFI_GLOBAL_VARIABLE_GUID;
@@ -207,14 +209,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
207 pr_efi_err(sys_table, "Failed to find DRAM base\n"); 209 pr_efi_err(sys_table, "Failed to find DRAM base\n");
208 goto fail; 210 goto fail;
209 } 211 }
210 status = handle_kernel_image(sys_table, image_addr, &image_size,
211 &reserve_addr,
212 &reserve_size,
213 dram_base, image);
214 if (status != EFI_SUCCESS) {
215 pr_efi_err(sys_table, "Failed to relocate kernel\n");
216 goto fail;
217 }
218 212
219 /* 213 /*
220 * Get the command line from EFI, using the LOADED_IMAGE 214 * Get the command line from EFI, using the LOADED_IMAGE
@@ -224,7 +218,28 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
224 cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size); 218 cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
225 if (!cmdline_ptr) { 219 if (!cmdline_ptr) {
226 pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n"); 220 pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
227 goto fail_free_image; 221 goto fail;
222 }
223
224 /* check whether 'nokaslr' was passed on the command line */
225 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
226 static const u8 default_cmdline[] = CONFIG_CMDLINE;
227 const u8 *str, *cmdline = cmdline_ptr;
228
229 if (IS_ENABLED(CONFIG_CMDLINE_FORCE))
230 cmdline = default_cmdline;
231 str = strstr(cmdline, "nokaslr");
232 if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
233 __nokaslr = true;
234 }
235
236 status = handle_kernel_image(sys_table, image_addr, &image_size,
237 &reserve_addr,
238 &reserve_size,
239 dram_base, image);
240 if (status != EFI_SUCCESS) {
241 pr_efi_err(sys_table, "Failed to relocate kernel\n");
242 goto fail_free_cmdline;
228 } 243 }
229 244
230 status = efi_parse_options(cmdline_ptr); 245 status = efi_parse_options(cmdline_ptr);
@@ -244,7 +259,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
244 259
245 if (status != EFI_SUCCESS) { 260 if (status != EFI_SUCCESS) {
246 pr_efi_err(sys_table, "Failed to load device tree!\n"); 261 pr_efi_err(sys_table, "Failed to load device tree!\n");
247 goto fail_free_cmdline; 262 goto fail_free_image;
248 } 263 }
249 } 264 }
250 265
@@ -286,12 +301,11 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
286 efi_free(sys_table, initrd_size, initrd_addr); 301 efi_free(sys_table, initrd_size, initrd_addr);
287 efi_free(sys_table, fdt_size, fdt_addr); 302 efi_free(sys_table, fdt_size, fdt_addr);
288 303
289fail_free_cmdline:
290 efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
291
292fail_free_image: 304fail_free_image:
293 efi_free(sys_table, image_size, *image_addr); 305 efi_free(sys_table, image_size, *image_addr);
294 efi_free(sys_table, reserve_size, reserve_addr); 306 efi_free(sys_table, reserve_size, reserve_addr);
307fail_free_cmdline:
308 efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
295fail: 309fail:
296 return EFI_ERROR; 310 return EFI_ERROR;
297} 311}
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 78dfbd34b6bf..e0e6b74fef8f 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -13,6 +13,10 @@
13#include <asm/efi.h> 13#include <asm/efi.h>
14#include <asm/sections.h> 14#include <asm/sections.h>
15 15
16#include "efistub.h"
17
18extern bool __nokaslr;
19
16efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, 20efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
17 unsigned long *image_addr, 21 unsigned long *image_addr,
18 unsigned long *image_size, 22 unsigned long *image_size,
@@ -23,26 +27,52 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
23{ 27{
24 efi_status_t status; 28 efi_status_t status;
25 unsigned long kernel_size, kernel_memsize = 0; 29 unsigned long kernel_size, kernel_memsize = 0;
26 unsigned long nr_pages;
27 void *old_image_addr = (void *)*image_addr; 30 void *old_image_addr = (void *)*image_addr;
28 unsigned long preferred_offset; 31 unsigned long preferred_offset;
32 u64 phys_seed = 0;
33
34 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
35 if (!__nokaslr) {
36 status = efi_get_random_bytes(sys_table_arg,
37 sizeof(phys_seed),
38 (u8 *)&phys_seed);
39 if (status == EFI_NOT_FOUND) {
40 pr_efi(sys_table_arg, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
41 } else if (status != EFI_SUCCESS) {
42 pr_efi_err(sys_table_arg, "efi_get_random_bytes() failed\n");
43 return status;
44 }
45 } else {
46 pr_efi(sys_table_arg, "KASLR disabled on kernel command line\n");
47 }
48 }
29 49
30 /* 50 /*
31 * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond 51 * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
32 * a 2 MB aligned base, which itself may be lower than dram_base, as 52 * a 2 MB aligned base, which itself may be lower than dram_base, as
33 * long as the resulting offset equals or exceeds it. 53 * long as the resulting offset equals or exceeds it.
34 */ 54 */
35 preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET; 55 preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET;
36 if (preferred_offset < dram_base) 56 if (preferred_offset < dram_base)
37 preferred_offset += SZ_2M; 57 preferred_offset += MIN_KIMG_ALIGN;
38 58
39 /* Relocate the image, if required. */
40 kernel_size = _edata - _text; 59 kernel_size = _edata - _text;
41 if (*image_addr != preferred_offset) { 60 kernel_memsize = kernel_size + (_end - _edata);
42 kernel_memsize = kernel_size + (_end - _edata); 61
62 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
63 /*
64 * If KASLR is enabled, and we have some randomness available,
65 * locate the kernel at a randomized offset in physical memory.
66 */
67 *reserve_size = kernel_memsize + TEXT_OFFSET;
68 status = efi_random_alloc(sys_table_arg, *reserve_size,
69 MIN_KIMG_ALIGN, reserve_addr,
70 phys_seed);
43 71
72 *image_addr = *reserve_addr + TEXT_OFFSET;
73 } else {
44 /* 74 /*
45 * First, try a straight allocation at the preferred offset. 75 * Else, try a straight allocation at the preferred offset.
46 * This will work around the issue where, if dram_base == 0x0, 76 * This will work around the issue where, if dram_base == 0x0,
47 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the 77 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the
48 * address of the allocation to be mistaken for a FAIL return 78 * address of the allocation to be mistaken for a FAIL return
@@ -52,27 +82,31 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
52 * Mustang), we can still place the kernel at the address 82 * Mustang), we can still place the kernel at the address
53 * 'dram_base + TEXT_OFFSET'. 83 * 'dram_base + TEXT_OFFSET'.
54 */ 84 */
85 if (*image_addr == preferred_offset)
86 return EFI_SUCCESS;
87
55 *image_addr = *reserve_addr = preferred_offset; 88 *image_addr = *reserve_addr = preferred_offset;
56 nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / 89 *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN);
57 EFI_PAGE_SIZE; 90
58 status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, 91 status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
59 EFI_LOADER_DATA, nr_pages, 92 EFI_LOADER_DATA,
93 *reserve_size / EFI_PAGE_SIZE,
60 (efi_physical_addr_t *)reserve_addr); 94 (efi_physical_addr_t *)reserve_addr);
61 if (status != EFI_SUCCESS) { 95 }
62 kernel_memsize += TEXT_OFFSET;
63 status = efi_low_alloc(sys_table_arg, kernel_memsize,
64 SZ_2M, reserve_addr);
65 96
66 if (status != EFI_SUCCESS) { 97 if (status != EFI_SUCCESS) {
67 pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); 98 *reserve_size = kernel_memsize + TEXT_OFFSET;
68 return status; 99 status = efi_low_alloc(sys_table_arg, *reserve_size,
69 } 100 MIN_KIMG_ALIGN, reserve_addr);
70 *image_addr = *reserve_addr + TEXT_OFFSET; 101
102 if (status != EFI_SUCCESS) {
103 pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
104 *reserve_size = 0;
105 return status;
71 } 106 }
72 memcpy((void *)*image_addr, old_image_addr, kernel_size); 107 *image_addr = *reserve_addr + TEXT_OFFSET;
73 *reserve_size = kernel_memsize;
74 } 108 }
75 109 memcpy((void *)*image_addr, old_image_addr, kernel_size);
76 110
77 return EFI_SUCCESS; 111 return EFI_SUCCESS;
78} 112}
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index cf7b7d46302a..6dba78aef337 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -147,6 +147,20 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
147 if (status) 147 if (status)
148 goto fdt_set_fail; 148 goto fdt_set_fail;
149 149
150 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
151 efi_status_t efi_status;
152
153 efi_status = efi_get_random_bytes(sys_table, sizeof(fdt_val64),
154 (u8 *)&fdt_val64);
155 if (efi_status == EFI_SUCCESS) {
156 status = fdt_setprop(fdt, node, "kaslr-seed",
157 &fdt_val64, sizeof(fdt_val64));
158 if (status)
159 goto fdt_set_fail;
160 } else if (efi_status != EFI_NOT_FOUND) {
161 return efi_status;
162 }
163 }
150 return EFI_SUCCESS; 164 return EFI_SUCCESS;
151 165
152fdt_set_fail: 166fdt_set_fail: