aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJesper Juhl <jj@chaosbits.net>2012-01-23 16:28:44 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-24 06:34:19 -0500
commitc83f1d7e71625801c72f4013291194e09b6f0a6e (patch)
tree1bf7303f85769c1a60e95d697ed7a7ab02c44b0d /sound
parent7edf1a4f27f44588d69cbde955651990090eb25d (diff)
ASoC: wm2000: Fix use-after-free - don't release_firmware() twice on error
In wm2000_i2c_probe(), if we take the true branch in " ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0); if (ret != 0) goto err_fw; " then we'll release_firmware(fw) at the 'err_fw' label. But we've already done that just a few lines above. That's a use-after-free bug. This patch restructures the code so that we always call release_firmware(fw) before leaving the function, but only ever call it once. This means that we have to initialize 'fw' to NULL since some paths may now end up calling it without having called request_firmware(), but since request_firmware() deals gracefully with NULL pointers, we are fine if we just NULL initialize it. Signed-off-by: Jesper Juhl <jj@chaosbits.net> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm2000.c31
1 files changed, 13 insertions, 18 deletions
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index c2880907fced..a75c3766aede 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -733,8 +733,9 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
733 struct wm2000_priv *wm2000; 733 struct wm2000_priv *wm2000;
734 struct wm2000_platform_data *pdata; 734 struct wm2000_platform_data *pdata;
735 const char *filename; 735 const char *filename;
736 const struct firmware *fw; 736 const struct firmware *fw = NULL;
737 int reg, ret; 737 int ret;
738 int reg;
738 u16 id; 739 u16 id;
739 740
740 wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv), 741 wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv),
@@ -751,7 +752,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
751 ret = PTR_ERR(wm2000->regmap); 752 ret = PTR_ERR(wm2000->regmap);
752 dev_err(&i2c->dev, "Failed to allocate register map: %d\n", 753 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
753 ret); 754 ret);
754 goto err; 755 goto out;
755 } 756 }
756 757
757 /* Verify that this is a WM2000 */ 758 /* Verify that this is a WM2000 */
@@ -763,7 +764,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
763 if (id != 0x2000) { 764 if (id != 0x2000) {
764 dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id); 765 dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
765 ret = -ENODEV; 766 ret = -ENODEV;
766 goto err_regmap; 767 goto out_regmap_exit;
767 } 768 }
768 769
769 reg = wm2000_read(i2c, WM2000_REG_REVISON); 770 reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -782,7 +783,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
782 ret = request_firmware(&fw, filename, &i2c->dev); 783 ret = request_firmware(&fw, filename, &i2c->dev);
783 if (ret != 0) { 784 if (ret != 0) {
784 dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret); 785 dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
785 goto err_regmap; 786 goto out_regmap_exit;
786 } 787 }
787 788
788 /* Pre-cook the concatenation of the register address onto the image */ 789 /* Pre-cook the concatenation of the register address onto the image */
@@ -793,15 +794,13 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
793 if (wm2000->anc_download == NULL) { 794 if (wm2000->anc_download == NULL) {
794 dev_err(&i2c->dev, "Out of memory\n"); 795 dev_err(&i2c->dev, "Out of memory\n");
795 ret = -ENOMEM; 796 ret = -ENOMEM;
796 goto err_fw; 797 goto out_regmap_exit;
797 } 798 }
798 799
799 wm2000->anc_download[0] = 0x80; 800 wm2000->anc_download[0] = 0x80;
800 wm2000->anc_download[1] = 0x00; 801 wm2000->anc_download[1] = 0x00;
801 memcpy(wm2000->anc_download + 2, fw->data, fw->size); 802 memcpy(wm2000->anc_download + 2, fw->data, fw->size);
802 803
803 release_firmware(fw);
804
805 wm2000->anc_eng_ena = 1; 804 wm2000->anc_eng_ena = 1;
806 wm2000->anc_active = 1; 805 wm2000->anc_active = 1;
807 wm2000->spk_ena = 1; 806 wm2000->spk_ena = 1;
@@ -809,18 +808,14 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
809 808
810 wm2000_reset(wm2000); 809 wm2000_reset(wm2000);
811 810
812 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, 811 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
813 NULL, 0); 812 if (!ret)
814 if (ret != 0) 813 goto out;
815 goto err_fw;
816 814
817 return 0; 815out_regmap_exit:
818
819err_fw:
820 release_firmware(fw);
821err_regmap:
822 regmap_exit(wm2000->regmap); 816 regmap_exit(wm2000->regmap);
823err: 817out:
818 release_firmware(fw);
824 return ret; 819 return ret;
825} 820}
826 821