From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Linus Walleij <linusw@kernel.org>, Bartosz Golaszewski <brgl@kernel.org>
Cc: Andy Shevchenko <andy@kernel.org>,
Janusz Krzysztofik <jmkrzyszt@gmail.com>,
linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/5] gpiolib: fix GPIO descriptor leak in gpiod_get_array()
Date: Wed, 21 Oct 2026 12:02:06 -0700 [thread overview]
Message-ID: <20261021190212.2237804-1-dmitry.torokhov@gmail.com> (raw)
In gpiod_get_array(), descs->ndescs is used as the loop induction
variable and is only incremented at the end of each iteration. When
krealloc() fails on the first iteration (when index is 0), descs->desc[0]
has already been acquired via gpiod_get_index(), but descs->ndescs is
still 0. Consequently, gpiod_put_array() frees descs without releasing
descs->desc[0], leaking the descriptor.
Fix this by using a dedicated loop induction variable and incrementing
descs->ndescs immediately upon storing the retrieved descriptor.
Additionally, since the fast-path array_info setup only executes for
the first element (index 0), simplify the bitmap_set() calls to start at
bit 0 for count bits instead of calculating offsets from the loop index.
Fixes: bf9346f5d47b ("gpiolib: Identify arrays matching GPIO hardware")
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/gpio/gpiolib.c | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c0394c7d6279..21c9cea71c68 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -5193,7 +5193,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
struct gpio_descs *descs;
struct gpio_device *gdev;
struct gpio_array *array_info = NULL;
- int count, bitmap_size;
+ int i, count, bitmap_size;
unsigned long dflags;
size_t descs_size;
@@ -5206,21 +5206,21 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
if (!descs)
return ERR_PTR(-ENOMEM);
- for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {
- desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
+ for (i = 0; i < count; i++) {
+ desc = gpiod_get_index(dev, con_id, i, flags);
if (IS_ERR(desc)) {
gpiod_put_array(descs);
return ERR_CAST(desc);
}
- descs->desc[descs->ndescs] = desc;
+ descs->desc[descs->ndescs++] = desc;
gdev = gpiod_to_gpio_device(desc);
/*
* If pin hardware number of array member 0 is also 0, select
* its chip as a candidate for fast bitmap processing path.
*/
- if (descs->ndescs == 0 && gpiod_hwgpio(desc) == 0) {
+ if (i == 0 && gpiod_hwgpio(desc) == 0) {
struct gpio_descs *array;
bitmap_size = BITS_TO_LONGS(gdev->ngpio > count ?
@@ -5245,10 +5245,8 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
array_info->desc = descs->desc;
array_info->size = count;
array_info->gdev = gdev;
- bitmap_set(array_info->get_mask, descs->ndescs,
- count - descs->ndescs);
- bitmap_set(array_info->set_mask, descs->ndescs,
- count - descs->ndescs);
+ bitmap_set(array_info->get_mask, 0, count);
+ bitmap_set(array_info->set_mask, 0, count);
descs->info = array_info;
}
@@ -5258,38 +5256,34 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
/* Unmark array members which don't belong to the 'fast' chip */
if (array_info->gdev != gdev) {
- __clear_bit(descs->ndescs, array_info->get_mask);
- __clear_bit(descs->ndescs, array_info->set_mask);
+ __clear_bit(i, array_info->get_mask);
+ __clear_bit(i, array_info->set_mask);
}
/*
* Detect array members which belong to the 'fast' chip
* but their pins are not in hardware order.
*/
- else if (gpiod_hwgpio(desc) != descs->ndescs) {
+ else if (gpiod_hwgpio(desc) != i) {
/*
* Don't use fast path if all array members processed so
* far belong to the same chip as this one but its pin
* hardware number is different from its array index.
*/
- if (bitmap_full(array_info->get_mask, descs->ndescs)) {
+ if (bitmap_full(array_info->get_mask, i)) {
array_info = NULL;
} else {
- __clear_bit(descs->ndescs,
- array_info->get_mask);
- __clear_bit(descs->ndescs,
- array_info->set_mask);
+ __clear_bit(i, array_info->get_mask);
+ __clear_bit(i, array_info->set_mask);
}
} else {
dflags = READ_ONCE(desc->flags);
/* Exclude open drain or open source from fast output */
if (test_bit(GPIOD_FLAG_OPEN_DRAIN, &dflags) ||
test_bit(GPIOD_FLAG_OPEN_SOURCE, &dflags))
- __clear_bit(descs->ndescs,
- array_info->set_mask);
+ __clear_bit(i, array_info->set_mask);
/* Identify 'fast' pins which require invertion */
if (gpiod_is_active_low(desc))
- __set_bit(descs->ndescs,
- array_info->invert_mask);
+ __set_bit(i, array_info->invert_mask);
}
}
if (array_info)
--
2.56.0.307.g5fe7bd680c-goog
next reply other threads:[~2026-10-21 19:02 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 19:02 Dmitry Torokhov [this message]
2026-10-21 19:02 ` [PATCH 2/5] gpiolib: fix fast-path cancellation in gpiod_get_array() Dmitry Torokhov
2026-10-21 19:02 ` [PATCH 3/5] gpiolib: add support for scope-based management of GPIO descriptors Dmitry Torokhov
2026-10-21 19:02 ` [PATCH 4/5] gpiolib: use __free(gpiod_put_array) in gpiod_get_array() Dmitry Torokhov
2026-10-21 19:02 ` [PATCH 5/5] gpiolib: avoid krealloc() " Dmitry Torokhov
2026-10-21 19:34 ` Andy Shevchenko
2026-10-21 20:39 ` Dmitry Torokhov
2026-10-21 20:54 ` Andy Shevchenko
2026-10-21 21:17 ` Dmitry Torokhov
2026-10-22 16:56 ` Andy Shevchenko
2026-10-21 19:39 ` Andy Shevchenko
2026-10-21 19:36 ` [PATCH 1/5] gpiolib: fix GPIO descriptor leak " Andy Shevchenko
2026-10-21 19:43 ` Dmitry Torokhov
2026-10-22 8:19 ` Bartosz Golaszewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261021190212.2237804-1-dmitry.torokhov@gmail.com \
--to=dmitry.torokhov@gmail.com \
--cc=andy@kernel.org \
--cc=brgl@kernel.org \
--cc=jmkrzyszt@gmail.com \
--cc=linusw@kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.