1 // SPDX-License-Identifier: GPL-2.0
3 * Helper functions used by the EFI stub on multiple
4 * architectures to deal with physical address space randomization.
11 * efi_kaslr_get_phys_seed() - Get random seed for physical kernel KASLR
12 * @image_handle: Handle to the image
14 * If KASLR is not disabled, obtain a random seed using EFI_RNG_PROTOCOL
15 * that will be used to move the kernel physical mapping.
17 * Return: the random seed
19 u32
efi_kaslr_get_phys_seed(efi_handle_t image_handle
)
21 efi_guid_t li_fixed_proto
= LINUX_EFI_LOADED_IMAGE_FIXED_GUID
;
24 if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE
))
28 efi_info("KASLR disabled on kernel command line\n");
29 } else if (efi_bs_call(handle_protocol
, image_handle
,
30 &li_fixed_proto
, &p
) == EFI_SUCCESS
) {
31 efi_info("Image placement fixed by loader\n");
36 status
= efi_get_random_bytes(sizeof(phys_seed
),
38 if (status
== EFI_SUCCESS
)
41 if (status
== EFI_NOT_FOUND
)
42 efi_info("EFI_RNG_PROTOCOL unavailable\n");
44 efi_err("efi_get_random_bytes() failed (0x%lx)\n", status
);
53 * Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
54 * to provide space, and fail to zero it). Check for this condition by double
55 * checking that the first and the last byte of the image are covered by the
56 * same EFI memory map entry.
58 static bool check_image_region(u64 base
, u64 size
)
60 struct efi_boot_memmap
*map
;
65 status
= efi_get_memory_map(&map
, false);
66 if (status
!= EFI_SUCCESS
)
69 for (map_offset
= 0; map_offset
< map
->map_size
; map_offset
+= map
->desc_size
) {
70 efi_memory_desc_t
*md
= (void *)map
->map
+ map_offset
;
71 u64 end
= md
->phys_addr
+ md
->num_pages
* EFI_PAGE_SIZE
;
74 * Find the region that covers base, and return whether
75 * it covers base+size bytes.
77 if (base
>= md
->phys_addr
&& base
< end
) {
78 ret
= (base
+ size
) <= end
;
83 efi_bs_call(free_pool
, map
);
89 * efi_kaslr_relocate_kernel() - Relocate the kernel (random if KASLR enabled)
90 * @image_addr: Pointer to the current kernel location
91 * @reserve_addr: Pointer to the relocated kernel location
92 * @reserve_size: Size of the relocated kernel
93 * @kernel_size: Size of the text + data
94 * @kernel_codesize: Size of the text
95 * @kernel_memsize: Size of the text + data + bss
96 * @phys_seed: Random seed used for the relocation
98 * If KASLR is not enabled, this function relocates the kernel to a fixed
99 * address (or leave it as its current location). If KASLR is enabled, the
100 * kernel physical location is randomized using the seed in parameter.
102 * Return: status code, EFI_SUCCESS if relocation is successful
104 efi_status_t
efi_kaslr_relocate_kernel(unsigned long *image_addr
,
105 unsigned long *reserve_addr
,
106 unsigned long *reserve_size
,
107 unsigned long kernel_size
,
108 unsigned long kernel_codesize
,
109 unsigned long kernel_memsize
,
113 u64 min_kimg_align
= efi_get_kimg_min_align();
115 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE
) && phys_seed
!= 0) {
117 * If KASLR is enabled, and we have some randomness available,
118 * locate the kernel at a randomized offset in physical memory.
120 status
= efi_random_alloc(*reserve_size
, min_kimg_align
,
121 reserve_addr
, phys_seed
,
122 EFI_LOADER_CODE
, 0, EFI_ALLOC_LIMIT
);
123 if (status
!= EFI_SUCCESS
)
124 efi_warn("efi_random_alloc() failed: 0x%lx\n", status
);
126 status
= EFI_OUT_OF_RESOURCES
;
129 if (status
!= EFI_SUCCESS
) {
130 if (!check_image_region(*image_addr
, kernel_memsize
)) {
131 efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
132 } else if (IS_ALIGNED(*image_addr
, min_kimg_align
) &&
133 (unsigned long)_end
< EFI_ALLOC_LIMIT
) {
135 * Just execute from wherever we were loaded by the
136 * UEFI PE/COFF loader if the placement is suitable.
142 status
= efi_allocate_pages_aligned(*reserve_size
, reserve_addr
,
143 ULONG_MAX
, min_kimg_align
,
146 if (status
!= EFI_SUCCESS
) {
147 efi_err("Failed to relocate kernel\n");
153 memcpy((void *)*reserve_addr
, (void *)*image_addr
, kernel_size
);
154 *image_addr
= *reserve_addr
;
155 efi_icache_sync(*image_addr
, *image_addr
+ kernel_codesize
);
156 efi_remap_image(*image_addr
, *reserve_size
, kernel_codesize
);