From 17189d9138fec95a7caacc0d6f602a5793d8f5dd Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 18 Aug 2020 11:13:53 +0200 Subject: ACPI: ioremap: avoid redundant rounding to OS page size The arm64 implementation of acpi_os_ioremap() was recently updated to tighten the checks around which parts of memory are permitted to be mapped by ACPI code, which generally only needs access to memory regions that are statically described by firmware, and any attempts to access memory that is in active use by the OS is generally a bug or a hacking attempt. This tightening is based on the EFI memory map, which describes all memory in the system. The AArch64 architecture permits page sizes of 16k and 64k in addition to the EFI default, which is 4k, which means that the EFI memory map may describe regions that cannot be mapped seamlessly if the OS page size is greater than 4k. This is usually not a problem, given that the EFI spec does not permit memory regions requiring different memory attributes to share a 64k page frame, and so the usual rounding to page size performed by ioremap() is sufficient to deal with this. However, this rounding does complicate our EFI memory map permission check, due to the loss of information that occurs when several small regions share a single 64k page frame (where rounding each of them will result in the same 64k single page region). However, due to the fact that the region check occurs *before* the call to ioremap() where the necessary rounding is performed, we can deal with this issue simply by removing the redundant rounding performed by acpi_os_map_iomem(), as it appears to be the only place where the arguments to a call to acpi_os_ioremap() are rounded up. So omit the rounding in the call, and instead, apply the necessary masking when assigning the map->virt member. Fixes: 1583052d111f ("arm64/acpi: disallow AML memory opregions to access kernel memory") Signed-off-by: Ard Biesheuvel Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/osl.c') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ad8cb05f672..74486bb5029a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -350,7 +350,7 @@ void __iomem __ref pg_off = round_down(phys, PAGE_SIZE); pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; - virt = acpi_map(pg_off, pg_sz); + virt = acpi_map(phys, size); if (!virt) { mutex_unlock(&acpi_ioremap_lock); kfree(map); @@ -358,7 +358,7 @@ void __iomem __ref } INIT_LIST_HEAD(&map->list); - map->virt = virt; + map->virt = (void __iomem __force *)((unsigned long)virt & PAGE_MASK); map->phys = pg_off; map->size = pg_sz; map->track.refcount = 1; -- cgit v1.2.3 From 33f61d725a86e9ae02bf504e9372ba973c010ddc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Aug 2020 19:42:55 +0200 Subject: ACPI: OSL: Prevent acpi_release_memory() from returning too early After commit 1757659d022b ("ACPI: OSL: Implement deferred unmapping of ACPI memory") in some cases acpi_release_memory() may return before the target memory mappings actually go away, because they are released asynchronously now. Prevent it from returning prematurely by making it wait for the next RCU grace period to elapse, for all of the RCU callbacks to complete and for all of the scheduled work items to be flushed before returning. Fixes: 1757659d022b ("ACPI: OSL: Implement deferred unmapping of ACPI memory") Reported-by: Kenneth R. Crudup Tested-by: Kenneth R. Crudup Signed-off-by: Rafael J. Wysocki Reviewed-by: Heikki Krogerus Reviewed-by: Mika Westerberg --- drivers/acpi/osl.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/acpi/osl.c') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 74486bb5029a..4a0b07792233 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1575,11 +1575,26 @@ static acpi_status acpi_deactivate_mem_region(acpi_handle handle, u32 level, acpi_status acpi_release_memory(acpi_handle handle, struct resource *res, u32 level) { + acpi_status status; + if (!(res->flags & IORESOURCE_MEM)) return AE_TYPE; - return acpi_walk_namespace(ACPI_TYPE_REGION, handle, level, - acpi_deactivate_mem_region, NULL, res, NULL); + status = acpi_walk_namespace(ACPI_TYPE_REGION, handle, level, + acpi_deactivate_mem_region, NULL, + res, NULL); + if (ACPI_FAILURE(status)) + return status; + + /* + * Wait for all of the mappings queued up for removal by + * acpi_deactivate_mem_region() to actually go away. + */ + synchronize_rcu(); + rcu_barrier(); + flush_scheduled_work(); + + return AE_OK; } EXPORT_SYMBOL_GPL(acpi_release_memory); -- cgit v1.2.3