P2P: Avoid undefined behavior in pointer arithmetic

Reorder terms in a way that no invalid pointers are generated with
pos+len operations. end-pos is always defined (with a valid pos pointer)
while pos+len could end up pointing beyond the end pointer which would
be undefined behavior.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-10-18 01:45:22 +03:00
parent 625745c297
commit d6ee858c3b
5 changed files with 64 additions and 65 deletions

View file

@ -636,11 +636,11 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
end = ies + ies_len; end = ies + ies_len;
for (pos = ies; pos + 1 < end; pos += len) { for (pos = ies; end - pos > 1; pos += len) {
id = *pos++; id = *pos++;
len = *pos++; len = *pos++;
if (pos + len > end) if (len > end - pos)
break; break;
if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3) if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)

View file

@ -38,7 +38,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
{ {
const u8 *pos, *end; const u8 *pos, *end;
struct p2p_channels *ch; struct p2p_channels *ch;
size_t channels; u8 channels;
struct p2p_channels intersection; struct p2p_channels intersection;
ch = &dev->channels; ch = &dev->channels;
@ -58,14 +58,14 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
} }
pos += 3; pos += 3;
while (pos + 2 < end) { while (end - pos > 2) {
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes]; struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
cl->reg_class = *pos++; cl->reg_class = *pos++;
if (pos + 1 + pos[0] > end) { channels = *pos++;
if (channels > end - pos) {
p2p_info(p2p, "Invalid peer Channel List"); p2p_info(p2p, "Invalid peer Channel List");
return -1; return -1;
} }
channels = *pos++;
cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ? cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
P2P_MAX_REG_CLASS_CHANNELS : channels; P2P_MAX_REG_CLASS_CHANNELS : channels;
os_memcpy(cl->channel, pos, cl->channels); os_memcpy(cl->channel, pos, cl->channels);

View file

@ -296,14 +296,14 @@ static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
os_memset(zero_addr, 0, ETH_ALEN); os_memset(zero_addr, 0, ETH_ALEN);
pos = wpabuf_head_u8(m->wfd_ie); pos = wpabuf_head_u8(m->wfd_ie);
end = pos + wpabuf_len(m->wfd_ie); end = pos + wpabuf_len(m->wfd_ie);
while (pos + 1 < end) { while (end - pos >= 3) {
u8 id; u8 id;
u16 len; u16 len;
id = *pos++; id = *pos++;
len = WPA_GET_BE16(pos); len = WPA_GET_BE16(pos);
pos += 2; pos += 2;
if (pos + len > end) if (len > end - pos)
break; break;
switch (id) { switch (id) {

View file

@ -19,7 +19,8 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
struct p2p_message *msg) struct p2p_message *msg)
{ {
const u8 *pos; const u8 *pos;
size_t i, nlen; size_t i;
u16 nlen;
char devtype[WPS_DEV_TYPE_BUFSIZE]; char devtype[WPS_DEV_TYPE_BUFSIZE];
switch (id) { switch (id) {
@ -149,10 +150,9 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
pos += 2; pos += 2;
nlen = WPA_GET_BE16(pos); nlen = WPA_GET_BE16(pos);
pos += 2; pos += 2;
if (data + len - pos < (int) nlen || if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
nlen > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name "
"length %d (buf len %d)", (int) nlen, "length %u (buf len %d)", nlen,
(int) (data + len - pos)); (int) (data + len - pos));
return -1; return -1;
} }
@ -637,49 +637,48 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
gend = gi + gi_len; gend = gi + gi_len;
while (g < gend) { while (g < gend) {
struct p2p_client_info *cli; struct p2p_client_info *cli;
const u8 *t, *cend; const u8 *cend;
int count; u16 count;
u8 len;
cli = &info->client[info->num_clients]; cli = &info->client[info->num_clients];
cend = g + 1 + g[0]; len = *g++;
if (cend > gend) if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
return -1; /* invalid data */ return -1; /* invalid data */
cend = g + len;
/* g at start of P2P Client Info Descriptor */ /* g at start of P2P Client Info Descriptor */
/* t at Device Capability Bitmap */ cli->p2p_device_addr = g;
t = g + 1 + 2 * ETH_ALEN; g += ETH_ALEN;
if (t > cend) cli->p2p_interface_addr = g;
return -1; /* invalid data */ g += ETH_ALEN;
cli->p2p_device_addr = g + 1; cli->dev_capab = *g++;
cli->p2p_interface_addr = g + 1 + ETH_ALEN;
cli->dev_capab = t[0];
if (t + 1 + 2 + 8 + 1 > cend) cli->config_methods = WPA_GET_BE16(g);
return -1; /* invalid data */ g += 2;
cli->pri_dev_type = g;
g += 8;
cli->config_methods = WPA_GET_BE16(&t[1]); /* g at Number of Secondary Device Types */
cli->pri_dev_type = &t[3]; len = *g++;
if (8 * len > cend - g)
t += 1 + 2 + 8;
/* t at Number of Secondary Device Types */
cli->num_sec_dev_types = *t++;
if (t + 8 * cli->num_sec_dev_types > cend)
return -1; /* invalid data */ return -1; /* invalid data */
cli->sec_dev_types = t; cli->num_sec_dev_types = len;
t += 8 * cli->num_sec_dev_types; cli->sec_dev_types = g;
g += 8 * len;
/* t at Device Name in WPS TLV format */ /* g at Device Name in WPS TLV format */
if (t + 2 + 2 > cend) if (cend - g < 2 + 2)
return -1; /* invalid data */ return -1; /* invalid data */
if (WPA_GET_BE16(t) != ATTR_DEV_NAME) if (WPA_GET_BE16(g) != ATTR_DEV_NAME)
return -1; /* invalid Device Name TLV */ return -1; /* invalid Device Name TLV */
t += 2; g += 2;
count = WPA_GET_BE16(t); count = WPA_GET_BE16(g);
t += 2; g += 2;
if (count > cend - t) if (count > cend - g)
return -1; /* invalid Device Name TLV */ return -1; /* invalid Device Name TLV */
if (count >= WPS_DEV_NAME_MAX_LEN) if (count >= WPS_DEV_NAME_MAX_LEN)
count = WPS_DEV_NAME_MAX_LEN; count = WPS_DEV_NAME_MAX_LEN;
cli->dev_name = (const char *) t; cli->dev_name = (const char *) g;
cli->dev_name_len = count; cli->dev_name_len = count;
g = cend; g = cend;

View file

@ -28,11 +28,11 @@ static int wfd_wsd_supported(struct wpabuf *wfd)
pos = wpabuf_head(wfd); pos = wpabuf_head(wfd);
end = pos + wpabuf_len(wfd); end = pos + wpabuf_len(wfd);
while (pos + 3 <= end) { while (end - pos >= 3) {
subelem = *pos++; subelem = *pos++;
len = WPA_GET_BE16(pos); len = WPA_GET_BE16(pos);
pos += 2; pos += 2;
if (pos + len > end) if (len > end - pos)
break; break;
if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) { if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
@ -355,11 +355,11 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos++; pos++;
slen = *pos++; slen = *pos++;
next = pos + slen; if (slen > end - pos || slen < 2) {
if (next > end || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Request"); p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
return; return;
} }
next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */ pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@ -370,16 +370,16 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
pos = next; pos = next;
/* Query Request */ /* Query Request */
if (pos + 2 > end) if (end - pos < 2)
return; return;
slen = WPA_GET_LE16(pos); slen = WPA_GET_LE16(pos);
pos += 2; pos += 2;
if (pos + slen > end) if (slen > end - pos)
return; return;
end = pos + slen; end = pos + slen;
/* ANQP Query Request */ /* ANQP Query Request */
if (pos + 4 > end) if (end - pos < 4)
return; return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@ -389,7 +389,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos); slen = WPA_GET_LE16(pos);
pos += 2; pos += 2;
if (pos + slen > end || slen < 3 + 1) { if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Request length"); p2p_dbg(p2p, "Invalid ANQP Query Request length");
return; return;
} }
@ -401,7 +401,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
} }
pos += 4; pos += 4;
if (pos + 2 > end) if (end - pos < 2)
return; return;
update_indic = WPA_GET_LE16(pos); update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@ -512,11 +512,11 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos++; pos++;
slen = *pos++; slen = *pos++;
next = pos + slen; if (slen > end - pos || slen < 2) {
if (next > end || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Initial Response"); p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
return; return;
} }
next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */ pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@ -527,14 +527,14 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
pos = next; pos = next;
/* Query Response */ /* Query Response */
if (pos + 2 > end) { if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response"); p2p_dbg(p2p, "Too short Query Response");
return; return;
} }
slen = WPA_GET_LE16(pos); slen = WPA_GET_LE16(pos);
pos += 2; pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen); p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) { if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data"); p2p_dbg(p2p, "Not enough Query Response data");
return; return;
} }
@ -552,7 +552,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
} }
/* ANQP Query Response */ /* ANQP Query Response */
if (pos + 4 > end) if (end - pos < 4)
return; return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@ -562,7 +562,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
slen = WPA_GET_LE16(pos); slen = WPA_GET_LE16(pos);
pos += 2; pos += 2;
if (pos + slen > end || slen < 3 + 1) { if (slen > end - pos || slen < 3 + 1) {
p2p_dbg(p2p, "Invalid ANQP Query Response length"); p2p_dbg(p2p, "Invalid ANQP Query Response length");
return; return;
} }
@ -574,7 +574,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
} }
pos += 4; pos += 4;
if (pos + 2 > end) if (end - pos < 2)
return; return;
update_indic = WPA_GET_LE16(pos); update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
@ -727,11 +727,11 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos++; pos++;
slen = *pos++; slen = *pos++;
next = pos + slen; if (slen > end - pos || slen < 2) {
if (next > end || slen < 2) {
p2p_dbg(p2p, "Invalid IE in GAS Comeback Response"); p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
return; return;
} }
next = pos + slen;
pos++; /* skip QueryRespLenLimit and PAME-BI */ pos++; /* skip QueryRespLenLimit and PAME-BI */
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@ -742,14 +742,14 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
pos = next; pos = next;
/* Query Response */ /* Query Response */
if (pos + 2 > end) { if (end - pos < 2) {
p2p_dbg(p2p, "Too short Query Response"); p2p_dbg(p2p, "Too short Query Response");
return; return;
} }
slen = WPA_GET_LE16(pos); slen = WPA_GET_LE16(pos);
pos += 2; pos += 2;
p2p_dbg(p2p, "Query Response Length: %d", slen); p2p_dbg(p2p, "Query Response Length: %d", slen);
if (pos + slen > end) { if (slen > end - pos) {
p2p_dbg(p2p, "Not enough Query Response data"); p2p_dbg(p2p, "Not enough Query Response data");
return; return;
} }
@ -768,7 +768,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
} }
/* ANQP Query Response */ /* ANQP Query Response */
if (pos + 4 > end) if (end - pos < 4)
return; return;
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
@ -783,7 +783,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Invalid ANQP Query Response length"); p2p_dbg(p2p, "Invalid ANQP Query Response length");
return; return;
} }
if (pos + 4 > end) if (end - pos < 4)
return; return;
if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
@ -793,7 +793,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
} }
pos += 4; pos += 4;
if (pos + 2 > end) if (end - pos < 2)
return; return;
p2p->sd_rx_update_indic = WPA_GET_LE16(pos); p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic); p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);