Jelajahi Sumber

[PATCH] bcm43xx: Fix array overrun in bcm43xx_geo_init

The problem here is that the bcm34xx driver and the ieee80211
stack do not agree on what channels are possible for 802.11a.
The ieee80211 stack only wants channels between 34 and 165, while
the bcm43xx driver accepts anything from 0 to 200. I made the
bcm43xx driver comply with the ieee80211 stack expectations, by
using the proper constants.

Signed-off-by: Jean Delvare <jdelvare@suse.de>

[mb]: Reduce stack usage by kzalloc-ing ieee80211_geo

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Michael Buesch 19 tahun lalu
induk
melakukan
869aaab181

+ 26 - 17
drivers/net/wireless/bcm43xx/bcm43xx_main.c

@@ -939,9 +939,9 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 	return 0;
 	return 0;
 }
 }
 
 
-static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
+static int bcm43xx_geo_init(struct bcm43xx_private *bcm)
 {
 {
-	struct ieee80211_geo geo;
+	struct ieee80211_geo *geo;
 	struct ieee80211_channel *chan;
 	struct ieee80211_channel *chan;
 	int have_a = 0, have_bg = 0;
 	int have_a = 0, have_bg = 0;
 	int i;
 	int i;
@@ -949,7 +949,10 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_phyinfo *phy;
 	struct bcm43xx_phyinfo *phy;
 	const char *iso_country;
 	const char *iso_country;
 
 
-	memset(&geo, 0, sizeof(geo));
+	geo = kzalloc(sizeof(*geo), GFP_KERNEL);
+	if (!geo)
+		return -ENOMEM;
+
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 		phy = &(bcm->core_80211_ext[i].phy);
 		phy = &(bcm->core_80211_ext[i].phy);
 		switch (phy->type) {
 		switch (phy->type) {
@@ -967,31 +970,36 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
 	iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
 	iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
 
 
  	if (have_a) {
  	if (have_a) {
-		for (i = 0, channel = 0; channel < 201; channel++) {
-			chan = &geo.a[i++];
+		for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL;
+		      channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) {
+			chan = &geo->a[i++];
 			chan->freq = bcm43xx_channel_to_freq_a(channel);
 			chan->freq = bcm43xx_channel_to_freq_a(channel);
 			chan->channel = channel;
 			chan->channel = channel;
 		}
 		}
-		geo.a_channels = i;
+		geo->a_channels = i;
 	}
 	}
 	if (have_bg) {
 	if (have_bg) {
-		for (i = 0, channel = 1; channel < 15; channel++) {
-			chan = &geo.bg[i++];
+		for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL;
+		      channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) {
+			chan = &geo->bg[i++];
 			chan->freq = bcm43xx_channel_to_freq_bg(channel);
 			chan->freq = bcm43xx_channel_to_freq_bg(channel);
 			chan->channel = channel;
 			chan->channel = channel;
 		}
 		}
-		geo.bg_channels = i;
+		geo->bg_channels = i;
 	}
 	}
-	memcpy(geo.name, iso_country, 2);
+	memcpy(geo->name, iso_country, 2);
 	if (0 /*TODO: Outdoor use only */)
 	if (0 /*TODO: Outdoor use only */)
-		geo.name[2] = 'O';
+		geo->name[2] = 'O';
 	else if (0 /*TODO: Indoor use only */)
 	else if (0 /*TODO: Indoor use only */)
-		geo.name[2] = 'I';
+		geo->name[2] = 'I';
 	else
 	else
-		geo.name[2] = ' ';
-	geo.name[3] = '\0';
+		geo->name[2] = ' ';
+	geo->name[3] = '\0';
+
+	ieee80211_set_geo(bcm->ieee, geo);
+	kfree(geo);
 
 
-	ieee80211_set_geo(bcm->ieee, &geo);
+	return 0;
 }
 }
 
 
 /* DummyTransmission function, as documented on 
 /* DummyTransmission function, as documented on 
@@ -3479,6 +3487,9 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
 			goto err_80211_unwind;
 			goto err_80211_unwind;
 		bcm43xx_wireless_core_disable(bcm);
 		bcm43xx_wireless_core_disable(bcm);
 	}
 	}
+	err = bcm43xx_geo_init(bcm);
+	if (err)
+		goto err_80211_unwind;
 	bcm43xx_pctl_set_crystal(bcm, 0);
 	bcm43xx_pctl_set_crystal(bcm, 0);
 
 
 	/* Set the MAC address in the networking subsystem */
 	/* Set the MAC address in the networking subsystem */
@@ -3487,8 +3498,6 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
 	else
 	else
 		memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
 		memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
 
 
-	bcm43xx_geo_init(bcm);
-
 	snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
 	snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
 		 "Broadcom %04X", bcm->chip_id);
 		 "Broadcom %04X", bcm->chip_id);
 
 

+ 4 - 2
drivers/net/wireless/bcm43xx/bcm43xx_main.h

@@ -118,12 +118,14 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
 static inline
 static inline
 int bcm43xx_is_valid_channel_a(u8 channel)
 int bcm43xx_is_valid_channel_a(u8 channel)
 {
 {
-	return (channel <= 200);
+	return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
+	       && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
 }
 }
 static inline
 static inline
 int bcm43xx_is_valid_channel_bg(u8 channel)
 int bcm43xx_is_valid_channel_bg(u8 channel)
 {
 {
-	return (channel >= 1 && channel <= 14);
+	return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
+	       && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
 }
 }
 static inline
 static inline
 int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
 int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,