drivers/regulator/wm8400-regulator.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
When platform_device_register() fails in wm8400_register_regulator(),
the embedded struct device in wm8400->regulators[reg] has already been
initialized by device_initialize(), but the failure path returns the
error without dropping the device reference for the current platform
device:
wm8400_register_regulator()
-> platform_device_register(&wm8400->regulators[reg])
-> device_initialize(&wm8400->regulators[reg].dev)
-> setup_pdev_dma_masks(&wm8400->regulators[reg])
-> platform_device_add(&wm8400->regulators[reg])
This leads to a reference leak when platform_device_register() fails.
Fix this by calling platform_device_put() before returning the error.
The issue was identified by a static analysis tool I developed and
confirmed by manual review.
Fixes: 42fad570b6662 ("regulator: Add WM8400 regulator support")
Cc: stable@vger.kernel.org
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
drivers/regulator/wm8400-regulator.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index fb3ca7956d00..5849bb051d2a 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -243,6 +243,7 @@ int wm8400_register_regulator(struct device *dev, int reg,
struct regulator_init_data *initdata)
{
struct wm8400 *wm8400 = dev_get_drvdata(dev);
+ int ret;
if (wm8400->regulators[reg].name)
return -EBUSY;
@@ -254,7 +255,12 @@ int wm8400_register_regulator(struct device *dev, int reg,
wm8400->regulators[reg].dev.parent = dev;
wm8400->regulators[reg].dev.platform_data = initdata;
- return platform_device_register(&wm8400->regulators[reg]);
+ ret = platform_device_register(&wm8400->regulators[reg]);
+ if (ret)
+ platform_device_put(&wm8400->regulators[reg]);
+
+ return ret;
+
}
EXPORT_SYMBOL_GPL(wm8400_register_regulator);
--
2.43.0
On Thu, Apr 16, 2026 at 02:12:28AM +0800, Guangshuo Li wrote: > When platform_device_register() fails in wm8400_register_regulator(), > the embedded struct device in wm8400->regulators[reg] has already been > initialized by device_initialize(), but the failure path returns the > error without dropping the device reference for the current platform > device: > - return platform_device_register(&wm8400->regulators[reg]); > + ret = platform_device_register(&wm8400->regulators[reg]); > + if (ret) > + platform_device_put(&wm8400->regulators[reg]); Note that the device is embedded in wm8400 so we don't want to free it, and we don't have a release() callback anyway. The whole lifecycle is messed up here, the subdevices should probably be dynamically allocated.
Hi Mark, Thanks for the review and clarification. On Tue, 21 Apr 2026 at 01:38, Mark Brown <broonie@kernel.org> wrote: > > Note that the device is embedded in wm8400 so we don't want to free it, > and we don't have a release() callback anyway. The whole lifecycle is > messed up here, the subdevices should probably be dynamically allocated. You are right. The platform_device is embedded in struct wm8400 and does not have a release callback, so calling platform_device_put() on the platform_device_register() failure path is not appropriate here. Please disregard this patch. I will drop it. As you said, the lifecycle is more fundamentally wrong here and would need a different fix, such as using dynamically allocated subdevices, rather than adding platform_device_put() in this path. Sorry for the noise. Best regards, Guangshuo Li
© 2016 - 2026 Red Hat, Inc.