ALSA: ASoC: Fix double free and memory leak in many codec drivers
authorJean Delvare <khali@linux-fr.org>
Mon, 25 Aug 2008 10:49:20 +0000 (11:49 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 25 Aug 2008 11:49:52 +0000 (13:49 +0200)
Many SoC audio codec drivers have improper freeing of memory in error
paths.

* codec is allocated in the platform device probe function, but is not
  freed there in case of error. Instead it is freed in the i2c device
  probe function's error path. However the success or failure of both
  functions is not linked, so this could result in a double free (if
  the platform device is successfully probed, the i2c device probing
  fails and then the platform driver is unregistered.)

* codec->private_data is allocated in many platform device probe
  functions but not freed in their error paths.

This patch hopefully solves all these problems.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/soc/codecs/ak4535.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8990.c

index b26003c4f3e850ba1559a9e158b1dca609fbda67..7da9f467b7b83f06d4fdf02a44e05ba4ff530b97 100644 (file)
@@ -562,10 +562,9 @@ static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -583,7 +582,6 @@ static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -660,6 +658,11 @@ static int ak4535_probe(struct platform_device *pdev)
 #else
        /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
index b1dce5f459db6d40663112ecb2e3f8eb13bb30a9..5f9abb199435b35e82d99d7603e11f2338556080 100644 (file)
@@ -1199,10 +1199,9 @@ static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -1221,7 +1220,6 @@ static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -1302,6 +1300,11 @@ static int aic3x_probe(struct platform_device *pdev)
 #else
        /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
index a52d6d9e007adf718fd25ac951c9eb55e1251cec..807318fbdc8f182a96df656f3918770887a65e31 100644 (file)
@@ -729,10 +729,9 @@ static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -750,7 +749,6 @@ static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -817,6 +815,9 @@ static int uda1380_probe(struct platform_device *pdev)
 #else
        /* Add other interfaces here */
 #endif
+
+       if (ret != 0)
+               kfree(codec);
        return ret;
 }
 
index 67325fd954472f51563b5803b799b69a119eca37..3d998e6a997e5270838a4532c425e154fb8f2bd6 100644 (file)
@@ -693,10 +693,9 @@ static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -714,7 +713,6 @@ static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -782,6 +780,9 @@ static int wm8510_probe(struct platform_device *pdev)
 #else
        /* Add other interfaces here */
 #endif
+
+       if (ret != 0)
+               kfree(codec);
        return ret;
 }
 
index 369d39c3f745d9d441ff23d253afaa51dc36aefb..9402fcaf04fa50b0c1c71bf2f3026e3aa0985ec8 100644 (file)
@@ -596,10 +596,9 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -617,7 +616,6 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -693,6 +691,11 @@ static int wm8731_probe(struct platform_device *pdev)
 #else
        /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
index c6a8edf302ad58d44a4e9a9dd8bebb8b1b1ba777..dd1f55404b29d073a2eb5a74beb3a468882a8bd8 100644 (file)
@@ -869,10 +869,9 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -890,7 +889,6 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -966,6 +964,10 @@ static int wm8750_probe(struct platform_device *pdev)
                /* Add other interfaces here */
 #endif
 
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
index 8604809f0c362b75ee150ae0292663683baebf6f..35bf1c369870ccc79f1d43636b35a740434db5a8 100644 (file)
@@ -1661,10 +1661,9 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (!i2c) {
-               kfree(codec);
+       if (!i2c)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -1683,7 +1682,6 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -1760,6 +1758,11 @@ static int wm8753_probe(struct platform_device *pdev)
 #else
                /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }
 
index e44153fa38de2543ea0b912f2bdc6564ab0593af..dd995ef448b44452dcab76cdb2f3aa0f48a1b55c 100644 (file)
@@ -1500,10 +1500,9 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        client_template.addr = addr;
 
        i2c =  kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
-       if (i2c == NULL) {
-               kfree(codec);
+       if (i2c == NULL)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(i2c, codec);
        codec->control_data = i2c;
 
@@ -1521,7 +1520,6 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind)
        return ret;
 
 err:
-       kfree(codec);
        kfree(i2c);
        return ret;
 }
@@ -1595,6 +1593,11 @@ static int wm8990_probe(struct platform_device *pdev)
 #else
                /* Add other interfaces here */
 #endif
+
+       if (ret != 0) {
+               kfree(codec->private_data);
+               kfree(codec);
+       }
        return ret;
 }