efi: memmap: Disregard bogus entries instead of returning them

The ESRT code currently contains two consistency checks on the memory
descriptor it obtains, but one of them is both incomplete and can only
trigger on invalid descriptors.

So let's drop these checks, and instead disregard descriptors entirely
if the start address is misaligned, or if the number of pages reaches
to or beyond the end of the address space.  Note that the memory map as
a whole could still be inconsistent: multiple entries might cover the
same area, or the address could be outside of the addressable PA space,
but validating that goes beyond the scope of these helpers.  Also note
that since the physical address space is never 64-bits wide, a
descriptor that includes the last page of memory is not valid.  This is
fortunate, since it means that a valid physical address will never be an
error pointer and that the length of a memory descriptor in bytes will
fit in a 64-bit unsigned integer.

Co-developed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Demi Marie Obenour <demi@invisiblethingslab.com>
Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Demi Marie Obenour 2023-01-19 14:03:56 -05:00 committed by Ard Biesheuvel
parent 2cf9e278ef
commit ab03e91e60
2 changed files with 7 additions and 8 deletions

View file

@ -496,6 +496,12 @@ int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
u64 size;
u64 end;
/* skip bogus entries (including empty ones) */
if ((md->phys_addr & (EFI_PAGE_SIZE - 1)) ||
(md->num_pages <= 0) ||
(md->num_pages > (U64_MAX - md->phys_addr) >> EFI_PAGE_SHIFT))
continue;
size = md->num_pages << EFI_PAGE_SHIFT;
end = md->phys_addr + size;
if (phys_addr >= md->phys_addr && phys_addr < end) {

View file

@ -263,15 +263,8 @@ void __init efi_esrt_init(void)
return;
}
max = efi_mem_desc_end(&md);
if (max < efi.esrt) {
pr_err("EFI memory descriptor is invalid. (esrt: %p max: %p)\n",
(void *)efi.esrt, (void *)max);
return;
}
max = efi_mem_desc_end(&md) - efi.esrt;
size = sizeof(*esrt);
max -= efi.esrt;
if (max < size) {
pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n",