diff mbox series

pinctrl: core: fix possible memory leak in error path in pinctrl_enable()

Message ID 20240601113502.2709597-1-yangyingliang@huawei.com
State New
Headers show
Series pinctrl: core: fix possible memory leak in error path in pinctrl_enable() | expand

Commit Message

Yang Yingliang June 1, 2024, 11:35 a.m. UTC
In devm_pinctrl_register(), if pinctrl_enable() fails in pinctrl_register(),
the "pctldev" has not been added to dev resources, so devm_pinctrl_dev_release()
can not be called, it leads memory leak.

And some driver calls pinctrl_register_and_init() which is not devm_ managed,
it also leads memory leak if pinctrl_enable() fails.

To fix this, add a flag devm_allocated to struct pinctrl_dev, free the memory
by checking this flag.

Fixes: 5038a66dad01 ("pinctrl: core: delete incorrect free in pinctrl_enable()")
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
 drivers/pinctrl/core.c | 9 +++++++++
 drivers/pinctrl/core.h | 1 +
 2 files changed, 10 insertions(+)

Comments

Dan Carpenter June 1, 2024, 6:03 p.m. UTC | #1
On Sat, Jun 01, 2024 at 07:35:02PM +0800, Yang Yingliang wrote:
> In devm_pinctrl_register(), if pinctrl_enable() fails in pinctrl_register(),
> the "pctldev" has not been added to dev resources, so devm_pinctrl_dev_release()
> can not be called, it leads memory leak.
> 
> And some driver calls pinctrl_register_and_init() which is not devm_ managed,
> it also leads memory leak if pinctrl_enable() fails.
> 
> To fix this, add a flag devm_allocated to struct pinctrl_dev, free the memory
> by checking this flag.
> 
> Fixes: 5038a66dad01 ("pinctrl: core: delete incorrect free in pinctrl_enable()")
> Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
> ---
>  drivers/pinctrl/core.c | 9 +++++++++
>  drivers/pinctrl/core.h | 1 +
>  2 files changed, 10 insertions(+)
> 
> diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
> index cffeb869130d..374c36f5c759 100644
> --- a/drivers/pinctrl/core.c
> +++ b/drivers/pinctrl/core.c
> @@ -2125,6 +2125,13 @@ int pinctrl_enable(struct pinctrl_dev *pctldev)
>  	error = pinctrl_claim_hogs(pctldev);
>  	if (error) {
>  		dev_err(pctldev->dev, "could not claim hogs: %i\n", error);
> +		if (!pctldev->devm_allocated) {
> +			pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
> +					      pctldev->desc->npins);
> +			mutex_destroy(&pctldev->mutex);
> +			kfree(pctldev);
> +		}

The other thing is, this should be done in a function.

ti_iodelay_probe() would have to call uninit as well.  The error
handling in ti_iodelay_probe() was already messed up.  They probably
assumed that pinctrl_enable() would do the cleanup so they forgot to
call of_node_put(np).

regards,
dan carpenter

diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 9fcb9d913556..704541385397 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -2090,6 +2090,13 @@ pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
 	return ERR_PTR(ret);
 }
 
+void pinctrl_uninit_controller(struct pinctrl_dev *pctldev)
+{
+	pinctrl_free_pindescs(pctldev, pctldev->desc->pins, pctldev->desc->npins);
+	mutex_destroy(&pctldev->mutex);
+	kfree(pctldev);
+}
+
 static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
 {
 	pctldev->p = create_pinctrl(pctldev->dev, pctldev);
diff mbox series

Patch

diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index cffeb869130d..374c36f5c759 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -2125,6 +2125,13 @@  int pinctrl_enable(struct pinctrl_dev *pctldev)
 	error = pinctrl_claim_hogs(pctldev);
 	if (error) {
 		dev_err(pctldev->dev, "could not claim hogs: %i\n", error);
+		if (!pctldev->devm_allocated) {
+			pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
+					      pctldev->desc->npins);
+			mutex_destroy(&pctldev->mutex);
+			kfree(pctldev);
+		}
+
 		return error;
 	}
 
@@ -2283,6 +2290,7 @@  struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
 		return pctldev;
 	}
 
+	pctldev->devm_allocated = true;
 	*ptr = pctldev;
 	devres_add(dev, ptr);
 
@@ -2319,6 +2327,7 @@  int devm_pinctrl_register_and_init(struct device *dev,
 		return error;
 	}
 
+	(*pctldev)->devm_allocated = true;
 	*ptr = *pctldev;
 	devres_add(dev, ptr);
 
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 837fd5bd903d..bf57ce4fe927 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -72,6 +72,7 @@  struct pinctrl_dev {
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *device_root;
 #endif
+	bool devm_allocated;
 };
 
 /**