From 1c0a7de226660b0306b54aaf2cb52312e74723eb Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Tue, 7 Nov 2017 16:16:26 +0530 Subject: [PATCH] ASoC: hdac_hdmi: Fix possible memory leak on parse and map nid failure During failure, widgets in cvt_list and pin_list are not freed. So fix the possible memory leak by freeing them when failure occurs. Signed-off-by: Subhransu S. Prusty Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 0c0aa6182502..f3b4f4dfae6a 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1453,6 +1453,8 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, int i, num_nodes; struct hdac_device *hdac = &edev->hdac; struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_cvt *temp_cvt, *cvt_next; + struct hdac_hdmi_pin *temp_pin, *pin_next; int ret; hdac_hdmi_skl_enable_all_pins(hdac); @@ -1482,32 +1484,54 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, case AC_WID_AUD_OUT: ret = hdac_hdmi_add_cvt(edev, nid); if (ret < 0) - return ret; + goto free_widgets; break; case AC_WID_PIN: ret = hdac_hdmi_add_pin(edev, nid); if (ret < 0) - return ret; + goto free_widgets; break; } } hdac->end_nid = nid; - if (!hdmi->num_pin || !hdmi->num_cvt) - return -EIO; + if (!hdmi->num_pin || !hdmi->num_cvt) { + ret = -EIO; + goto free_widgets; + } ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); if (ret) { dev_err(&hdac->dev, "Failed to create dais with err: %d\n", ret); - return ret; + goto free_widgets; } *num_dais = hdmi->num_cvt; + ret = hdac_hdmi_init_dai_map(edev); + if (ret < 0) + goto free_widgets; - return hdac_hdmi_init_dai_map(edev); + return ret; + +free_widgets: + list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) { + list_del(&temp_cvt->head); + kfree(temp_cvt->name); + kfree(temp_cvt); + } + + list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) { + for (i = 0; i < temp_pin->num_ports; i++) + temp_pin->ports[i].pin = NULL; + kfree(temp_pin->ports); + list_del(&temp_pin->head); + kfree(temp_pin); + } + + return ret; } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)