summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2021-07-20 14:14:05 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-08-18 09:59:14 +0300
commitafcb84e6cf8cf8ab1fb8b4bfa44c6caad64ae581 (patch)
treec26eb9b49a7268813b831f06d1a24166895f7057
parente0ee8d9c31b5a670f35a4ff7e2daf59967f2f27a (diff)
downloadlinux-afcb84e6cf8cf8ab1fb8b4bfa44c6caad64ae581.tar.xz
arm64: efi: kaslr: Fix occasional random alloc (and boot) failure
[ Upstream commit 4152433c397697acc4b02c4a10d17d5859c2730d ] The EFI stub random allocator used for kaslr on arm64 has a subtle bug. In function get_entry_num_slots() which counts the number of possible allocation "slots" for the image in a given chunk of free EFI memory, "last_slot" can become negative if the chunk is smaller than the requested allocation size. The test "if (first_slot > last_slot)" doesn't catch it because both first_slot and last_slot are unsigned. I chose not to make them signed to avoid problems if this is ever used on architectures where there are meaningful addresses with the top bit set. Instead, fix it with an additional test against the allocation size. This can cause a boot failure in addition to a loss of randomisation due to another bug in the arm64 stub fixed separately. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Fixes: 2ddbfc81eac8 ("efi: stub: add implementation of efi_random_alloc()") Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/firmware/efi/libstub/randomalloc.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
index a408df474d83..724155b9e10d 100644
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -30,6 +30,8 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
(u64)ULONG_MAX);
+ if (region_end < size)
+ return 0;
first_slot = round_up(md->phys_addr, align);
last_slot = round_down(region_end - size + 1, align);