arm64: permit ACPI core to map kernel memory used for table overrides

Jonathan reports that the strict policy for memory mapped by the
ACPI core breaks the use case of passing ACPI table overrides via
initramfs. This is due to the fact that the memory type used for
loading the initramfs in memory is not recognized as a memory type
that is typically used by firmware to pass firmware tables.

Since the purpose of the strict policy is to ensure that no AML or
other ACPI code can manipulate any memory that is used by the kernel
to keep its internal state or the state of user tasks, we can relax
the permission check, and allow mappings of memory that is reserved
and marked as NOMAP via memblock, and therefore not covered by the
linear mapping to begin with.

Fixes: 1583052d111f ("arm64/acpi: disallow AML memory opregions to access kernel memory")
Fixes: 325f5585ec36 ("arm64/acpi: disallow writeable AML opregion mapping for EFI code regions")
Reported-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Tested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Link: https://lore.kernel.org/r/20200929132522.18067-1-ardb@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by Ard Biesheuvel and committed by Catalin Marinas a509a66a 75df529b

Changed files
+21 -3
arch
arm64
kernel
include
linux
+20 -2
arch/arm64/kernel/acpi.c
··· 298 298 case EFI_BOOT_SERVICES_DATA: 299 299 case EFI_CONVENTIONAL_MEMORY: 300 300 case EFI_PERSISTENT_MEMORY: 301 - pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys); 302 - return NULL; 301 + if (memblock_is_map_memory(phys) || 302 + !memblock_is_region_memory(phys, size)) { 303 + pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys); 304 + return NULL; 305 + } 306 + /* 307 + * Mapping kernel memory is permitted if the region in 308 + * question is covered by a single memblock with the 309 + * NOMAP attribute set: this enables the use of ACPI 310 + * table overrides passed via initramfs, which are 311 + * reserved in memory using arch_reserve_mem_area() 312 + * below. As this particular use case only requires 313 + * read access, fall through to the R/O mapping case. 314 + */ 315 + fallthrough; 303 316 304 317 case EFI_RUNTIME_SERVICES_CODE: 305 318 /* ··· 400 387 local_daif_restore(current_flags); 401 388 402 389 return err; 390 + } 391 + 392 + void arch_reserve_mem_area(acpi_physical_address addr, size_t size) 393 + { 394 + memblock_mark_nomap(addr, size); 403 395 }
+1 -1
include/linux/acpi.h
··· 958 958 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, 959 959 u32 val_a, u32 val_b); 960 960 961 - #ifdef CONFIG_X86 961 + #ifndef CONFIG_IA64 962 962 void arch_reserve_mem_area(acpi_physical_address addr, size_t size); 963 963 #else 964 964 static inline void arch_reserve_mem_area(acpi_physical_address addr,