[PATCH] spi: fix controller reference leak in acpi_spi_device_alloc()
From: Wentao Liang
Date: Thu Sep 17 2026 - 12:01:33 EST
acpi_spi_add_resource() stores the controller returned by
acpi_spi_find_controller_by_adev() in lookup->ctlr. That lookup takes a
reference via class_find_device(), which acpi_spi_device_alloc() never
releases, leaking it on the error paths and on the success path too,
where spi_alloc_device() takes its own reference. Drop the lookup
reference when the caller did not pass a controller.
Fixes: 87e59b36e5e2 ("spi: Support selection of the index of the ACPI Spi Resource before alloc")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/spi/spi.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 104279858f56..fb5e17d55801 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2979,9 +2979,12 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
acpi_spi_add_resource, &lookup);
acpi_dev_free_resource_list(&resource_list);
- if (ret < 0)
+ if (ret < 0) {
/* Found SPI in _CRS but it points to another controller */
+ if (!ctlr)
+ spi_controller_put(lookup.ctlr);
return ERR_PTR(ret);
+ }
if (!lookup.max_speed_hz &&
ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) &&
@@ -2990,13 +2993,18 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
acpi_spi_parse_apple_properties(adev, &lookup);
}
- if (!lookup.max_speed_hz)
+ if (!lookup.max_speed_hz) {
+ if (!ctlr)
+ spi_controller_put(lookup.ctlr);
return ERR_PTR(-ENODEV);
+ }
spi = spi_alloc_device(lookup.ctlr);
if (!spi) {
dev_err(&lookup.ctlr->dev, "failed to allocate SPI device for %s\n",
dev_name(&adev->dev));
+ if (!ctlr)
+ spi_controller_put(lookup.ctlr);
return ERR_PTR(-ENOMEM);
}
@@ -3013,6 +3021,14 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
*/
spi->cs_index_mask = BIT(0);
+ /*
+ * If the controller was looked up from the ACPI resource, release the
+ * reference taken by acpi_spi_find_controller_by_adev(). The new SPI
+ * device holds the reference taken by spi_alloc_device() instead.
+ */
+ if (!ctlr)
+ spi_controller_put(lookup.ctlr);
+
return spi;
}
EXPORT_SYMBOL_GPL(acpi_spi_device_alloc);
--
2.34.1