There are a number of error paths in the probe function that do not call
of_node_put() to decrement the np device node refcount, leading to
memory leaks if those errors occur.
In order to ease backporting, the fix has been divided into two patches:
the first one simply adds the missing calls to of_node_put(), and the
second one adds the __free() macro to the existing device nodes to
remove the need for of_node_put(), ensuring that the same bug will not
arise in the future.
The issue was found by chance while analyzing the code, and I do not
have the hardware to test it beyond compiling and static analysis tools.
Although the issue is clear and the fix too, if someone wants to
volunteer to test the series with real hardware, it would be great.
Signed-off-by: Javier Carrasco <[email protected]>
---
Javier Carrasco (2):
cpufreq: qcom-nvmem: fix memory leaks in probe error paths
cpufreq: qcom-nvmem: eliminate uses of of_node_put()
drivers/cpufreq/qcom-cpufreq-nvmem.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
---
base-commit: 3689b0ef08b70e4e03b82ebd37730a03a672853a
change-id: 20240523-qcom-cpufreq-nvmem_memleak-6b6821db52b1
Best regards,
--
Javier Carrasco <[email protected]>
The code refactoring added new error paths between the np device node
allocation and the call to of_node_put(), which leads to memory leaks if
any of those errors occur.
Add the missing of_node_put() in the error paths that require it.
Cc: [email protected]
Fixes: 57f2f8b4aa0c ("cpufreq: qcom: Refactor the driver to make it easier to extend")
Signed-off-by: Javier Carrasco <[email protected]>
---
drivers/cpufreq/qcom-cpufreq-nvmem.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c
index ea05d9d67490..5004e1dbc752 100644
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -480,23 +480,30 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()),
GFP_KERNEL);
- if (!drv)
+ if (!drv) {
+ of_node_put(np);
return -ENOMEM;
+ }
match = pdev->dev.platform_data;
drv->data = match->data;
- if (!drv->data)
+ if (!drv->data) {
+ of_node_put(np);
return -ENODEV;
+ }
if (drv->data->get_version) {
speedbin_nvmem = of_nvmem_cell_get(np, NULL);
- if (IS_ERR(speedbin_nvmem))
+ if (IS_ERR(speedbin_nvmem)) {
+ of_node_put(np);
return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
"Could not get nvmem cell\n");
+ }
ret = drv->data->get_version(cpu_dev,
speedbin_nvmem, &pvs_name, drv);
if (ret) {
+ of_node_put(np);
nvmem_cell_put(speedbin_nvmem);
return ret;
}
--
2.40.1
Make use of the __free() macro to automate memory deallocation when
the existing device nodes get out of scope, removing the need for
of_node_put() and therefore increasing code safety if more error paths
are added to the driver, which could miss the required of_node_put()
as it already occurred with commit '57f2f8b4aa0c ("cpufreq: qcom:
Refactor the driver to make it easier to extend")'.
Signed-off-by: Javier Carrasco <[email protected]>
---
drivers/cpufreq/qcom-cpufreq-nvmem.c | 25 +++++++------------------
1 file changed, 7 insertions(+), 18 deletions(-)
diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c
index 5004e1dbc752..716066423b92 100644
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -455,7 +455,6 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
{
struct qcom_cpufreq_drv *drv;
struct nvmem_cell *speedbin_nvmem;
- struct device_node *np;
struct device *cpu_dev;
char pvs_name_buffer[] = "speedXX-pvsXX-vXX";
char *pvs_name = pvs_name_buffer;
@@ -467,49 +466,40 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
if (!cpu_dev)
return -ENODEV;
- np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
+ struct device_node *np __free(device_node) =
+ dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!np)
return -ENOENT;
ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu") ||
of_device_is_compatible(np, "operating-points-v2-krait-cpu");
- if (!ret) {
- of_node_put(np);
+ if (!ret)
return -ENOENT;
- }
drv = devm_kzalloc(&pdev->dev, struct_size(drv, cpus, num_possible_cpus()),
GFP_KERNEL);
- if (!drv) {
- of_node_put(np);
+ if (!drv)
return -ENOMEM;
- }
match = pdev->dev.platform_data;
drv->data = match->data;
- if (!drv->data) {
- of_node_put(np);
+ if (!drv->data)
return -ENODEV;
- }
if (drv->data->get_version) {
speedbin_nvmem = of_nvmem_cell_get(np, NULL);
- if (IS_ERR(speedbin_nvmem)) {
- of_node_put(np);
+ if (IS_ERR(speedbin_nvmem))
return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
"Could not get nvmem cell\n");
- }
ret = drv->data->get_version(cpu_dev,
speedbin_nvmem, &pvs_name, drv);
if (ret) {
- of_node_put(np);
nvmem_cell_put(speedbin_nvmem);
return ret;
}
nvmem_cell_put(speedbin_nvmem);
}
- of_node_put(np);
for_each_possible_cpu(cpu) {
struct device **virt_devs = NULL;
@@ -645,7 +635,7 @@ MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list);
*/
static int __init qcom_cpufreq_init(void)
{
- struct device_node *np = of_find_node_by_path("/");
+ struct device_node *np __free(device_node) = of_find_node_by_path("/");
const struct of_device_id *match;
int ret;
@@ -653,7 +643,6 @@ static int __init qcom_cpufreq_init(void)
return -ENODEV;
match = of_match_node(qcom_cpufreq_match_list, np);
- of_node_put(np);
if (!match)
return -ENODEV;
--
2.40.1
On 23-05-24, 23:24, Javier Carrasco wrote:
> There are a number of error paths in the probe function that do not call
> of_node_put() to decrement the np device node refcount, leading to
> memory leaks if those errors occur.
>
> In order to ease backporting, the fix has been divided into two patches:
> the first one simply adds the missing calls to of_node_put(), and the
> second one adds the __free() macro to the existing device nodes to
> remove the need for of_node_put(), ensuring that the same bug will not
> arise in the future.
>
> The issue was found by chance while analyzing the code, and I do not
> have the hardware to test it beyond compiling and static analysis tools.
> Although the issue is clear and the fix too, if someone wants to
> volunteer to test the series with real hardware, it would be great.
>
> Signed-off-by: Javier Carrasco <[email protected]>
> ---
> Javier Carrasco (2):
> cpufreq: qcom-nvmem: fix memory leaks in probe error paths
> cpufreq: qcom-nvmem: eliminate uses of of_node_put()
Applied. Thanks.
--
viresh