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>
This commit is contained in:
committed by
John W. Linville
parent
8c28293f55
commit
c2f2d3a06f
@@ -166,18 +166,23 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||||||
struct p54_common *priv = dev->priv;
|
struct p54_common *priv = dev->priv;
|
||||||
struct eeprom_pda_wrap *wrap = NULL;
|
struct eeprom_pda_wrap *wrap = NULL;
|
||||||
struct pda_entry *entry;
|
struct pda_entry *entry;
|
||||||
int i = 0;
|
|
||||||
unsigned int data_len, entry_len;
|
unsigned int data_len, entry_len;
|
||||||
void *tmp;
|
void *tmp;
|
||||||
int err;
|
int err;
|
||||||
|
u8 *end = (u8 *)eeprom + len;
|
||||||
|
|
||||||
wrap = (struct eeprom_pda_wrap *) eeprom;
|
wrap = (struct eeprom_pda_wrap *) eeprom;
|
||||||
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
entry = (void *)wrap->data + le16_to_cpu(wrap->len);
|
||||||
i += 2;
|
|
||||||
i += le16_to_cpu(entry->len)*2;
|
/* verify that at least the entry length/code fits */
|
||||||
while (i < len) {
|
while ((u8 *)entry <= end - sizeof(*entry)) {
|
||||||
entry_len = le16_to_cpu(entry->len);
|
entry_len = le16_to_cpu(entry->len);
|
||||||
data_len = ((entry_len - 1) << 1);
|
data_len = ((entry_len - 1) << 1);
|
||||||
|
|
||||||
|
/* abort if entry exceeds whole structure */
|
||||||
|
if ((u8 *)entry + sizeof(*entry) + data_len > end)
|
||||||
|
break;
|
||||||
|
|
||||||
switch (le16_to_cpu(entry->code)) {
|
switch (le16_to_cpu(entry->code)) {
|
||||||
case PDR_MAC_ADDRESS:
|
case PDR_MAC_ADDRESS:
|
||||||
SET_IEEE80211_PERM_ADDR(dev, entry->data);
|
SET_IEEE80211_PERM_ADDR(dev, entry->data);
|
||||||
@@ -249,13 +254,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||||||
priv->version = *(u8 *)(entry->data + 1);
|
priv->version = *(u8 *)(entry->data + 1);
|
||||||
break;
|
break;
|
||||||
case PDR_END:
|
case PDR_END:
|
||||||
i = len;
|
/* make it overrun */
|
||||||
|
entry_len = len;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = (void *)entry + (entry_len + 1)*2;
|
entry = (void *)entry + (entry_len + 1)*2;
|
||||||
i += 2;
|
|
||||||
i += entry_len*2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
|
if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
|
||||||
|
Reference in New Issue
Block a user