Skip to content

Commit

Permalink
ALSA: ASoC: Fix double free and memory leak in many codec drivers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jean Delvare authored and Takashi Iwai committed Aug 25, 2008
1 parent c5d4442 commit 3051e41
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 32 deletions.
11 changes: 7 additions & 4 deletions sound/soc/codecs/ak4535.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 7 additions & 4 deletions sound/soc/codecs/tlv320aic3x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 5 additions & 4 deletions sound/soc/codecs/uda1380.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
9 changes: 5 additions & 4 deletions sound/soc/codecs/wm8510.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 7 additions & 4 deletions sound/soc/codecs/wm8731.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
10 changes: 6 additions & 4 deletions sound/soc/codecs/wm8750.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 7 additions & 4 deletions sound/soc/codecs/wm8753.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 7 additions & 4 deletions sound/soc/codecs/wm8990.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 3051e41

Please sign in to comment.