aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2016-01-26 08:48:29 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2016-02-24 09:57:29 -0500
commit2b5fe07a78a09a32002642b8a823428ade611f16 (patch)
treedb8929655f2d9de7827d68fbfad1ea08d1cd0e29 /drivers/firmware/efi
parent48fcb2d0216103d15306caa4814e2381104df6d8 (diff)
arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
Since arm64 does not use a decompressor that supplies an execution environment where it is feasible to some extent to provide a source of randomness, the arm64 KASLR kernel depends on the bootloader to supply some random bits in the /chosen/kaslr-seed DT property upon kernel entry. On UEFI systems, we can use the EFI_RNG_PROTOCOL, if supplied, to obtain some random bits. At the same time, use it to randomize the offset of the kernel Image in physical memory. Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'drivers/firmware/efi')
-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
3 files changed, 97 insertions, 35 deletions
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: