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:
parent
625745c297
commit
d6ee858c3b
5 changed files with 64 additions and 65 deletions
|
@ -636,11 +636,11 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
|
|||
|
||||
end = ies + ies_len;
|
||||
|
||||
for (pos = ies; pos + 1 < end; pos += len) {
|
||||
for (pos = ies; end - pos > 1; pos += len) {
|
||||
id = *pos++;
|
||||
len = *pos++;
|
||||
|
||||
if (pos + len > end)
|
||||
if (len > end - pos)
|
||||
break;
|
||||
|
||||
if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
|
||||
|
|
|
@ -38,7 +38,7 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
|
|||
{
|
||||
const u8 *pos, *end;
|
||||
struct p2p_channels *ch;
|
||||
size_t channels;
|
||||
u8 channels;
|
||||
struct p2p_channels intersection;
|
||||
|
||||
ch = &dev->channels;
|
||||
|
@ -58,14 +58,14 @@ int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
|
|||
}
|
||||
pos += 3;
|
||||
|
||||
while (pos + 2 < end) {
|
||||
while (end - pos > 2) {
|
||||
struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes];
|
||||
cl->reg_class = *pos++;
|
||||
if (pos + 1 + pos[0] > end) {
|
||||
channels = *pos++;
|
||||
if (channels > end - pos) {
|
||||
p2p_info(p2p, "Invalid peer Channel List");
|
||||
return -1;
|
||||
}
|
||||
channels = *pos++;
|
||||
cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ?
|
||||
P2P_MAX_REG_CLASS_CHANNELS : channels;
|
||||
os_memcpy(cl->channel, pos, cl->channels);
|
||||
|
|
|
@ -296,14 +296,14 @@ static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
|
|||
os_memset(zero_addr, 0, ETH_ALEN);
|
||||
pos = wpabuf_head_u8(m->wfd_ie);
|
||||
end = pos + wpabuf_len(m->wfd_ie);
|
||||
while (pos + 1 < end) {
|
||||
while (end - pos >= 3) {
|
||||
u8 id;
|
||||
u16 len;
|
||||
|
||||
id = *pos++;
|
||||
len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len > end)
|
||||
if (len > end - pos)
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
|
|
|
@ -19,7 +19,8 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
|
|||
struct p2p_message *msg)
|
||||
{
|
||||
const u8 *pos;
|
||||
size_t i, nlen;
|
||||
size_t i;
|
||||
u16 nlen;
|
||||
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||
|
||||
switch (id) {
|
||||
|
@ -149,10 +150,9 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
|
|||
pos += 2;
|
||||
nlen = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (data + len - pos < (int) nlen ||
|
||||
nlen > WPS_DEV_NAME_MAX_LEN) {
|
||||
if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) {
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
|
@ -637,49 +637,48 @@ int p2p_group_info_parse(const u8 *gi, size_t gi_len,
|
|||
gend = gi + gi_len;
|
||||
while (g < gend) {
|
||||
struct p2p_client_info *cli;
|
||||
const u8 *t, *cend;
|
||||
int count;
|
||||
const u8 *cend;
|
||||
u16 count;
|
||||
u8 len;
|
||||
|
||||
cli = &info->client[info->num_clients];
|
||||
cend = g + 1 + g[0];
|
||||
if (cend > gend)
|
||||
len = *g++;
|
||||
if (len > gend - g || len < 2 * ETH_ALEN + 1 + 2 + 8 + 1)
|
||||
return -1; /* invalid data */
|
||||
cend = g + len;
|
||||
/* g at start of P2P Client Info Descriptor */
|
||||
/* t at Device Capability Bitmap */
|
||||
t = g + 1 + 2 * ETH_ALEN;
|
||||
if (t > cend)
|
||||
return -1; /* invalid data */
|
||||
cli->p2p_device_addr = g + 1;
|
||||
cli->p2p_interface_addr = g + 1 + ETH_ALEN;
|
||||
cli->dev_capab = t[0];
|
||||
cli->p2p_device_addr = g;
|
||||
g += ETH_ALEN;
|
||||
cli->p2p_interface_addr = g;
|
||||
g += ETH_ALEN;
|
||||
cli->dev_capab = *g++;
|
||||
|
||||
if (t + 1 + 2 + 8 + 1 > cend)
|
||||
return -1; /* invalid data */
|
||||
cli->config_methods = WPA_GET_BE16(g);
|
||||
g += 2;
|
||||
cli->pri_dev_type = g;
|
||||
g += 8;
|
||||
|
||||
cli->config_methods = WPA_GET_BE16(&t[1]);
|
||||
cli->pri_dev_type = &t[3];
|
||||
|
||||
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)
|
||||
/* g at Number of Secondary Device Types */
|
||||
len = *g++;
|
||||
if (8 * len > cend - g)
|
||||
return -1; /* invalid data */
|
||||
cli->sec_dev_types = t;
|
||||
t += 8 * cli->num_sec_dev_types;
|
||||
cli->num_sec_dev_types = len;
|
||||
cli->sec_dev_types = g;
|
||||
g += 8 * len;
|
||||
|
||||
/* t at Device Name in WPS TLV format */
|
||||
if (t + 2 + 2 > cend)
|
||||
/* g at Device Name in WPS TLV format */
|
||||
if (cend - g < 2 + 2)
|
||||
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 */
|
||||
t += 2;
|
||||
count = WPA_GET_BE16(t);
|
||||
t += 2;
|
||||
if (count > cend - t)
|
||||
g += 2;
|
||||
count = WPA_GET_BE16(g);
|
||||
g += 2;
|
||||
if (count > cend - g)
|
||||
return -1; /* invalid Device Name TLV */
|
||||
if (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;
|
||||
|
||||
g = cend;
|
||||
|
|
|
@ -28,11 +28,11 @@ static int wfd_wsd_supported(struct wpabuf *wfd)
|
|||
pos = wpabuf_head(wfd);
|
||||
end = pos + wpabuf_len(wfd);
|
||||
|
||||
while (pos + 3 <= end) {
|
||||
while (end - pos >= 3) {
|
||||
subelem = *pos++;
|
||||
len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
if (pos + len > end)
|
||||
if (len > end - pos)
|
||||
break;
|
||||
|
||||
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++;
|
||||
|
||||
slen = *pos++;
|
||||
next = pos + slen;
|
||||
if (next > end || slen < 2) {
|
||||
if (slen > end - pos || slen < 2) {
|
||||
p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
|
||||
return;
|
||||
}
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
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;
|
||||
/* Query Request */
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return;
|
||||
slen = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + slen > end)
|
||||
if (slen > end - pos)
|
||||
return;
|
||||
end = pos + slen;
|
||||
|
||||
/* ANQP Query Request */
|
||||
if (pos + 4 > end)
|
||||
if (end - pos < 4)
|
||||
return;
|
||||
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
|
||||
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);
|
||||
pos += 2;
|
||||
if (pos + slen > end || slen < 3 + 1) {
|
||||
if (slen > end - pos || slen < 3 + 1) {
|
||||
p2p_dbg(p2p, "Invalid ANQP Query Request length");
|
||||
return;
|
||||
}
|
||||
|
@ -401,7 +401,7 @@ void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
|
|||
}
|
||||
pos += 4;
|
||||
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return;
|
||||
update_indic = WPA_GET_LE16(pos);
|
||||
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++;
|
||||
|
||||
slen = *pos++;
|
||||
next = pos + slen;
|
||||
if (next > end || slen < 2) {
|
||||
if (slen > end - pos || slen < 2) {
|
||||
p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
|
||||
return;
|
||||
}
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
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;
|
||||
/* Query Response */
|
||||
if (pos + 2 > end) {
|
||||
if (end - pos < 2) {
|
||||
p2p_dbg(p2p, "Too short Query Response");
|
||||
return;
|
||||
}
|
||||
slen = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
p2p_dbg(p2p, "Query Response Length: %d", slen);
|
||||
if (pos + slen > end) {
|
||||
if (slen > end - pos) {
|
||||
p2p_dbg(p2p, "Not enough Query Response data");
|
||||
return;
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
}
|
||||
|
||||
/* ANQP Query Response */
|
||||
if (pos + 4 > end)
|
||||
if (end - pos < 4)
|
||||
return;
|
||||
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
|
||||
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);
|
||||
pos += 2;
|
||||
if (pos + slen > end || slen < 3 + 1) {
|
||||
if (slen > end - pos || slen < 3 + 1) {
|
||||
p2p_dbg(p2p, "Invalid ANQP Query Response length");
|
||||
return;
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
}
|
||||
pos += 4;
|
||||
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return;
|
||||
update_indic = WPA_GET_LE16(pos);
|
||||
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++;
|
||||
|
||||
slen = *pos++;
|
||||
next = pos + slen;
|
||||
if (next > end || slen < 2) {
|
||||
if (slen > end - pos || slen < 2) {
|
||||
p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
|
||||
return;
|
||||
}
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
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;
|
||||
/* Query Response */
|
||||
if (pos + 2 > end) {
|
||||
if (end - pos < 2) {
|
||||
p2p_dbg(p2p, "Too short Query Response");
|
||||
return;
|
||||
}
|
||||
slen = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
p2p_dbg(p2p, "Query Response Length: %d", slen);
|
||||
if (pos + slen > end) {
|
||||
if (slen > end - pos) {
|
||||
p2p_dbg(p2p, "Not enough Query Response data");
|
||||
return;
|
||||
}
|
||||
|
@ -768,7 +768,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
}
|
||||
|
||||
/* ANQP Query Response */
|
||||
if (pos + 4 > end)
|
||||
if (end - pos < 4)
|
||||
return;
|
||||
if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
if (pos + 4 > end)
|
||||
if (end - pos < 4)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return;
|
||||
p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
|
||||
p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
|
||||
|
|
Loading…
Reference in a new issue