From bd22f7e63509fa758cf500d9af3e88a3d3df96be Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 14 Oct 2026 11:38:25 +0200 Subject: [PATCH] gpio: shared: fix use-after-free bug when adding shared proxies The GPIO lookup table can stay alive for longer than the kobject whose name string's address we're assigning to lookup->dev_id. Fix a potential UAF by duplicating the string. Cc: stable@vger.kernel.org Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20261014-gpio-shared-fwnode-lookup-v4-1-2253ad645fd6@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-shared.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 5f9623e40b0f..6acfec73b734 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -450,7 +450,6 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle * const char *con_id, unsigned long lflags) { const char *dev_id = dev_name(consumer); - struct gpiod_lookup_table *lookup; struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; @@ -480,18 +479,22 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle * if (!key) return -ENOMEM; - lookup = kzalloc_flex(*lookup, table, 2); + struct gpiod_lookup_table *lookup __free(kfree) = + kzalloc_flex(*lookup, table, 2); if (!lookup) return -ENOMEM; pr_debug("Adding machine lookup entry for a shared GPIO for consumer %s, with key '%s' and con_id '%s'\n", dev_id, key, ref->con_id ?: "none"); - lookup->dev_id = dev_id; + lookup->dev_id = kstrdup(dev_id, GFP_KERNEL); + if (!lookup->dev_id) + return -ENOMEM; + lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0, ref->con_id, lflags); - ref->lookup = lookup; + ref->lookup = no_free_ptr(lookup); gpiod_add_lookup_table(ref->lookup); return 0; @@ -611,6 +614,7 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) if (ref->lookup) { gpiod_remove_lookup_table(ref->lookup); kfree(ref->lookup->table[0].key); + kfree(ref->lookup->dev_id); kfree(ref->lookup); ref->lookup = NULL; }