Commit 9b9eaee9 authored by Ard Biesheuvel's avatar Ard Biesheuvel

arm64: efi: Fix handling of misaligned runtime regions and drop warning

Currently, when mapping the EFI runtime regions in the EFI page tables,
we complain about misaligned regions in a rather noisy way, using
WARN().

Not only does this produce a lot of irrelevant clutter in the log, it is
factually incorrect, as misaligned runtime regions are actually allowed
by the EFI spec as long as they don't require conflicting memory types
within the same 64k page.

So let's drop the warning, and tweak the code so that we
- take both the start and end of the region into account when checking
  for misalignment
- only revert to RWX mappings for non-code regions if misaligned code
  regions are also known to exist.

Cc: <stable@vger.kernel.org>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 550b33cf
...@@ -13,6 +13,14 @@ ...@@ -13,6 +13,14 @@
#include <asm/efi.h> #include <asm/efi.h>
static bool region_is_misaligned(const efi_memory_desc_t *md)
{
if (PAGE_SIZE == EFI_PAGE_SIZE)
return false;
return !PAGE_ALIGNED(md->phys_addr) ||
!PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT);
}
/* /*
* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
* executable, everything else can be mapped with the XN bits * executable, everything else can be mapped with the XN bits
...@@ -26,14 +34,22 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) ...@@ -26,14 +34,22 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md)
if (type == EFI_MEMORY_MAPPED_IO) if (type == EFI_MEMORY_MAPPED_IO)
return PROT_DEVICE_nGnRE; return PROT_DEVICE_nGnRE;
if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr), if (region_is_misaligned(md)) {
"UEFI Runtime regions are not aligned to 64 KB -- buggy firmware?")) static bool __initdata code_is_misaligned;
/* /*
* If the region is not aligned to the page size of the OS, we * Regions that are not aligned to the OS page size cannot be
* can not use strict permissions, since that would also affect * mapped with strict permissions, as those might interfere
* the mapping attributes of the adjacent regions. * with the permissions that are needed by the adjacent
* region's mapping. However, if we haven't encountered any
* misaligned runtime code regions so far, we can safely use
* non-executable permissions for non-code regions.
*/ */
return pgprot_val(PAGE_KERNEL_EXEC); code_is_misaligned |= (type == EFI_RUNTIME_SERVICES_CODE);
return code_is_misaligned ? pgprot_val(PAGE_KERNEL_EXEC)
: pgprot_val(PAGE_KERNEL);
}
/* R-- */ /* R-- */
if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) == if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
...@@ -64,19 +80,16 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) ...@@ -64,19 +80,16 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE || bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE ||
md->type == EFI_RUNTIME_SERVICES_DATA); md->type == EFI_RUNTIME_SERVICES_DATA);
if (!PAGE_ALIGNED(md->phys_addr) || /*
!PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT)) { * If this region is not aligned to the page size used by the OS, the
/* * mapping will be rounded outwards, and may end up sharing a page
* If the end address of this region is not aligned to page * frame with an adjacent runtime memory region. Given that the page
* size, the mapping is rounded up, and may end up sharing a * table descriptor covering the shared page will be rewritten when the
* page frame with the next UEFI memory region. If we create * adjacent region gets mapped, we must avoid block mappings here so we
* a block entry now, we may need to split it again when mapping * don't have to worry about splitting them when that happens.
* the next region, and support for that is going to be removed */
* from the MMU routines. So avoid block mappings altogether in if (region_is_misaligned(md))
* that case.
*/
page_mappings_only = true; page_mappings_only = true;
}
create_pgd_mapping(mm, md->phys_addr, md->virt_addr, create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
md->num_pages << EFI_PAGE_SHIFT, md->num_pages << EFI_PAGE_SHIFT,
...@@ -103,6 +116,9 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm, ...@@ -103,6 +116,9 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE && BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
md->type != EFI_RUNTIME_SERVICES_DATA); md->type != EFI_RUNTIME_SERVICES_DATA);
if (region_is_misaligned(md))
return 0;
/* /*
* Calling apply_to_page_range() is only safe on regions that are * Calling apply_to_page_range() is only safe on regions that are
* guaranteed to be mapped down to pages. Since we are only called * guaranteed to be mapped down to pages. Since we are only called
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment