diff mbox

Libertas: Association request to the driver failed

Message ID 4A7EAED8.9090900@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Roel Kluin Aug. 9, 2009, 11:11 a.m. UTC
Several arrays were read before checking whether the index was within
bounds. ARRAY_SIZE() should be used to determine the size of arrays.

rates->rates has an arraysize of 1, so calling get_common_rates()
with a rates_size of MAX_RATES (14) was causing reads out of bounds.

tmp_size can increment at most to *rates_size * ARRAY_SIZE(lbs_bg_rates),
so that should be the number of elements of tmp[].

A goto can be eliminated: ret was already set upon its declaration.

---
>>>> The change came in after -rc5,
>>>> and I found 57921c31 ("libertas: Read buffer overflow") to be the
>>>> culprit. Reverting it brings my libertas device back to life. I copied
>>>> the author.
>>>>
>>>> Thanks,
>>>> Daniel
>>> Ah, I think I made an error, I think tmp is too small and should be
>>>
>>> u8 tmp[*rates_size * ARRAY_SIZE(lbs_bg_rates) - 1];
>> After some sleep I realized it should be:
>>
>> u8 tmp[*rates_size * ARRAY_SIZE(lbs_bg_rates)];
> 
> I'll test that tomorrow. Would be easier if you send in a new patch I
> can ack directly in case it works :)

This is the patch that should be applied after the revert, or do you want a
delta patch?

And does this give your libertas back?

Thanks for testing,

Roel

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Michael Buesch Aug. 9, 2009, 11:10 a.m. UTC | #1
On Sunday 09 August 2009 13:11:20 Roel Kluin wrote:
> @@ -43,21 +44,21 @@ static int get_common_rates(struct lbs_private *priv,
>  	u16 *rates_size)
>  {
>  	u8 *card_rates = lbs_bg_rates;
> -	size_t num_card_rates = sizeof(lbs_bg_rates);
>  	int ret = 0, i, j;
> -	u8 tmp[30];
> +	u8 tmp[*rates_size * ARRAY_SIZE(lbs_bg_rates)];

Is it a good idea to use dynamic stack arrays in the kernel?
What about kmalloc for dynamic allocations?
Cyrill Gorcunov Aug. 9, 2009, 7:13 p.m. UTC | #2
[Michael Buesch - Sun, Aug 09, 2009 at 01:10:56PM +0200]
| On Sunday 09 August 2009 13:11:20 Roel Kluin wrote:
| > @@ -43,21 +44,21 @@ static int get_common_rates(struct lbs_private *priv,
| >  	u16 *rates_size)
| >  {
| >  	u8 *card_rates = lbs_bg_rates;
| > -	size_t num_card_rates = sizeof(lbs_bg_rates);
| >  	int ret = 0, i, j;
| > -	u8 tmp[30];
| > +	u8 tmp[*rates_size * ARRAY_SIZE(lbs_bg_rates)];
| 
| Is it a good idea to use dynamic stack arrays in the kernel?
| What about kmalloc for dynamic allocations?
| 
| -- 
| Greetings, Michael.

I saw one pattern in trace code (not sure if it's
still there) but personally don't like dynamic
stack arrays (though at moment the max value
being passed into routine is known maybe just
use MAX_RATES instead of (*rates_size)?). Hmm?

	-- Cyrill
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
John W. Linville Aug. 10, 2009, 5:59 p.m. UTC | #3
On Sun, Aug 09, 2009 at 01:11:20PM +0200, Roel Kluin wrote:
> > I'll test that tomorrow. Would be easier if you send in a new patch I
> > can ack directly in case it works :)
> 
> This is the patch that should be applied after the revert, or do you want a
> delta patch?

Delta patch, please...
diff mbox

Patch

diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b3741..e9efc4c 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,7 @@ 
 /* Copyright (C) 2006, Red Hat, Inc. */
 
 #include <linux/types.h>
+#include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <linux/ieee80211.h>
 #include <linux/if_arp.h>
@@ -43,21 +44,21 @@  static int get_common_rates(struct lbs_private *priv,
 	u16 *rates_size)
 {
 	u8 *card_rates = lbs_bg_rates;
-	size_t num_card_rates = sizeof(lbs_bg_rates);
 	int ret = 0, i, j;
-	u8 tmp[30];
+	u8 tmp[*rates_size * ARRAY_SIZE(lbs_bg_rates)];
 	size_t tmp_size = 0;
 
 	/* For each rate in card_rates that exists in rate1, copy to tmp */
-	for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
-		for (j = 0; rates[j] && (j < *rates_size); j++) {
+	for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
+		for (j = 0; j < *rates_size && rates[j]; j++) {
 			if (rates[j] == card_rates[i])
 				tmp[tmp_size++] = card_rates[i];
 		}
 	}
 
 	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
-	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
+	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates,
+			ARRAY_SIZE(lbs_bg_rates));
 	lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
 	lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
 
@@ -69,10 +70,7 @@  static int get_common_rates(struct lbs_private *priv,
 		lbs_pr_alert("Previously set fixed data rate %#x isn't "
 		       "compatible with the network.\n", priv->cur_rate);
 		ret = -1;
-		goto done;
 	}
-	ret = 0;
-
 done:
 	memset(rates, 0, *rates_size);
 	*rates_size = min_t(int, tmp_size, *rates_size);
@@ -322,7 +320,7 @@  static int lbs_associate(struct lbs_private *priv,
 	rates = (struct mrvl_ie_rates_param_set *) pos;
 	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
 	memcpy(&rates->rates, &bss->rates, MAX_RATES);
-	tmplen = MAX_RATES;
+	tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
 	if (get_common_rates(priv, rates->rates, &tmplen)) {
 		ret = -1;
 		goto done;
@@ -598,7 +596,7 @@  static int lbs_adhoc_join(struct lbs_private *priv,
 
 	/* Copy Data rates from the rates recorded in scan response */
 	memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
-	ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+	ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
 	memcpy(cmd.bss.rates, bss->rates, ratesize);
 	if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
 		lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");