From 4d23d84ef2d04ba554b3063931dd12bed4223e1f Mon Sep 17 00:00:00 2001 From: Jamie Nguyen Date: Tue, 13 Oct 2026 11:07:28 -0700 Subject: [PATCH] ACPI: sysfs: Map only the requested range in acpi_data_show() acpi_data_show() maps the whole data region on every read(), although it copies at most count bytes and sysfs passes at most PAGE_SIZE bytes per call. acpi_os_unmap_iomem() defers the iounmap until after an RCU grace period, so a process reading one of these files in a loop keeps many full-size mappings in flight. Map only the range being read. acpi_os_map_iomem() rounds the mapping to page boundaries, so each mapping is now at most two pages, whatever the size of the region. A malformed table can describe a region that wraps around the end of the physical address space. acpi_os_map_iomem() doesn't check for that, and its lookup of existing mappings then matches an unrelated mapping, with or without this change. Fail reads of such a region before mapping anything. Signed-off-by: Jamie Nguyen Link: https://patch.msgid.link/20261013180728.957618-1-jamien@nvidia.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index a99373547126..c7188d506dda 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -420,6 +420,7 @@ static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj, struct acpi_data_attr *data_attr; void __iomem *base; ssize_t size; + u64 end; data_attr = container_of(bin_attr, struct acpi_data_attr, attr); size = data_attr->attr.size; @@ -433,13 +434,17 @@ static ssize_t acpi_data_show(struct file *filp, struct kobject *kobj, if (count > size - offset) count = size - offset; - base = acpi_os_map_iomem(data_attr->addr, size); + /* acpi_os_map_iomem() can't handle a range that wraps around */ + if (check_add_overflow(data_attr->addr, size, &end)) + return -EINVAL; + + base = acpi_os_map_iomem(data_attr->addr + offset, count); if (!base) return -ENOMEM; - memcpy_fromio(buf, base + offset, count); + memcpy_fromio(buf, base, count); - acpi_os_unmap_iomem(base, size); + acpi_os_unmap_iomem(base, count); return count; }