libertas: Read buffer overflow
PATCH 1/1 libertas: Read buffer overflow
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.
Since ratesize is at most MAX_RATES, tmp_size can increment at most to MAX_RATES * ARRAY_SIZE(lbs_bg_rates), so that should be the number of elements of tmp[].
---
Please review.
drivers/net/wireless/libertas/assoc.c +7 -6
@@ -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,14 +44,14 @@ 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); +size_t num_card_rates =ARRAY_SIZE (lbs_bg_rates);int ret =0 , i, j; -u8 tmp[30 ]; +u8 tmp[MAX_RATES *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 < num_card_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]; }
@@ -322,7 +323,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 +599,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.
");
drivers/net/wireless/libertas/assoc.c static int get_common_rates(struct lbs_private *priv, · line 47
Quoted 2 lines
drivers/net/wireless/libertas/assoc.c +1
-1-size_t num_card_rates =sizeof (lbs_bg_rates); +size_t num_card_rates =ARRAY_SIZE (lbs_bg_rates);
Hmm, not sure about this. First I don't know if we need a variable for this at all. Can't you simply use ARRAY_SIZE() whenever it's needed?
If you want to keep num_card_rates, you should change it's type. "size_t" is normally used to denote sizes in bytes, e.g. it's the type for the length of malloc and friends. But now the variable holds a number of elements and should be int or unsigned int.
Signature · 1 line
http://www.holgerschurig.de
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 (ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1), so that should be the number of elements of tmp[].
A goto can be eliminated: ret was already set upon its declaration.
---
Op 28-07-09 10:19, Holger Schurig schreef:
Quoted 6 lines
Review
Quoted 2 lines
(quoted diff) +1
-1- size_t num_card_rates = sizeof(lbs_bg_rates); + size_t num_card_rates = ARRAY_SIZE(lbs_bg_rates);Hmm, not sure about this. First I don't know if we need a variable for this at all. Can't you simply use
ARRAY_SIZE()whenever it's needed?
Of course. Please note the additional changes.
drivers/net/wireless/libertas/assoc.c +8 -10
@@ -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[(ARRAY_SIZE (lbs_bg_rates) -1 ) * (*rates_size -1 )];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" );