Skip to content

Commit e009472

Browse files
Ard BiesheuvelAlex Shi
authored andcommitted
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> (cherry picked from commit 2b5fe07a78a09a32002642b8a823428ade611f16) Signed-off-by: Alex Shi <alex.shi@linaro.org>
1 parent 4a9c146 commit e009472

4 files changed

Lines changed: 102 additions & 35 deletions

File tree

arch/arm64/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,11 @@ config RANDOMIZE_BASE
760760
It is the bootloader's job to provide entropy, by passing a
761761
random u64 value in /chosen/kaslr-seed at kernel entry.
762762

763+
When booting via the UEFI stub, it will invoke the firmware's
764+
EFI_RNG_PROTOCOL implementation (if available) to supply entropy
765+
to the kernel proper. In addition, it will randomise the physical
766+
location of the kernel Image as well.
767+
763768
If unsure, say N.
764769

765770
config RANDOMIZE_MODULE_REGION_FULL

drivers/firmware/efi/libstub/arm-stub.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include "efistub.h"
2020

21+
bool __nokaslr;
22+
2123
static int efi_secureboot_enabled(efi_system_table_t *sys_table_arg)
2224
{
2325
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,
207209
pr_efi_err(sys_table, "Failed to find DRAM base\n");
208210
goto fail;
209211
}
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-
}
218212

219213
/*
220214
* 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,
224218
cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
225219
if (!cmdline_ptr) {
226220
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;
228243
}
229244

230245
status = efi_parse_options(cmdline_ptr);
@@ -244,7 +259,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
244259

245260
if (status != EFI_SUCCESS) {
246261
pr_efi_err(sys_table, "Failed to load device tree!\n");
247-
goto fail_free_cmdline;
262+
goto fail_free_image;
248263
}
249264
}
250265

@@ -286,12 +301,11 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
286301
efi_free(sys_table, initrd_size, initrd_addr);
287302
efi_free(sys_table, fdt_size, fdt_addr);
288303

289-
fail_free_cmdline:
290-
efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
291-
292304
fail_free_image:
293305
efi_free(sys_table, image_size, *image_addr);
294306
efi_free(sys_table, reserve_size, reserve_addr);
307+
fail_free_cmdline:
308+
efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
295309
fail:
296310
return EFI_ERROR;
297311
}

drivers/firmware/efi/libstub/arm64-stub.c

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#include <asm/efi.h>
1414
#include <asm/sections.h>
1515

16+
#include "efistub.h"
17+
18+
extern bool __nokaslr;
19+
1620
efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
1721
unsigned long *image_addr,
1822
unsigned long *image_size,
@@ -23,26 +27,52 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
2327
{
2428
efi_status_t status;
2529
unsigned long kernel_size, kernel_memsize = 0;
26-
unsigned long nr_pages;
2730
void *old_image_addr = (void *)*image_addr;
2831
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+
}
2949

3050
/*
3151
* The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
3252
* a 2 MB aligned base, which itself may be lower than dram_base, as
3353
* long as the resulting offset equals or exceeds it.
3454
*/
35-
preferred_offset = round_down(dram_base, SZ_2M) + TEXT_OFFSET;
55+
preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET;
3656
if (preferred_offset < dram_base)
37-
preferred_offset += SZ_2M;
57+
preferred_offset += MIN_KIMG_ALIGN;
3858

39-
/* Relocate the image, if required. */
4059
kernel_size = _edata - _text;
41-
if (*image_addr != preferred_offset) {
42-
kernel_memsize = kernel_size + (_end - _edata);
60+
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);
4371

72+
*image_addr = *reserve_addr + TEXT_OFFSET;
73+
} else {
4474
/*
45-
* First, try a straight allocation at the preferred offset.
75+
* Else, try a straight allocation at the preferred offset.
4676
* This will work around the issue where, if dram_base == 0x0,
4777
* efi_low_alloc() refuses to allocate at 0x0 (to prevent the
4878
* 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,
5282
* Mustang), we can still place the kernel at the address
5383
* 'dram_base + TEXT_OFFSET'.
5484
*/
85+
if (*image_addr == preferred_offset)
86+
return EFI_SUCCESS;
87+
5588
*image_addr = *reserve_addr = preferred_offset;
56-
nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) /
57-
EFI_PAGE_SIZE;
89+
*reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN);
90+
5891
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,
6094
(efi_physical_addr_t *)reserve_addr);
61-
if (status != EFI_SUCCESS) {
62-
kernel_memsize += TEXT_OFFSET;
63-
status = efi_low_alloc(sys_table_arg, kernel_memsize,
64-
SZ_2M, reserve_addr);
95+
}
6596

66-
if (status != EFI_SUCCESS) {
67-
pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
68-
return status;
69-
}
70-
*image_addr = *reserve_addr + TEXT_OFFSET;
97+
if (status != EFI_SUCCESS) {
98+
*reserve_size = kernel_memsize + TEXT_OFFSET;
99+
status = efi_low_alloc(sys_table_arg, *reserve_size,
100+
MIN_KIMG_ALIGN, reserve_addr);
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;
71106
}
72-
memcpy((void *)*image_addr, old_image_addr, kernel_size);
73-
*reserve_size = kernel_memsize;
107+
*image_addr = *reserve_addr + TEXT_OFFSET;
74108
}
75-
109+
memcpy((void *)*image_addr, old_image_addr, kernel_size);
76110

77111
return EFI_SUCCESS;
78112
}

drivers/firmware/efi/libstub/fdt.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
147147
if (status)
148148
goto fdt_set_fail;
149149

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+
}
150164
return EFI_SUCCESS;
151165

152166
fdt_set_fail:

0 commit comments

Comments
 (0)