From nobody Mon Jun 8 08:30:34 2026 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 92EF33876B8; Sun, 31 May 2026 12:08:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229336; cv=none; b=UJ3vM035518zQUJ3wqFM9XrGr5kjmrMclUJTvuTqUCGAWgN8IXINnKGtYsFrFLVFKt3gaG7So5qHugUAahW09YR5f5FfivOmKAlRt6RDkVgpMiQdwhj69q200QQm/8Hc5JHW5huO3Ixb1aywsD7+x647mmktsxVT3OUxBwLvZ7w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229336; c=relaxed/simple; bh=ao8E/HUJ95Uy8yFMTAXWVrLeFM6seDj/PETTG4aF4W8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=N6QycJG9PqwBrjA8UDWMs2/0oJMy1eeVsFYB7QOIDRbFl+IkV2piTYOsmIghKA3ZNxAsUxRwKOlljYyk4on4cwFMvHk4imUUWSlCwIAZWOy+oKaQaPvM9raygiNAELdaBqzt4Wo0eXgm8KLYZsKUIxF6xSr8e1q7WfLJIl2Wlos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=Q6o6G9yU; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="Q6o6G9yU" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 6D31D26A37; Sun, 31 May 2026 14:08:44 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id PFjZHU4N0jkD; Sun, 31 May 2026 14:08:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1780229323; bh=ao8E/HUJ95Uy8yFMTAXWVrLeFM6seDj/PETTG4aF4W8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Q6o6G9yU5OUMc6A+ylkAPQDy53az5494r1a1ae0NcWaOlX5LmSackaP3DeYdLgUWL Czdt1gYh6VTztwyEJ/9Na+mtl/pOP/l1hngSfMsJzWsIBSMCmzV1/K75TKMggJs0h6 ziMkcf1AZ4ahDX5BTZwF9VVBc8eKTKQZfxIl8tCVpX7vk2NtO8mDeQLp2SSoWCg0yP Yl6Jzuf9+POmrh6Cx1KOJqLIBsvRIDVKWZd4QvGOEtTt0Ft6ckkXpwi0HrSP3zfXlb Y1rd24fGshD+hVshMYRGMaZ3Q5piICEN9Rku4z/T0NliZDzUqxWyzJrCKQ3Cs4+J2o yTqXFISjRGuBg== From: Marco Scardovi To: Mika Westerberg , Andy Shevchenko , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, "Marco Scardovi (scardracs)" Subject: [PATCH v4 1/4] gpiolib: acpi: Add robust bounds-checking for GPIO pin resources Date: Sun, 31 May 2026 14:03:08 +0200 Message-ID: <20260531120816.17255-2-scardracs@disroot.org> In-Reply-To: <20260531120816.17255-1-scardracs@disroot.org> References: <20260531120816.17255-1-scardracs@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Marco Scardovi (scardracs)" Ensure that the GPIO pin resource arrays are safely bounded before accessing indices. Add bounds checking in acpi_request_own_gpiod(), acpi_gpio_irq_is_wake(), and acpi_gpiochip_alloc_event() to prevent out-of-bounds array reads if the ACPI namespace provides malformed or empty pin tables. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Marco Scardovi --- drivers/gpio/gpiolib-acpi-core.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-c= ore.c index eb8a40cfb7a9..a6d78dad299e 100644 --- a/drivers/gpio/gpiolib-acpi-core.c +++ b/drivers/gpio/gpiolib-acpi-core.c @@ -320,10 +320,18 @@ static struct gpio_desc *acpi_request_own_gpiod(struc= t gpio_chip *chip, unsigned int index, const char *label) { - int polarity =3D GPIO_ACTIVE_HIGH; - enum gpiod_flags flags =3D acpi_gpio_to_gpiod_flags(agpio, polarity); - unsigned int pin =3D agpio->pin_table[index]; struct gpio_desc *desc; + enum gpiod_flags flags; + unsigned int pin; + int polarity; + + polarity =3D GPIO_ACTIVE_HIGH; + flags =3D acpi_gpio_to_gpiod_flags(agpio, polarity); + + if (index >=3D agpio->pin_table_length) + return ERR_PTR(-EINVAL); + + pin =3D agpio->pin_table[index]; =20 desc =3D gpiochip_request_own_desc(chip, pin, label, polarity, flags); if (IS_ERR(desc)) @@ -337,11 +345,16 @@ static struct gpio_desc *acpi_request_own_gpiod(struc= t gpio_chip *chip, static bool acpi_gpio_irq_is_wake(struct device *parent, const struct acpi_resource_gpio *agpio) { - unsigned int pin =3D agpio->pin_table[0]; + unsigned int pin; =20 if (agpio->wake_capable !=3D ACPI_WAKE_CAPABLE) return false; =20 + if (agpio->pin_table_length =3D=3D 0) + return false; + + pin =3D agpio->pin_table[0]; + if (acpi_gpio_in_ignore_list(ACPI_GPIO_IGNORE_WAKE, dev_name(parent), pin= )) { dev_info(parent, "Ignoring wakeup on pin %u\n", pin); return false; @@ -368,6 +381,9 @@ static acpi_status acpi_gpiochip_alloc_event(struct acp= i_resource *ares, return AE_OK; =20 handle =3D ACPI_HANDLE(chip->parent); + if (agpio->pin_table_length =3D=3D 0) + return AE_OK; + pin =3D agpio->pin_table[0]; =20 if (pin <=3D 255) { --=20 2.54.0 From nobody Mon Jun 8 08:30:34 2026 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9516B387364; Sun, 31 May 2026 12:08:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229337; cv=none; b=Rfzhb5HOIFFNfuyypmsacDXHBlzNR4tyW6I/Ok+jxLhI9n8Xc1hzAF8D+zBduLSrVwjWwn6fvhp2MarPq/0Vu4Q4OuCl4RL1CrUnEYP5K5E2HRAQl/xQjqLFtS/A0owuRBuQAB4uOMvlYw31Tuw20mF860j5T2a4DV63GvWI8t0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229337; c=relaxed/simple; bh=Yb9n8lFcDW+MQasQQBR0L1bLDUzcSEP0Rh/ujJ55Wv0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WGD7fyFxIZIDqIrbaE6BcW2J+ldsVyEk3nPI/p6APybb6X9a3Iel9PChzofOsQnbJPwZXo6FLeNthGc6dJvyZ0pyobEljbCBOtxbPNImOAfj8L/yEKPfWmTq8QgBIF4EXjVO32IOppnPhzWo8oGwc+iRXwz1NtCE2rjkUGy4V/I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=N9TgIdVU; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="N9TgIdVU" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 5AE5A26E0B; Sun, 31 May 2026 14:08:45 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id zHmP-Z_jQxTi; Sun, 31 May 2026 14:08:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1780229324; bh=Yb9n8lFcDW+MQasQQBR0L1bLDUzcSEP0Rh/ujJ55Wv0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=N9TgIdVUVCXj+SCZrIRu3+MtWEy/jSgHsGg5VhUdPGC4D02YA51g5y6ADblVa3R1P 8vdKofpJ0cYeTb/shTAaEiIkrB3e+Ohqm8l5YS7wXzTQBAGgYq9XFTLa8Bfu2mBxwU SfLa8YUGYy8uhyoPeRzpaCJi/sqAoUNjFSVxQj1B5SYwyrVQVLLG2JRiib+S5fK5Ek e0zHWN6M/85DdfUqLBJCKVY3/8czPG+0G99Auw+q/ov9uNh+BkcQnDP3chXCsgm2OI 5aM1p7zAPhKk2rrR/uvrcIaSKU2UAbEcLGPOB+irwbd+Dsk5o/Wf4ofVNrn/NraoYy Rh/xcEcIyE44g== From: Marco Scardovi To: Mika Westerberg , Andy Shevchenko , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, "Marco Scardovi (scardracs)" Subject: [PATCH v4 2/4] gpiolib: acpi: fix resource leak in OpRegion Date: Sun, 31 May 2026 14:03:09 +0200 Message-ID: <20260531120816.17255-3-scardracs@disroot.org> In-Reply-To: <20260531120816.17255-1-scardracs@disroot.org> References: <20260531120816.17255-1-scardracs@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Marco Scardovi (scardracs)" If acpi_remove_address_space_handler() fails, the cleanup function acpi_gpiochip_free_regions() previously returned early. This leaks the connections list and all requested GPIO descriptors. Similarly, if acpi_gpio_adr_space_handler() fails to allocate a connection or request a GPIO descriptor during a multi-pin transaction, it exits without freeing the descriptors and connections that were already allocated in the same call. To avoid leaks, introduce a localized new_conns list inside the handler to track the new connections requested during the current transaction. On error, roll back only the connections in the new_conns list (avoiding deadlock on the non-recursive conn_lock and preventing over-cleanup of historic connections). On success, splice the new_conns list into the global achip->conns list under the conn_lock. Additionally, rename the global connection cleanup function to acpi_gpiochip_free_all_connections() and call it in the GPIO chip teardown path. Fixes: 473ed7be0da0 ("gpio / ACPI: Add support for ACPI GPIO operation regi= ons") Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Marco Scardovi --- drivers/gpio/gpiolib-acpi-core.c | 142 ++++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 31 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-c= ore.c index a6d78dad299e..e3bc4677b51d 100644 --- a/drivers/gpio/gpiolib-acpi-core.c +++ b/drivers/gpio/gpiolib-acpi-core.c @@ -1094,6 +1094,51 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device= *adev, const char *con_id, } EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_wake_get_by); =20 +static void acpi_gpiochip_free_connection_list(struct list_head *list) +{ + struct acpi_gpio_connection *conn; + struct acpi_gpio_connection *tmp; + + list_for_each_entry_safe_reverse(conn, tmp, list, node) { + gpiochip_free_own_desc(conn->desc); + list_del(&conn->node); + kfree(conn); + } +} + +static void acpi_gpiochip_free_all_connections(struct acpi_gpio_chip *achi= p) +{ + guard(mutex)(&achip->conn_lock); + + acpi_gpiochip_free_connection_list(&achip->conns); +} + +/* + * Find a connection in the global or local list. + * The caller must hold achip->conn_lock to protect the global list. + * The local list new_conns is private to the calling thread. + */ +static struct acpi_gpio_connection * +acpi_gpiochip_find_conn(struct acpi_gpio_chip *achip, + struct list_head *new_conns, unsigned int pin) +{ + struct acpi_gpio_connection *conn; + + list_for_each_entry(conn, &achip->conns, node) { + if (conn->pin =3D=3D pin) + return conn; + } + + if (new_conns) { + list_for_each_entry(conn, new_conns, node) { + if (conn->pin =3D=3D pin) + return conn; + } + } + + return NULL; +} + static acpi_status acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, u32 bits, u64 *value, void *handler_context, @@ -1101,11 +1146,16 @@ acpi_gpio_adr_space_handler(u32 function, acpi_phys= ical_address address, { struct acpi_gpio_chip *achip =3D region_context; struct gpio_chip *chip =3D achip->chip; + struct acpi_gpio_connection *other; + struct acpi_gpio_connection *conn; struct acpi_resource_gpio *agpio; struct acpi_resource *ares; u16 pin_index =3D address; + LIST_HEAD(new_conns); acpi_status status; int length; + u16 shift; + u16 word; int i; =20 status =3D acpi_buffer_to_resource(achip->conn_info.connection, @@ -1129,20 +1179,15 @@ acpi_gpio_adr_space_handler(u32 function, acpi_phys= ical_address address, length =3D min(agpio->pin_table_length, pin_index + bits); for (i =3D pin_index; i < length; ++i) { unsigned int pin =3D agpio->pin_table[i]; - struct acpi_gpio_connection *conn; struct gpio_desc *desc; - u16 word, shift; - bool found; + bool found =3D false; =20 mutex_lock(&achip->conn_lock); =20 - found =3D false; - list_for_each_entry(conn, &achip->conns, node) { - if (conn->pin =3D=3D pin) { - found =3D true; - desc =3D conn->desc; - break; - } + conn =3D acpi_gpiochip_find_conn(achip, &new_conns, pin); + if (conn) { + desc =3D conn->desc; + found =3D true; } =20 /* @@ -1163,34 +1208,66 @@ acpi_gpio_adr_space_handler(u32 function, acpi_phys= ical_address address, } } =20 + mutex_unlock(&achip->conn_lock); + if (!found) { desc =3D acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion"); if (IS_ERR(desc)) { - mutex_unlock(&achip->conn_lock); + /* + * In case of concurrent handler execution, another + * thread may have already requested the same GPIO, + * causing acpi_request_own_gpiod() to fail with -EBUSY. + * Re-check the visible connection lists and reuse an + * existing connection if one is found. + */ + if (PTR_ERR(desc) =3D=3D -EBUSY) { + mutex_lock(&achip->conn_lock); + conn =3D acpi_gpiochip_find_conn(achip, &new_conns, pin); + if (conn) { + desc =3D conn->desc; + found =3D true; + } + mutex_unlock(&achip->conn_lock); + if (found) + goto use_existing; + } status =3D AE_ERROR; - goto out; + goto err_free_new_conns; } =20 conn =3D kzalloc_obj(*conn); if (!conn) { gpiochip_free_own_desc(desc); - mutex_unlock(&achip->conn_lock); status =3D AE_NO_MEMORY; - goto out; + goto err_free_new_conns; } =20 conn->pin =3D pin; conn->desc =3D desc; - list_add_tail(&conn->node, &achip->conns); - } =20 - mutex_unlock(&achip->conn_lock); + mutex_lock(&achip->conn_lock); + /* + * Re-check both lists again before adding to local + * new_conns, as another thread could have completed + * and spliced its list while conn_lock was released. + */ + other =3D acpi_gpiochip_find_conn(achip, &new_conns, pin); + if (other) { + struct gpio_desc *desc_to_free =3D conn->desc; + struct acpi_gpio_connection *c_to_free =3D conn; =20 - /* - * For the cases when OperationRegion() consists of more than - * 64 bits calculate the word and bit shift to use that one to - * access the value. - */ + desc =3D other->desc; + mutex_unlock(&achip->conn_lock); + + gpiochip_free_own_desc(desc_to_free); + kfree(c_to_free); + } else { + list_add_tail(&conn->node, &new_conns); + mutex_unlock(&achip->conn_lock); + } + } + +use_existing: word =3D i / 64; shift =3D i % 64; =20 @@ -1204,9 +1281,19 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physi= cal_address address, } } =20 + mutex_lock(&achip->conn_lock); + list_splice_tail(&new_conns, &achip->conns); + mutex_unlock(&achip->conn_lock); + + status =3D AE_OK; + out: ACPI_FREE(ares); return status; + +err_free_new_conns: + acpi_gpiochip_free_connection_list(&new_conns); + goto out; } =20 static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip) @@ -1229,22 +1316,15 @@ static void acpi_gpiochip_free_regions(struct acpi_= gpio_chip *achip) { struct gpio_chip *chip =3D achip->chip; acpi_handle handle =3D ACPI_HANDLE(chip->parent); - struct acpi_gpio_connection *conn, *tmp; acpi_status status; =20 status =3D acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, acpi_gpio_adr_space_handler); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status)) dev_err(chip->parent, "Failed to remove GPIO OpRegion handler\n"); - return; - } =20 - list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) { - gpiochip_free_own_desc(conn->desc); - list_del(&conn->node); - kfree(conn); - } + acpi_gpiochip_free_all_connections(achip); } =20 void acpi_gpiochip_add(struct gpio_chip *chip) --=20 2.54.0 From nobody Mon Jun 8 08:30:34 2026 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5E80387590; Sun, 31 May 2026 12:08:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229335; cv=none; b=dSZEZOyW/is5lSsFn12Fu/nchp5KDYGfAjQeXQGT/vpeepEJwW2HMl/bdXYtjiRJRy5CGMEvRoydaNSeVDTsNs5HLmqXAxwLXuNC8i//ehNMxC2EkS6uc1h9xgPZLNA0TO/CY4pdz0lJXq5iq0bnW7QMQEiQ8t5XqBBIDjyNuN4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229335; c=relaxed/simple; bh=tdajEXMQ5N7AV+va3HatLfSv1PtR1PahzDWuNgcMkNQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NpRiw+GgsFk5ZZIyxmoyp+VEZe8axOS0FS2CIbnxp58SfBo6GGU53XIRnVeKZB1gO+WG1/S5NRbkL22uAuxrJRTPWZZil2BWgvhkPtcy5Qvfwv+MmF0oVd8/VIYnWxdrb5ZT/CWCXakWoLsLV/TxTpDEf0NQJQeffpLY8fRvXd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=ZHAiqnfK; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="ZHAiqnfK" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 8E3B42672E; Sun, 31 May 2026 14:08:45 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id R5Zm5lksZQRy; Sun, 31 May 2026 14:08:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1780229325; bh=tdajEXMQ5N7AV+va3HatLfSv1PtR1PahzDWuNgcMkNQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZHAiqnfKmAu98Iz7hW3Glo7x7slXk6pTHQ9J3NL/TqF9B8yTrNh5FGjomtkZxWduT k5j9AWB8QfHDER4T18iZqih++/kUnr0ckQh+tEPLIEFqk0MP4cloFZ7oVmZAs8JkKP NFHP7oKGB6q+Uz0ElQ+0T3+5VGzqfYSahAmBMS5O9zhJVCmDWwafMZe480ZKO4gs6/ /zcNFAlKG4bXyu4RBWlkMEQ4a3N5PxyePQrpFLXKV8SzrwmukXL9uesrBoSBo9lyRJ Be2KkBbZNUg/CbfEkaUkg5b96vcfzzLo9FnYcjY8+lGeDIXI/qHEVmGuyShWXkSwLr NK7Gt2vKPabww== From: Marco Scardovi To: Mika Westerberg , Andy Shevchenko , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 3/4] gpiolib: acpi: prevent address truncation in OperationRegion handler Date: Sun, 31 May 2026 14:03:10 +0200 Message-ID: <20260531120816.17255-4-scardracs@disroot.org> In-Reply-To: <20260531120816.17255-1-scardracs@disroot.org> References: <20260531120816.17255-1-scardracs@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The ACPI address space handler for GPIO OperationRegions receives the pin offset as a 64-bit acpi_physical_address. However, the handler truncates this address to a u16 pin_index before validating it. If an ACPI table attempts to access a pin offset greater than 65535, the truncation wraps the index around. This may result in accesses to unintended GPIO pins. Fix this by adding an explicit check to verify that the 64-bit address is less than agpio->pin_table_length before assigning it to the u16 pin_index, returning AE_BAD_PARAMETER if it is out of bounds. Additionally, make the length calculation overflow-safe and change the types of length and loop counter to unsigned. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Marco Scardovi --- drivers/gpio/gpiolib-acpi-core.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-c= ore.c index e3bc4677b51d..d12dab42a096 100644 --- a/drivers/gpio/gpiolib-acpi-core.c +++ b/drivers/gpio/gpiolib-acpi-core.c @@ -1150,13 +1150,13 @@ acpi_gpio_adr_space_handler(u32 function, acpi_phys= ical_address address, struct acpi_gpio_connection *conn; struct acpi_resource_gpio *agpio; struct acpi_resource *ares; - u16 pin_index =3D address; + unsigned int length; LIST_HEAD(new_conns); acpi_status status; - int length; + unsigned int i; + u16 pin_index; u16 shift; u16 word; - int i; =20 status =3D acpi_buffer_to_resource(achip->conn_info.connection, achip->conn_info.length, &ares); @@ -1176,7 +1176,17 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physi= cal_address address, return AE_BAD_PARAMETER; } =20 - length =3D min(agpio->pin_table_length, pin_index + bits); + if (address >=3D agpio->pin_table_length) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + pin_index =3D address; + if (bits > agpio->pin_table_length - pin_index) + length =3D agpio->pin_table_length; + else + length =3D pin_index + bits; + for (i =3D pin_index; i < length; ++i) { unsigned int pin =3D agpio->pin_table[i]; struct gpio_desc *desc; --=20 2.54.0 From nobody Mon Jun 8 08:30:34 2026 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC6BC388363; Sun, 31 May 2026 12:08:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229336; cv=none; b=PphpUCxK7SU9J5eGB8OvloqMdqaETUP/iObIqGAmRRWQW1XC7Mng9j4gjQTYeukcpNV1V61dtJhj8ndazR9v8RnrQswIwJT8tAWYOa/rLdkwTOqxaBAfPtCf0bugzKfRuzaHzV8VlWfTEHa0p6n4BWGniENpgc5UvplnLRYHiBE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780229336; c=relaxed/simple; bh=f+QFGKw57t7OAFxTEhRep7ZHukaojLVALJidlwEkm9A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jvhHx8SyYyejgWFZnjbIvryhxc8HtjUsr2qds65VU2aiVug/05O0E2qcyVigCTQn+thwkxXzg70+F9V2LsC0M3YO5BlHuGdySH1O763/8oT6rFMOT7AJlc+wkry2StahIUkhyrEP4JnZJOww5ao92Bx4vbwhzssdKVzerUOEIxo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=ij2bWptI; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="ij2bWptI" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 0E4A32691C; Sun, 31 May 2026 14:08:46 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Bs7vuvj2FXem; Sun, 31 May 2026 14:08:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1780229325; bh=f+QFGKw57t7OAFxTEhRep7ZHukaojLVALJidlwEkm9A=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ij2bWptIS8HBdbWSGC7+I3CeDV3zmRO8RhVfONMX/uKJgBhw0qaNpi+N9RgAFIIgP UxciY0d/7yORkgy3xKfBQNynbKVVn3vVcm2gMndfdMAUE8xYItYsOPzTM+Q6h0dG6T V+FkfdwW8nzFxynRPioknBbPY0acHvpqF2hnbPQh9s4DpoMu+NpbBe8ilCmmSf14+K y5I+7vsyWiwZETIPh1Pb4vk7fqmEhu+gUcIfBINkdX0J6tmp0lIez9iefZGmurkChD gRscBBi7iisD66ndSlfLLvuv4HYzPpN3MoZ4XXmi4W0nCZPMcD0TBbNvLqcLSLu71L uzJY0BELN+0Gw== From: Marco Scardovi To: Mika Westerberg , Andy Shevchenko , Linus Walleij , Bartosz Golaszewski Cc: linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v4 4/4] gpiolib: acpi: fix out-of-bounds pointer arithmetic in acpi_gpio_package_count Date: Sun, 31 May 2026 14:03:11 +0200 Message-ID: <20260531120816.17255-5-scardracs@disroot.org> In-Reply-To: <20260531120816.17255-1-scardracs@disroot.org> References: <20260531120816.17255-1-scardracs@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When counting GPIOs in an ACPI package, encountering a reference or string causes the element pointer to be advanced by 3 (element +=3D 3) and then by 1 (element++). If a malformed ACPI package contains fewer than 4 remaining elements when a reference or string is processed, this pointer arithmetic advances the element pointer past the end of the package elements array. This results in undefined behavior and can cause out-of-bounds reads. Fix this by ensuring at least 4 elements remain in the package before advancing the element pointer, returning -EPROTO if the package structure is invalid. Assisted-by: Antigravity:gemini-3.5-flash Signed-off-by: Marco Scardovi --- drivers/gpio/gpiolib-acpi-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi-core.c b/drivers/gpio/gpiolib-acpi-c= ore.c index d12dab42a096..b19fd02b64d0 100644 --- a/drivers/gpio/gpiolib-acpi-core.c +++ b/drivers/gpio/gpiolib-acpi-core.c @@ -1407,6 +1407,8 @@ static int acpi_gpio_package_count(const union acpi_o= bject *obj) switch (element->type) { case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_STRING: + if (end - element < 4) + return -EPROTO; element +=3D 3; fallthrough; case ACPI_TYPE_INTEGER: --=20 2.54.0