Skip to content

Commit 5b94046

Browse files
committed
efi/libstub: arm64: Force Image reallocation if BSS was not reserved
Distro versions of GRUB replace the usual LoadImage/StartImage calls used to load the kernel image with some local code that fails to honor the allocation requirements described in the PE/COFF header, as it does not account for the image's BSS section at all: it fails to allocate space for it, and fails to zero initialize it. Since the EFI stub itself is allocated in the .init segment, which is in the middle of the image, its BSS section is not impacted by this, and the main consequence of this omission is that the BSS section may overlap with memory regions that are already used by the firmware. So let's warn about this condition, and force image reallocation to occur in this case, which works around the problem. Fixes: 8204670 ("efi/libstub/arm64: Replace 'preferred' offset with alignment check") Signed-off-by: Ard Biesheuvel <[email protected]> Tested-by: Benjamin Herrenschmidt <[email protected]>
1 parent 4152433 commit 5b94046

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,51 @@ efi_status_t check_platform_features(void)
3434
return EFI_SUCCESS;
3535
}
3636

37+
/*
38+
* Distro versions of GRUB may ignore the BSS allocation entirely (i.e., fail
39+
* to provide space, and fail to zero it). Check for this condition by double
40+
* checking that the first and the last byte of the image are covered by the
41+
* same EFI memory map entry.
42+
*/
43+
static bool check_image_region(u64 base, u64 size)
44+
{
45+
unsigned long map_size, desc_size, buff_size;
46+
efi_memory_desc_t *memory_map;
47+
struct efi_boot_memmap map;
48+
efi_status_t status;
49+
bool ret = false;
50+
int map_offset;
51+
52+
map.map = &memory_map;
53+
map.map_size = &map_size;
54+
map.desc_size = &desc_size;
55+
map.desc_ver = NULL;
56+
map.key_ptr = NULL;
57+
map.buff_size = &buff_size;
58+
59+
status = efi_get_memory_map(&map);
60+
if (status != EFI_SUCCESS)
61+
return false;
62+
63+
for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
64+
efi_memory_desc_t *md = (void *)memory_map + map_offset;
65+
u64 end = md->phys_addr + md->num_pages * EFI_PAGE_SIZE;
66+
67+
/*
68+
* Find the region that covers base, and return whether
69+
* it covers base+size bytes.
70+
*/
71+
if (base >= md->phys_addr && base < end) {
72+
ret = (base + size) <= end;
73+
break;
74+
}
75+
}
76+
77+
efi_bs_call(free_pool, memory_map);
78+
79+
return ret;
80+
}
81+
3782
/*
3883
* Although relocatable kernels can fix up the misalignment with respect to
3984
* MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
@@ -92,7 +137,9 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
92137
}
93138

94139
if (status != EFI_SUCCESS) {
95-
if (IS_ALIGNED((u64)_text, min_kimg_align())) {
140+
if (!check_image_region((u64)_text, kernel_memsize)) {
141+
efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
142+
} else if (IS_ALIGNED((u64)_text, min_kimg_align())) {
96143
/*
97144
* Just execute from wherever we were loaded by the
98145
* UEFI PE/COFF loader if the alignment is suitable.

0 commit comments

Comments
 (0)