public inbox for linux-iio@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path
@ 2026-04-11  8:04 Guangshuo Li
  2026-04-11  8:21 ` Dan Carpenter
  0 siblings, 1 reply; 4+ messages in thread
From: Guangshuo Li @ 2026-04-11  8:04 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Dan Carpenter, linux-iio, linux-kernel
  Cc: Guangshuo Li, stable

After device_initialize(), the lifetime of the embedded struct device
is expected to be managed through the device core reference counting.

In viio_trigger_alloc(), if irq_alloc_descs() or kvasprintf() fails,
the error path frees trig directly with kfree() rather than releasing
the device reference with put_device(). This bypasses the normal device
lifetime rules and may leave the reference count of the embedded struct
device unbalanced, resulting in a refcount leak and potentially leading
to a use-after-free.

Fix this by using put_device(&trig->dev) in the failure path and let
iio_trig_release() handle the final cleanup. Also update the subirq_base
check in iio_trig_release() to test for >= 0, so that a negative error
code from irq_alloc_descs() is not treated as a valid IRQ descriptor
base during cleanup.

Fixes: 2c99f1a09da3 ("iio: trigger: clean up viio_trigger_alloc()")
Cc: stable@vger.kernel.org
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
 drivers/iio/industrialio-trigger.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 54416a384232..ab544976018f 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -509,7 +509,7 @@ static void iio_trig_release(struct device *device)
 	struct iio_trigger *trig = to_iio_trigger(device);
 	int i;
 
-	if (trig->subirq_base) {
+	if (trig->subirq_base >= 0) {
 		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
 			irq_modify_status(trig->subirq_base + i,
 					  IRQ_NOAUTOEN,
@@ -572,11 +572,11 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
 					    CONFIG_IIO_CONSUMERS_PER_TRIGGER,
 					    0);
 	if (trig->subirq_base < 0)
-		goto free_trig;
+		goto err_put;
 
 	trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
 	if (trig->name == NULL)
-		goto free_descs;
+		goto err_put;
 
 	INIT_LIST_HEAD(&trig->list);
 
@@ -594,10 +594,8 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
 
 	return trig;
 
-free_descs:
-	irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
-free_trig:
-	kfree(trig);
+err_put:
+	put_device(&trig->dev);
 	return NULL;
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path
  2026-04-11  8:04 [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path Guangshuo Li
@ 2026-04-11  8:21 ` Dan Carpenter
  2026-04-11  9:30   ` Guangshuo Li
  0 siblings, 1 reply; 4+ messages in thread
From: Dan Carpenter @ 2026-04-11  8:21 UTC (permalink / raw)
  To: Guangshuo Li
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	linux-iio, linux-kernel, stable

On Sat, Apr 11, 2026 at 04:04:35PM +0800, Guangshuo Li wrote:
> After device_initialize(), the lifetime of the embedded struct device
  ^^^^^
The commit message says after but you're changing the before.

> is expected to be managed through the device core reference counting.
> 
> In viio_trigger_alloc(), if irq_alloc_descs() or kvasprintf() fails,
> the error path frees trig directly with kfree() rather than releasing
> the device reference with put_device(). This bypasses the normal device
> lifetime rules and may leave the reference count of the embedded struct
> device unbalanced, resulting in a refcount leak and potentially leading
> to a use-after-free.
> 
> Fix this by using put_device(&trig->dev) in the failure path and let
> iio_trig_release() handle the final cleanup. Also update the subirq_base
> check in iio_trig_release() to test for >= 0, so that a negative error
> code from irq_alloc_descs() is not treated as a valid IRQ descriptor
> base during cleanup.
> 
> Fixes: 2c99f1a09da3 ("iio: trigger: clean up viio_trigger_alloc()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
>  drivers/iio/industrialio-trigger.c | 12 +++++-------
>  1 file changed, 5 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
> index 54416a384232..ab544976018f 100644
> --- a/drivers/iio/industrialio-trigger.c
> +++ b/drivers/iio/industrialio-trigger.c
> @@ -509,7 +509,7 @@ static void iio_trig_release(struct device *device)
>  	struct iio_trigger *trig = to_iio_trigger(device);
>  	int i;
>  
> -	if (trig->subirq_base) {
> +	if (trig->subirq_base >= 0) {
>  		for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
>  			irq_modify_status(trig->subirq_base + i,
>  					  IRQ_NOAUTOEN,
> @@ -572,11 +572,11 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
>  					    CONFIG_IIO_CONSUMERS_PER_TRIGGER,
>  					    0);
>  	if (trig->subirq_base < 0)
> -		goto free_trig;
> +		goto err_put;
>  
>  	trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
>  	if (trig->name == NULL)
> -		goto free_descs;
> +		goto err_put;

At this point we haven't done:

	trig->dev.type = &iio_trig_type;
or
	device_initialize(&trig->dev);

So the original code is fine and the new code just introduces memory
leaks.

regards,
dan carpenter

>  
>  	INIT_LIST_HEAD(&trig->list);
>  
> @@ -594,10 +594,8 @@ struct iio_trigger *viio_trigger_alloc(struct device *parent,
>  
>  	return trig;
>  
> -free_descs:
> -	irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
> -free_trig:
> -	kfree(trig);
> +err_put:
> +	put_device(&trig->dev);
>  	return NULL;
>  }

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path
  2026-04-11  8:21 ` Dan Carpenter
@ 2026-04-11  9:30   ` Guangshuo Li
  2026-04-11 10:36     ` Dan Carpenter
  0 siblings, 1 reply; 4+ messages in thread
From: Guangshuo Li @ 2026-04-11  9:30 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	linux-iio, linux-kernel, stable

Hi Dan,

Thank you very much for your review and for pointing this out.

The kernel version on our side is `v6.19-rc8-214-ge7aa57247700`. For
clarity, below is the full `viio_trigger_alloc()` function in our
tree:

```c
struct iio_trigger *viio_trigger_alloc(struct device *parent,
       struct module *this_mod,
       const char *fmt,
       va_list vargs)
{
struct iio_trigger *trig;
int i;

trig = kzalloc(sizeof(*trig), GFP_KERNEL);
if (!trig)
return NULL;

trig->dev.parent = parent;
trig->dev.type = &iio_trig_type;
trig->dev.bus = &iio_bus_type;
device_initialize(&trig->dev);
INIT_WORK(&trig->reenable_work, iio_reenable_work_fn);

mutex_init(&trig->pool_lock);
trig->subirq_base = irq_alloc_descs(-1, 0,
    CONFIG_IIO_CONSUMERS_PER_TRIGGER,
    0);
if (trig->subirq_base < 0)
goto free_trig;

trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
if (trig->name == NULL)
goto free_descs;

INIT_LIST_HEAD(&trig->list);

trig->owner = this_mod;

trig->subirq_chip.name = trig->name;
trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
irq_set_chip(trig->subirq_base + i, &trig->subirq_chip);
irq_set_handler(trig->subirq_base + i, &handle_simple_irq);
irq_modify_status(trig->subirq_base + i,
  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
}

return trig;

free_descs:
irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
free_trig:
kfree(trig);
return NULL;
}
```

So in this version, both error paths are reached after `device_initialize()`.

That was why I thought `put_device(&trig->dev)` would be more
appropriate here than freeing `trig` directly with `kfree()`.

Also, since `irq_alloc_descs()` can return a negative error code, I
thought changing the release-side check to `trig->subirq_base >= 0`
was needed as well.

I may be missing something here, so I would very much appreciate any
correction if my understanding is off.

Best regards,
Guangshuo

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path
  2026-04-11  9:30   ` Guangshuo Li
@ 2026-04-11 10:36     ` Dan Carpenter
  0 siblings, 0 replies; 4+ messages in thread
From: Dan Carpenter @ 2026-04-11 10:36 UTC (permalink / raw)
  To: Guangshuo Li
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	linux-iio, linux-kernel, stable

Ah, yes.  It *was* a real bug but it was fixed a few months ago
by commit 12b393486c70 ("iio: core: Clean up device correctly on
viio_trigger_alloc() failure").

It's unfortunate that that commit didn't have a Fixes tag.

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-11 10:36 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-11  8:04 [PATCH] iio: trigger: Fix refcount leak in viio_trigger_alloc() error path Guangshuo Li
2026-04-11  8:21 ` Dan Carpenter
2026-04-11  9:30   ` Guangshuo Li
2026-04-11 10:36     ` Dan Carpenter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox