diff options
author | Jean Delvare <khali@linux-fr.org> | 2008-08-25 06:49:20 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-08-25 07:49:52 -0400 |
commit | 3051e41ab7daaa59d4564f20b25dcb8c03f35f2b (patch) | |
tree | 0908f13da020b0e6e5d025caa60b1fed4c056abc /sound/soc/codecs | |
parent | c5d44423d55e3abca7b1d544af9e4c97ec203999 (diff) |
ALSA: ASoC: Fix double free and memory leak in many codec drivers
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>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/ak4535.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/uda1380.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8510.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8731.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/wm8750.c | 10 | ||||
-rw-r--r-- | sound/soc/codecs/wm8753.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 11 |
8 files changed, 51 insertions, 32 deletions
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index b26003c4f3e8..7da9f467b7b8 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -562,10 +562,9 @@ static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
562 | client_template.addr = addr; | 562 | client_template.addr = addr; |
563 | 563 | ||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
565 | if (i2c == NULL) { | 565 | if (i2c == NULL) |
566 | kfree(codec); | ||
567 | return -ENOMEM; | 566 | return -ENOMEM; |
568 | } | 567 | |
569 | i2c_set_clientdata(i2c, codec); | 568 | i2c_set_clientdata(i2c, codec); |
570 | codec->control_data = i2c; | 569 | codec->control_data = i2c; |
571 | 570 | ||
@@ -583,7 +582,6 @@ static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
583 | return ret; | 582 | return ret; |
584 | 583 | ||
585 | err: | 584 | err: |
586 | kfree(codec); | ||
587 | kfree(i2c); | 585 | kfree(i2c); |
588 | return ret; | 586 | return ret; |
589 | } | 587 | } |
@@ -660,6 +658,11 @@ static int ak4535_probe(struct platform_device *pdev) | |||
660 | #else | 658 | #else |
661 | /* Add other interfaces here */ | 659 | /* Add other interfaces here */ |
662 | #endif | 660 | #endif |
661 | |||
662 | if (ret != 0) { | ||
663 | kfree(codec->private_data); | ||
664 | kfree(codec); | ||
665 | } | ||
663 | return ret; | 666 | return ret; |
664 | } | 667 | } |
665 | 668 | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b1dce5f459db..5f9abb199435 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -1199,10 +1199,9 @@ static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1199 | client_template.addr = addr; | 1199 | client_template.addr = addr; |
1200 | 1200 | ||
1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1202 | if (i2c == NULL) { | 1202 | if (i2c == NULL) |
1203 | kfree(codec); | ||
1204 | return -ENOMEM; | 1203 | return -ENOMEM; |
1205 | } | 1204 | |
1206 | i2c_set_clientdata(i2c, codec); | 1205 | i2c_set_clientdata(i2c, codec); |
1207 | codec->control_data = i2c; | 1206 | codec->control_data = i2c; |
1208 | 1207 | ||
@@ -1221,7 +1220,6 @@ static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1221 | return ret; | 1220 | return ret; |
1222 | 1221 | ||
1223 | err: | 1222 | err: |
1224 | kfree(codec); | ||
1225 | kfree(i2c); | 1223 | kfree(i2c); |
1226 | return ret; | 1224 | return ret; |
1227 | } | 1225 | } |
@@ -1302,6 +1300,11 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1302 | #else | 1300 | #else |
1303 | /* Add other interfaces here */ | 1301 | /* Add other interfaces here */ |
1304 | #endif | 1302 | #endif |
1303 | |||
1304 | if (ret != 0) { | ||
1305 | kfree(codec->private_data); | ||
1306 | kfree(codec); | ||
1307 | } | ||
1305 | return ret; | 1308 | return ret; |
1306 | } | 1309 | } |
1307 | 1310 | ||
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a52d6d9e007a..807318fbdc8f 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -729,10 +729,9 @@ static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
729 | client_template.addr = addr; | 729 | client_template.addr = addr; |
730 | 730 | ||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
732 | if (i2c == NULL) { | 732 | if (i2c == NULL) |
733 | kfree(codec); | ||
734 | return -ENOMEM; | 733 | return -ENOMEM; |
735 | } | 734 | |
736 | i2c_set_clientdata(i2c, codec); | 735 | i2c_set_clientdata(i2c, codec); |
737 | codec->control_data = i2c; | 736 | codec->control_data = i2c; |
738 | 737 | ||
@@ -750,7 +749,6 @@ static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
750 | return ret; | 749 | return ret; |
751 | 750 | ||
752 | err: | 751 | err: |
753 | kfree(codec); | ||
754 | kfree(i2c); | 752 | kfree(i2c); |
755 | return ret; | 753 | return ret; |
756 | } | 754 | } |
@@ -817,6 +815,9 @@ static int uda1380_probe(struct platform_device *pdev) | |||
817 | #else | 815 | #else |
818 | /* Add other interfaces here */ | 816 | /* Add other interfaces here */ |
819 | #endif | 817 | #endif |
818 | |||
819 | if (ret != 0) | ||
820 | kfree(codec); | ||
820 | return ret; | 821 | return ret; |
821 | } | 822 | } |
822 | 823 | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 67325fd95447..3d998e6a997e 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -693,10 +693,9 @@ static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
693 | client_template.addr = addr; | 693 | client_template.addr = addr; |
694 | 694 | ||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
696 | if (i2c == NULL) { | 696 | if (i2c == NULL) |
697 | kfree(codec); | ||
698 | return -ENOMEM; | 697 | return -ENOMEM; |
699 | } | 698 | |
700 | i2c_set_clientdata(i2c, codec); | 699 | i2c_set_clientdata(i2c, codec); |
701 | codec->control_data = i2c; | 700 | codec->control_data = i2c; |
702 | 701 | ||
@@ -714,7 +713,6 @@ static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
714 | return ret; | 713 | return ret; |
715 | 714 | ||
716 | err: | 715 | err: |
717 | kfree(codec); | ||
718 | kfree(i2c); | 716 | kfree(i2c); |
719 | return ret; | 717 | return ret; |
720 | } | 718 | } |
@@ -782,6 +780,9 @@ static int wm8510_probe(struct platform_device *pdev) | |||
782 | #else | 780 | #else |
783 | /* Add other interfaces here */ | 781 | /* Add other interfaces here */ |
784 | #endif | 782 | #endif |
783 | |||
784 | if (ret != 0) | ||
785 | kfree(codec); | ||
785 | return ret; | 786 | return ret; |
786 | } | 787 | } |
787 | 788 | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 369d39c3f745..9402fcaf04fa 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -596,10 +596,9 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
596 | client_template.addr = addr; | 596 | client_template.addr = addr; |
597 | 597 | ||
598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
599 | if (i2c == NULL) { | 599 | if (i2c == NULL) |
600 | kfree(codec); | ||
601 | return -ENOMEM; | 600 | return -ENOMEM; |
602 | } | 601 | |
603 | i2c_set_clientdata(i2c, codec); | 602 | i2c_set_clientdata(i2c, codec); |
604 | codec->control_data = i2c; | 603 | codec->control_data = i2c; |
605 | 604 | ||
@@ -617,7 +616,6 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
617 | return ret; | 616 | return ret; |
618 | 617 | ||
619 | err: | 618 | err: |
620 | kfree(codec); | ||
621 | kfree(i2c); | 619 | kfree(i2c); |
622 | return ret; | 620 | return ret; |
623 | } | 621 | } |
@@ -693,6 +691,11 @@ static int wm8731_probe(struct platform_device *pdev) | |||
693 | #else | 691 | #else |
694 | /* Add other interfaces here */ | 692 | /* Add other interfaces here */ |
695 | #endif | 693 | #endif |
694 | |||
695 | if (ret != 0) { | ||
696 | kfree(codec->private_data); | ||
697 | kfree(codec); | ||
698 | } | ||
696 | return ret; | 699 | return ret; |
697 | } | 700 | } |
698 | 701 | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index c6a8edf302ad..dd1f55404b29 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -869,10 +869,9 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
869 | client_template.addr = addr; | 869 | client_template.addr = addr; |
870 | 870 | ||
871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
872 | if (i2c == NULL) { | 872 | if (i2c == NULL) |
873 | kfree(codec); | ||
874 | return -ENOMEM; | 873 | return -ENOMEM; |
875 | } | 874 | |
876 | i2c_set_clientdata(i2c, codec); | 875 | i2c_set_clientdata(i2c, codec); |
877 | codec->control_data = i2c; | 876 | codec->control_data = i2c; |
878 | 877 | ||
@@ -890,7 +889,6 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
890 | return ret; | 889 | return ret; |
891 | 890 | ||
892 | err: | 891 | err: |
893 | kfree(codec); | ||
894 | kfree(i2c); | 892 | kfree(i2c); |
895 | return ret; | 893 | return ret; |
896 | } | 894 | } |
@@ -966,6 +964,10 @@ static int wm8750_probe(struct platform_device *pdev) | |||
966 | /* Add other interfaces here */ | 964 | /* Add other interfaces here */ |
967 | #endif | 965 | #endif |
968 | 966 | ||
967 | if (ret != 0) { | ||
968 | kfree(codec->private_data); | ||
969 | kfree(codec); | ||
970 | } | ||
969 | return ret; | 971 | return ret; |
970 | } | 972 | } |
971 | 973 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 8604809f0c36..35bf1c369870 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1661,10 +1661,9 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1661 | client_template.addr = addr; | 1661 | client_template.addr = addr; |
1662 | 1662 | ||
1663 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1663 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1664 | if (!i2c) { | 1664 | if (!i2c) |
1665 | kfree(codec); | ||
1666 | return -ENOMEM; | 1665 | return -ENOMEM; |
1667 | } | 1666 | |
1668 | i2c_set_clientdata(i2c, codec); | 1667 | i2c_set_clientdata(i2c, codec); |
1669 | codec->control_data = i2c; | 1668 | codec->control_data = i2c; |
1670 | 1669 | ||
@@ -1683,7 +1682,6 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1683 | return ret; | 1682 | return ret; |
1684 | 1683 | ||
1685 | err: | 1684 | err: |
1686 | kfree(codec); | ||
1687 | kfree(i2c); | 1685 | kfree(i2c); |
1688 | return ret; | 1686 | return ret; |
1689 | } | 1687 | } |
@@ -1760,6 +1758,11 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1760 | #else | 1758 | #else |
1761 | /* Add other interfaces here */ | 1759 | /* Add other interfaces here */ |
1762 | #endif | 1760 | #endif |
1761 | |||
1762 | if (ret != 0) { | ||
1763 | kfree(codec->private_data); | ||
1764 | kfree(codec); | ||
1765 | } | ||
1763 | return ret; | 1766 | return ret; |
1764 | } | 1767 | } |
1765 | 1768 | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index e44153fa38de..dd995ef448b4 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1500,10 +1500,9 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1500 | client_template.addr = addr; | 1500 | client_template.addr = addr; |
1501 | 1501 | ||
1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1503 | if (i2c == NULL) { | 1503 | if (i2c == NULL) |
1504 | kfree(codec); | ||
1505 | return -ENOMEM; | 1504 | return -ENOMEM; |
1506 | } | 1505 | |
1507 | i2c_set_clientdata(i2c, codec); | 1506 | i2c_set_clientdata(i2c, codec); |
1508 | codec->control_data = i2c; | 1507 | codec->control_data = i2c; |
1509 | 1508 | ||
@@ -1521,7 +1520,6 @@ static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1521 | return ret; | 1520 | return ret; |
1522 | 1521 | ||
1523 | err: | 1522 | err: |
1524 | kfree(codec); | ||
1525 | kfree(i2c); | 1523 | kfree(i2c); |
1526 | return ret; | 1524 | return ret; |
1527 | } | 1525 | } |
@@ -1595,6 +1593,11 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1595 | #else | 1593 | #else |
1596 | /* Add other interfaces here */ | 1594 | /* Add other interfaces here */ |
1597 | #endif | 1595 | #endif |
1596 | |||
1597 | if (ret != 0) { | ||
1598 | kfree(codec->private_data); | ||
1599 | kfree(codec); | ||
1600 | } | ||
1598 | return ret; | 1601 | return ret; |
1599 | } | 1602 | } |
1600 | 1603 | ||