Skip to content

Commit 1583052

Browse files
ardbiesheuvelctmarinas
authored andcommitted
arm64/acpi: disallow AML memory opregions to access kernel memory
AML uses SystemMemory opregions to allow AML handlers to access MMIO registers of, e.g., GPIO controllers, or access reserved regions of memory that are owned by the firmware. Currently, we also allow AML access to memory that is owned by the kernel and mapped via the linear region, which does not seem to be supported by a valid use case, and exposes the kernel's internal state to AML methods that may be buggy and exploitable. On arm64, ACPI support requires booting in EFI mode, and so we can cross reference the requested region against the EFI memory map, rather than just do a minimal check on the first page. So let's only permit regions to be remapped by the ACPI core if - they don't appear in the EFI memory map at all (which is the case for most MMIO), or - they are covered by a single region in the EFI memory map, which is not of a type that describes memory that is given to the kernel at boot. Reported-by: Jason A. Donenfeld <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]> Acked-by: Lorenzo Pieralisi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 9ebcfad commit 1583052

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

arch/arm64/include/asm/acpi.h

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,7 @@
4747
pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
4848

4949
/* ACPI table mapping after acpi_permanent_mmap is set */
50-
static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
51-
acpi_size size)
52-
{
53-
/* For normal memory we already have a cacheable mapping. */
54-
if (memblock_is_map_memory(phys))
55-
return (void __iomem *)__phys_to_virt(phys);
56-
57-
/*
58-
* We should still honor the memory's attribute here because
59-
* crash dump kernel possibly excludes some ACPI (reclaim)
60-
* regions from memblock list.
61-
*/
62-
return __ioremap(phys, size, __acpi_get_mem_attribute(phys));
63-
}
50+
void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
6451
#define acpi_os_ioremap acpi_os_ioremap
6552

6653
typedef u64 phys_cpuid_t;

arch/arm64/kernel/acpi.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,72 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
261261
return __pgprot(PROT_DEVICE_nGnRnE);
262262
}
263263

264+
void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
265+
{
266+
efi_memory_desc_t *md, *region = NULL;
267+
pgprot_t prot;
268+
269+
if (WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))
270+
return NULL;
271+
272+
for_each_efi_memory_desc(md) {
273+
u64 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
274+
275+
if (phys < md->phys_addr || phys >= end)
276+
continue;
277+
278+
if (phys + size > end) {
279+
pr_warn(FW_BUG "requested region covers multiple EFI memory regions\n");
280+
return NULL;
281+
}
282+
region = md;
283+
break;
284+
}
285+
286+
/*
287+
* It is fine for AML to remap regions that are not represented in the
288+
* EFI memory map at all, as it only describes normal memory, and MMIO
289+
* regions that require a virtual mapping to make them accessible to
290+
* the EFI runtime services.
291+
*/
292+
prot = __pgprot(PROT_DEVICE_nGnRnE);
293+
if (region) {
294+
switch (region->type) {
295+
case EFI_LOADER_CODE:
296+
case EFI_LOADER_DATA:
297+
case EFI_BOOT_SERVICES_CODE:
298+
case EFI_BOOT_SERVICES_DATA:
299+
case EFI_CONVENTIONAL_MEMORY:
300+
case EFI_PERSISTENT_MEMORY:
301+
pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
302+
return NULL;
303+
304+
case EFI_ACPI_RECLAIM_MEMORY:
305+
/*
306+
* ACPI reclaim memory is used to pass firmware tables
307+
* and other data that is intended for consumption by
308+
* the OS only, which may decide it wants to reclaim
309+
* that memory and use it for something else. We never
310+
* do that, but we usually add it to the linear map
311+
* anyway, in which case we should use the existing
312+
* mapping.
313+
*/
314+
if (memblock_is_map_memory(phys))
315+
return (void __iomem *)__phys_to_virt(phys);
316+
/* fall through */
317+
318+
default:
319+
if (region->attribute & EFI_MEMORY_WB)
320+
prot = PAGE_KERNEL;
321+
else if (region->attribute & EFI_MEMORY_WT)
322+
prot = __pgprot(PROT_NORMAL_WT);
323+
else if (region->attribute & EFI_MEMORY_WC)
324+
prot = __pgprot(PROT_NORMAL_NC);
325+
}
326+
}
327+
return __ioremap(phys, size, prot);
328+
}
329+
264330
/*
265331
* Claim Synchronous External Aborts as a firmware first notification.
266332
*

0 commit comments

Comments
 (0)