]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gpiolib: acpi: Prevent out-of-bounds pin access in OperationRegion handler
authorMarco Scardovi <scardracs@disroot.org>
Wed, 10 Jun 2026 15:42:04 +0000 (17:42 +0200)
committerBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Wed, 17 Jun 2026 06:14:30 +0000 (08:14 +0200)
The ACPI GPIO OperationRegion handler receives pin offsets as a
64-bit address. Previously, this value could be assigned to a pin index
without validation, potentially causing out-of-bounds access if
the ACPI table provides an invalid offset.

This patch explicitly checks that the 64-bit address is less than
agpio->pin_table_length before using it, returning AE_BAD_PARAMETER
if the check fails. Additionally, it makes the length calculation
overflow-safe and ensures proper unsigned types for loop counters.

This corrects the commit message from v5 to accurately reflect the
underlying issue, removing references to truncation or wrap-around,
which do not occur in ACPICA.

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs@disroot.org>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Link: https://patch.msgid.link/20260610154204.110379-3-scardracs@disroot.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
drivers/gpio/gpiolib-acpi-core.c

index b09f89832890ef92477c4547d3aa49b5ddc7a787..220f0ac4204ef06b1899201cc4f91b8fe8993320 100644 (file)
@@ -1098,10 +1098,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
        struct gpio_chip *chip = achip->chip;
        struct acpi_resource_gpio *agpio;
        struct acpi_resource *ares;
-       u16 pin_index = address;
+       unsigned int length;
        acpi_status status;
-       int length;
-       int i;
+       unsigned int i;
+       u16 pin_index;
 
        status = acpi_buffer_to_resource(achip->conn_info.connection,
                                         achip->conn_info.length, &ares);
@@ -1121,7 +1121,14 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                return AE_BAD_PARAMETER;
        }
 
-       length = min(agpio->pin_table_length, pin_index + bits);
+       /* address represents GPIO pin index in connection table */
+       if (address >= agpio->pin_table_length) {
+               ACPI_FREE(ares);
+               return AE_BAD_PARAMETER;
+       }
+
+       pin_index = address;
+       length = min_t(unsigned int, agpio->pin_table_length, pin_index + bits);
        for (i = pin_index; i < length; ++i) {
                unsigned int pin = agpio->pin_table[i];
                struct acpi_gpio_connection *conn;