aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-29 17:28:25 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-04 18:36:36 -0500
commitc2f2d3a06f8b628d444cf4f396d6c6ddd47e1d1f (patch)
tree7879c02aa491f6e335dd907b1093941bfb892215
parent8c28293f5514f64ba064bac7946aebeda4a663c6 (diff)
p54: fix eeprom parser length sanity checks
When I called p54_parse_eeprom() on a hand-coded structure I managed to make a small mistake with wrap->len which caused a segfault a few lines down when trying to read entry->len. This patch changes the validation code to avoid such problems. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Tested-by: Florian Fainelli <florian.fainelli@telecomint.eu> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/p54common.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
index 56aabec73c20..d191e055a788 100644
--- a/drivers/net/wireless/p54common.c
+++ b/drivers/net/wireless/p54common.c
@@ -166,18 +166,23 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
166 struct p54_common *priv = dev->priv; 166 struct p54_common *priv = dev->priv;
167 struct eeprom_pda_wrap *wrap = NULL; 167 struct eeprom_pda_wrap *wrap = NULL;
168 struct pda_entry *entry; 168 struct pda_entry *entry;
169 int i = 0;
170 unsigned int data_len, entry_len; 169 unsigned int data_len, entry_len;
171 void *tmp; 170 void *tmp;
172 int err; 171 int err;
172 u8 *end = (u8 *)eeprom + len;
173 173
174 wrap = (struct eeprom_pda_wrap *) eeprom; 174 wrap = (struct eeprom_pda_wrap *) eeprom;
175 entry = (void *)wrap->data + le16_to_cpu(wrap->len); 175 entry = (void *)wrap->data + le16_to_cpu(wrap->len);
176 i += 2; 176
177 i += le16_to_cpu(entry->len)*2; 177 /* verify that at least the entry length/code fits */
178 while (i < len) { 178 while ((u8 *)entry <= end - sizeof(*entry)) {
179 entry_len = le16_to_cpu(entry->len); 179 entry_len = le16_to_cpu(entry->len);
180 data_len = ((entry_len - 1) << 1); 180 data_len = ((entry_len - 1) << 1);
181
182 /* abort if entry exceeds whole structure */
183 if ((u8 *)entry + sizeof(*entry) + data_len > end)
184 break;
185
181 switch (le16_to_cpu(entry->code)) { 186 switch (le16_to_cpu(entry->code)) {
182 case PDR_MAC_ADDRESS: 187 case PDR_MAC_ADDRESS:
183 SET_IEEE80211_PERM_ADDR(dev, entry->data); 188 SET_IEEE80211_PERM_ADDR(dev, entry->data);
@@ -249,13 +254,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
249 priv->version = *(u8 *)(entry->data + 1); 254 priv->version = *(u8 *)(entry->data + 1);
250 break; 255 break;
251 case PDR_END: 256 case PDR_END:
252 i = len; 257 /* make it overrun */
258 entry_len = len;
253 break; 259 break;
254 } 260 }
255 261
256 entry = (void *)entry + (entry_len + 1)*2; 262 entry = (void *)entry + (entry_len + 1)*2;
257 i += 2;
258 i += entry_len*2;
259 } 263 }
260 264
261 if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) { 265 if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {