Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 137

kernel-2.6.18-238.el5.src.rpm

From: Jaroslav Kysela <jkysela@redhat.com>
Date: Thu, 28 Aug 2008 09:02:00 -0400
Subject: [alsa] asoc: double free and mem leak in i2c codec
Message-id: 200808281302.m7SD205x031440@ns3.rdu.redhat.com
O-Subject: [RHEL 5.3 PATCH] alsa: asoc: fix double free and memory leak in i2c codec drivers
Bugzilla: 460103
RH-Acked-by: Larry Woodman <lwoodman@redhat.com>
RH-Acked-by: John Feeney <jfeeney@redhat.com>
RH-Acked-by: Eugene Teo <eteo@redhat.com>

Resolves: BZ#460103

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.

The patch is backport from upstream:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3051e41ab7daaa59d4564f20b25dcb8c03f35f2b

diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 7ca0b52..c37d764 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -624,10 +624,8 @@ 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;
 
@@ -645,7 +643,6 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 	return ret;
 
 err:
-	kfree(codec);
 	kfree(i2c);
 	return ret;
 }
@@ -721,6 +718,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;
 }
 
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 7073e8e..af62704 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -896,10 +896,8 @@ 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;
 
@@ -917,7 +915,6 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind)
 	return ret;
 
 err:
-	kfree(codec);
 	kfree(i2c);
 	return ret;
 }
@@ -993,6 +990,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;
 }