Commit 948a013a authored by Kiryl Shutsemau (Meta)'s avatar Kiryl Shutsemau (Meta) Committed by Ard Biesheuvel
Browse files

efi: Align unaccepted memory range to page boundary



The accept_memory() and range_contains_unaccepted_memory() functions
employ a "guard page" logic to prevent crashes with load_unaligned_zeropad().
This logic extends the range to be accepted (or checked) by one unit_size
if the end of the range is aligned to a unit_size boundary.

However, if the caller passes a range that is not page-aligned, the
'end' of the range might not be numerically aligned to unit_size, even
if it covers the last page of a unit. This causes the "if (!(end % unit_size))"
check to fail, skipping the necessary extension and leaving the next
unit unaccepted, which can lead to a kernel panic when accessed by
load_unaligned_zeropad().

Align the start address down and the size up to the nearest page
boundary before performing the unit_size alignment check. This ensures
that the guard unit is correctly added when the range effectively ends
on a unit boundary.

Signed-off-by: default avatarKiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Acked-by: default avatarMike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 0862438c
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -35,14 +35,17 @@ void accept_memory(phys_addr_t start, unsigned long size)
	struct efi_unaccepted_memory *unaccepted;
	unsigned long range_start, range_end;
	struct accept_range range, *entry;
	phys_addr_t end = start + size;
	unsigned long flags;
	phys_addr_t end;
	u64 unit_size;

	unaccepted = efi_get_unaccepted_table();
	if (!unaccepted)
		return;

	end = PAGE_ALIGN(start + size);
	start = PAGE_ALIGN_DOWN(start);

	unit_size = unaccepted->unit_size;

	/*
@@ -160,15 +163,18 @@ void accept_memory(phys_addr_t start, unsigned long size)
bool range_contains_unaccepted_memory(phys_addr_t start, unsigned long size)
{
	struct efi_unaccepted_memory *unaccepted;
	phys_addr_t end = start + size;
	unsigned long flags;
	bool ret = false;
	phys_addr_t end;
	u64 unit_size;

	unaccepted = efi_get_unaccepted_table();
	if (!unaccepted)
		return false;

	end = PAGE_ALIGN(start + size);
	start = PAGE_ALIGN_DOWN(start);

	unit_size = unaccepted->unit_size;

	/*