From: sashiko-bot@kernel.org
To: "Bartosz Golaszewski" <bartosz.golaszewski@oss.qualcomm.com>
Cc: linux-gpio@vger.kernel.org
Subject: Re: [PATCH v6 4/5] gpio: shared: detach the proxy device from struct gpio_shared_ref
Date: Wed, 21 Oct 2026 14:43:16 +0000 [thread overview]
Message-ID: <sashiko-outbox-180395@kernel.org> (raw)
In-Reply-To: <20261021-gpio-shared-fwnode-lookup-v6-4-6af7d8eefd25@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] gpio: shared: unlocked proxy_dev teardown in gpio_shared_remove_proxy_dev()
--
commit 744026242eec2478ed3cf7962883c73cf7ffb5cd
Author: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
gpio: shared: detach the proxy device from struct gpio_shared_ref
This commit moves the auxiliary device out of struct gpio_shared_ref in
drivers/gpio/gpiolib-shared.c and allocates it dynamically as proxy_dev
when setting up a shared GPIO proxy device.
> diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
> index 043d5daba7a73..3ed25609cae10 100644
> --- a/drivers/gpio/gpiolib-shared.c
> +++ b/drivers/gpio/gpiolib-shared.c
> @@ -35,11 +35,10 @@ struct gpio_shared_ref {
> /* GPIO flags this consumer uses for the request. */
> enum gpiod_flags flags;
> char *con_id;
> - int dev_id;
> /* Protects the auxiliary device struct and the lookup table. */
> struct mutex lock;
> struct lock_class_key lock_key;
> - struct auxiliary_device adev;
> + struct auxiliary_device *proxy_dev;
> struct gpiod_lookup_table *lookup;
> bool is_reset_gpio;
> };
[ ... ]
> @@ -306,31 +301,43 @@ static int gpio_shared_of_scan(void)
> }
> #endif /* CONFIG_OF */
>
> -static void gpio_shared_adev_release(struct device *dev)
> +static void gpio_shared_proxy_dev_release(struct device *dev)
> {
> + struct auxiliary_device *adev = to_auxiliary_dev(dev);
>
> + ida_free(&gpio_shared_ida, adev->id);
> + kfree(adev);
> }
>
> -static int gpio_shared_make_adev(struct gpio_device *gdev,
> - struct gpio_shared_entry *entry,
> - struct gpio_shared_ref *ref)
> +static int gpio_shared_make_proxy_dev(struct gpio_device *gdev,
> + struct gpio_shared_entry *entry,
> + struct gpio_shared_ref *ref)
> {
> - struct auxiliary_device *adev = &ref->adev;
> - int ret;
> + struct auxiliary_device *adev;
> + int ret, id;
>
> - guard(mutex)(&ref->lock);
> + adev = kzalloc_obj(*adev);
> + if (!adev)
> + return -ENOMEM;
[ ... ]
> pr_debug("Created an auxiliary GPIO proxy %s for GPIO device %s\n",
> dev_name(&adev->dev), gpio_device_get_label(gdev));
>
> + scoped_guard(mutex, &ref->lock) {
> + ref->proxy_dev = adev;
> + }
> +
> return 0;
> }
>
> @@ -480,7 +491,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *
> char *key __free(kfree) =
> kasprintf(GFP_KERNEL,
> KBUILD_MODNAME ".proxy.%u",
> - ref->adev.id);
> + ref->proxy_dev->id);
> if (!key)
> return -ENOMEM;
>
> @@ -511,10 +522,11 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *
> return -ENOENT;
> }
>
> -static void gpio_shared_remove_adev(struct auxiliary_device *adev)
> +static void gpio_shared_remove_proxy_dev(struct gpio_shared_ref *ref)
> {
> - auxiliary_device_delete(adev);
> - auxiliary_device_uninit(adev);
> + auxiliary_device_delete(ref->proxy_dev);
> + auxiliary_device_uninit(ref->proxy_dev);
> + ref->proxy_dev = NULL;
> }
[Severity: High]
Can tearing down ref->proxy_dev in gpio_shared_remove_proxy_dev() without
holding ref->lock race with concurrent readers and cause a use-after-free or
NULL pointer dereference?
In drivers/gpio/gpiolib-shared.c, struct gpio_shared_ref documents that
ref->lock protects the auxiliary device and the lookup table, and
gpio_shared_make_proxy_dev() assigns ref->proxy_dev under ref->lock.
However, gpio_shared_remove_proxy_dev() and gpio_shared_teardown_entry() do
not take ref->lock, and auxiliary_device_uninit(ref->proxy_dev) drops the
final reference and frees ref->proxy_dev via gpio_shared_proxy_dev_release()
before ref->proxy_dev is set to NULL.
In gpiochip_add_data_with_key(), gpiochip_setup_dev() calls gcdev_register()
while gdev is already visible on gpio_devices. If gpiochip_sysfs_register()
subsequently fails, the error path runs:
gpiochip_add_data_with_key()
-> gpio_device_teardown_shared()
-> gpio_shared_teardown_entry()
-> gpio_shared_remove_proxy_dev()
before gdev is removed from gpio_devices and synchronize_srcu() is called
(and gpiod_free_commit() leaves GPIOD_FLAG_SHARED set on the descriptor).
A concurrent consumer in gpiod_find_and_request() that looked up the
descriptor under gpio_devices_srcu can call gpio_shared_add_proxy_lookup(),
take ref->lock, and dereference ref->proxy_dev->id while
gpio_shared_remove_proxy_dev() is freeing ref->proxy_dev or after it has set
ref->proxy_dev to NULL.
Similarly, if a consumer node references multiple shared GPIOs with the same
fwnode and con_id across two GPIO controllers, requesting the pin on one
registered controller calls gpio_shared_add_proxy_lookup(), which walks
gpio_shared_list and can match the ref belonging to the second controller
while its ref->proxy_dev is still NULL or being torn down in
gpio_shared_remove_proxy_dev().
Concurrent gpiochip_setup_shared() calls for other controllers also walk
gpio_shared_list without ref->lock:
list_for_each_entry(entry, &gpio_shared_list, list) {
list_for_each_entry(ref, &entry->refs, list) {
if (ref->proxy_dev && gdev->dev.parent == &ref->proxy_dev->dev) {
which can read a non-NULL ref->proxy_dev pointer after
auxiliary_device_uninit() has already freed the structure (or after the slab
slot has been reallocated).
Note that the follow-up commit ("gpio: shared: convert to using software
nodes for GPIO shared proxy lookup") still leaves
gpio_shared_remove_proxy_dev() unlocked and frees ref->proxy_dev and
unregisters ref->proxy_swnode before clearing ref->proxy_dev and
ref->proxy_fwnode to NULL.
Should gpio_shared_remove_proxy_dev() and the readers of ref->proxy_dev
serialize access with ref->lock and check for a NULL ref->proxy_dev?
>
> static void gpio_shared_teardown_entry(struct gpio_device *gdev,
> @@ -534,7 +546,7 @@ static void gpio_shared_teardown_entry(struct gpio_device *gdev,
> ref->lookup = NULL;
> }
>
> - gpio_shared_remove_adev(&ref->adev);
> + gpio_shared_remove_proxy_dev(ref);
> }
> }
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021-gpio-shared-fwnode-lookup-v6-0-6af7d8eefd25@oss.qualcomm.com?part=4
next prev parent reply other threads:[~2026-10-21 14:43 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 14:23 [PATCH v6 0/5] gpio: shared: replace platform lookup with dummy software nodes Bartosz Golaszewski
2026-10-21 14:23 ` [PATCH v6 1/5] gpio: shared: factor out per-entry teardown helper Bartosz Golaszewski
2026-10-21 14:24 ` [PATCH v6 2/5] gpio: shared: factor out per-entry setup helper Bartosz Golaszewski
2026-10-21 14:24 ` [PATCH v6 3/5] gpio: shared: unwind partial failures in gpiochip_setup_shared() Bartosz Golaszewski
2026-10-21 14:24 ` [PATCH v6 4/5] gpio: shared: detach the proxy device from struct gpio_shared_ref Bartosz Golaszewski
2026-10-21 14:43 ` sashiko-bot [this message]
2026-10-21 14:24 ` [PATCH v6 5/5] gpio: shared: convert to using software nodes for GPIO shared proxy lookup Bartosz Golaszewski
2026-10-21 14:59 ` sashiko-bot
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=sashiko-outbox-180395@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bartosz.golaszewski@oss.qualcomm.com \
--cc=linux-gpio@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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.