Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Michael Buesch and committed by
John W. Linville
869aaab1 f9f7b960

+30 -19
+26 -17
drivers/net/wireless/bcm43xx/bcm43xx_main.c
··· 939 939 return 0; 940 940 } 941 941 942 - static void bcm43xx_geo_init(struct bcm43xx_private *bcm) 942 + static int bcm43xx_geo_init(struct bcm43xx_private *bcm) 943 943 { 944 - struct ieee80211_geo geo; 944 + struct ieee80211_geo *geo; 945 945 struct ieee80211_channel *chan; 946 946 int have_a = 0, have_bg = 0; 947 947 int i; ··· 949 949 struct bcm43xx_phyinfo *phy; 950 950 const char *iso_country; 951 951 952 - memset(&geo, 0, sizeof(geo)); 952 + geo = kzalloc(sizeof(*geo), GFP_KERNEL); 953 + if (!geo) 954 + return -ENOMEM; 955 + 953 956 for (i = 0; i < bcm->nr_80211_available; i++) { 954 957 phy = &(bcm->core_80211_ext[i].phy); 955 958 switch (phy->type) { ··· 970 967 iso_country = bcm43xx_locale_iso(bcm->sprom.locale); 971 968 972 969 if (have_a) { 973 - for (i = 0, channel = 0; channel < 201; channel++) { 974 - chan = &geo.a[i++]; 970 + for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL; 971 + channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) { 972 + chan = &geo->a[i++]; 975 973 chan->freq = bcm43xx_channel_to_freq_a(channel); 976 974 chan->channel = channel; 977 975 } 978 - geo.a_channels = i; 976 + geo->a_channels = i; 979 977 } 980 978 if (have_bg) { 981 - for (i = 0, channel = 1; channel < 15; channel++) { 982 - chan = &geo.bg[i++]; 979 + for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL; 980 + channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) { 981 + chan = &geo->bg[i++]; 983 982 chan->freq = bcm43xx_channel_to_freq_bg(channel); 984 983 chan->channel = channel; 985 984 } 986 - geo.bg_channels = i; 985 + geo->bg_channels = i; 987 986 } 988 - memcpy(geo.name, iso_country, 2); 987 + memcpy(geo->name, iso_country, 2); 989 988 if (0 /*TODO: Outdoor use only */) 990 - geo.name[2] = 'O'; 989 + geo->name[2] = 'O'; 991 990 else if (0 /*TODO: Indoor use only */) 992 - geo.name[2] = 'I'; 991 + geo->name[2] = 'I'; 993 992 else 994 - geo.name[2] = ' '; 995 - geo.name[3] = '\0'; 993 + geo->name[2] = ' '; 994 + geo->name[3] = '\0'; 996 995 997 - ieee80211_set_geo(bcm->ieee, &geo); 996 + ieee80211_set_geo(bcm->ieee, geo); 997 + kfree(geo); 998 + 999 + return 0; 998 1000 } 999 1001 1000 1002 /* DummyTransmission function, as documented on ··· 3487 3479 goto err_80211_unwind; 3488 3480 bcm43xx_wireless_core_disable(bcm); 3489 3481 } 3482 + err = bcm43xx_geo_init(bcm); 3483 + if (err) 3484 + goto err_80211_unwind; 3490 3485 bcm43xx_pctl_set_crystal(bcm, 0); 3491 3486 3492 3487 /* Set the MAC address in the networking subsystem */ ··· 3497 3486 memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); 3498 3487 else 3499 3488 memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); 3500 - 3501 - bcm43xx_geo_init(bcm); 3502 3489 3503 3490 snprintf(bcm->nick, IW_ESSID_MAX_SIZE, 3504 3491 "Broadcom %04X", bcm->chip_id);
+4 -2
drivers/net/wireless/bcm43xx/bcm43xx_main.h
··· 118 118 static inline 119 119 int bcm43xx_is_valid_channel_a(u8 channel) 120 120 { 121 - return (channel <= 200); 121 + return (channel >= IEEE80211_52GHZ_MIN_CHANNEL 122 + && channel <= IEEE80211_52GHZ_MAX_CHANNEL); 122 123 } 123 124 static inline 124 125 int bcm43xx_is_valid_channel_bg(u8 channel) 125 126 { 126 - return (channel >= 1 && channel <= 14); 127 + return (channel >= IEEE80211_24GHZ_MIN_CHANNEL 128 + && channel <= IEEE80211_24GHZ_MAX_CHANNEL); 127 129 } 128 130 static inline 129 131 int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,