ASoC: hdac_hdmi: Fix possible memory leak on parse and map nid failure
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>
Tue, 7 Nov 2017 10:46:26 +0000 (16:16 +0530)
committerMark Brown <broonie@kernel.org>
Wed, 8 Nov 2017 18:58:29 +0000 (18:58 +0000)
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 <subhransu.s.prusty@intel.com>
Signed-off-by: Guneshwor Singh <guneshwor.o.singh@intel.com>
Acked-By: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/hdac_hdmi.c

index 0c0aa618250223f910da7aba36ce2108aef77049..f3b4f4dfae6ad29cd9e7b34b38b54580ddea43b6 100644 (file)
@@ -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;
        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);
        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)
                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)
                        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;
 
                        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);
 
        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;
        }
 
        *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)
 }
 
 static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)