Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: davinci-evm: Fix reference leak in davinci_evm_probe

The davinci_evm_probe() function calls of_parse_phandle() to acquire
device nodes for "ti,audio-codec" and "ti,mcasp-controller". These
functions return device nodes with incremented reference counts.

However, in several error paths (e.g., when the second of_parse_phandle(),
snd_soc_of_parse_card_name(), or devm_snd_soc_register_card() fails),
the function returns directly without releasing the acquired nodes,
leading to reference leaks.

This patch adds an error handling path 'err_put' to properly release
the device nodes using of_node_put() and clean up the pointers when
an error occurs.

Signed-off-by: Kery Qi <qikeyu2017@gmail.com>
Link: https://patch.msgid.link/20260107154836.1521-2-qikeyu2017@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Kery Qi and committed by
Mark Brown
5b577d21 2fa0eaf7

+31 -8
+31 -8
sound/soc/ti/davinci-evm.c
··· 194 194 return -EINVAL; 195 195 196 196 dai->cpus->of_node = of_parse_phandle(np, "ti,mcasp-controller", 0); 197 - if (!dai->cpus->of_node) 198 - return -EINVAL; 197 + if (!dai->cpus->of_node) { 198 + ret = -EINVAL; 199 + goto err_put; 200 + } 199 201 200 202 dai->platforms->of_node = dai->cpus->of_node; 201 203 202 204 evm_soc_card.dev = &pdev->dev; 203 205 ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model"); 204 206 if (ret) 205 - return ret; 207 + goto err_put; 206 208 207 209 mclk = devm_clk_get(&pdev->dev, "mclk"); 208 210 if (PTR_ERR(mclk) == -EPROBE_DEFER) { 209 - return -EPROBE_DEFER; 211 + ret = -EPROBE_DEFER; 212 + goto err_put; 210 213 } else if (IS_ERR(mclk)) { 211 214 dev_dbg(&pdev->dev, "mclk not found.\n"); 212 215 mclk = NULL; 213 216 } 214 217 215 218 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); 216 - if (!drvdata) 217 - return -ENOMEM; 219 + if (!drvdata) { 220 + ret = -ENOMEM; 221 + goto err_put; 222 + } 218 223 219 224 drvdata->mclk = mclk; 220 225 ··· 229 224 if (!drvdata->mclk) { 230 225 dev_err(&pdev->dev, 231 226 "No clock or clock rate defined.\n"); 232 - return -EINVAL; 227 + ret = -EINVAL; 228 + goto err_put; 233 229 } 234 230 drvdata->sysclk = clk_get_rate(drvdata->mclk); 235 231 } else if (drvdata->mclk) { ··· 246 240 snd_soc_card_set_drvdata(&evm_soc_card, drvdata); 247 241 ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); 248 242 249 - if (ret) 243 + if (ret) { 250 244 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); 245 + goto err_put; 246 + } 247 + 248 + return ret; 249 + 250 + err_put: 251 + dai->platforms->of_node = NULL; 252 + 253 + if (dai->cpus->of_node) { 254 + of_node_put(dai->cpus->of_node); 255 + dai->cpus->of_node = NULL; 256 + } 257 + 258 + if (dai->codecs->of_node) { 259 + of_node_put(dai->codecs->of_node); 260 + dai->codecs->of_node = NULL; 261 + } 251 262 252 263 return ret; 253 264 }