Interworking: 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:37:38 +03:00
parent 3991cb7b3c
commit 67fea55ca2

View file

@ -362,13 +362,13 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
u8 elen, auth_count, a; u8 elen, auth_count, a;
const u8 *e_end; const u8 *e_end;
if (pos + 3 > end) { if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields"); wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
return NULL; return NULL;
} }
elen = *pos++; elen = *pos++;
if (pos + elen > end || elen < 2) { if (elen > end - pos || elen < 2) {
wpa_printf(MSG_DEBUG, "No room for EAP Method subfield"); wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
return NULL; return NULL;
} }
@ -381,14 +381,19 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
for (a = 0; a < auth_count; a++) { for (a = 0; a < auth_count; a++) {
u8 id, len; u8 id, len;
if (pos + 2 > end || pos + 2 + pos[1] > end) { if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "No room for Authentication " wpa_printf(MSG_DEBUG,
"Parameter subfield"); "No room for Authentication Parameter subfield header");
return NULL; return NULL;
} }
id = *pos++; id = *pos++;
len = *pos++; len = *pos++;
if (len > end - pos) {
wpa_printf(MSG_DEBUG,
"No room for Authentication Parameter subfield");
return NULL;
}
switch (id) { switch (id) {
case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH: case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
@ -463,7 +468,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */ len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
pos += 2; pos += 2;
if (pos + len > end || len < 3) { if (len > end - pos || len < 3) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm Data " wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
"(len=%u; left=%u)", "(len=%u; left=%u)",
len, (unsigned int) (end - pos)); len, (unsigned int) (end - pos));
@ -473,7 +478,7 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
r->encoding = *pos++; r->encoding = *pos++;
realm_len = *pos++; realm_len = *pos++;
if (pos + realm_len > f_end) { if (realm_len > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for NAI Realm " wpa_printf(MSG_DEBUG, "No room for NAI Realm "
"(len=%u; left=%u)", "(len=%u; left=%u)",
realm_len, (unsigned int) (f_end - pos)); realm_len, (unsigned int) (f_end - pos));
@ -485,13 +490,13 @@ static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
return NULL; return NULL;
pos += realm_len; pos += realm_len;
if (pos + 1 > f_end) { if (f_end - pos < 1) {
wpa_printf(MSG_DEBUG, "No room for EAP Method Count"); wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
return NULL; return NULL;
} }
r->eap_count = *pos++; r->eap_count = *pos++;
wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count); wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
if (pos + r->eap_count * 3 > f_end) { if (r->eap_count * 3 > f_end - pos) {
wpa_printf(MSG_DEBUG, "No room for EAP Methods"); wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL; return NULL;
} }
@ -746,7 +751,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
return 0; return 0;
pos = wpabuf_head_u8(anqp); pos = wpabuf_head_u8(anqp);
end = pos + wpabuf_len(anqp); end = pos + wpabuf_len(anqp);
if (pos + 2 > end) if (end - pos < 2)
return 0; return 0;
if (*pos != 0) { if (*pos != 0) {
wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos); wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
@ -754,7 +759,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
} }
pos++; pos++;
udhl = *pos++; udhl = *pos++;
if (pos + udhl > end) { if (udhl > end - pos) {
wpa_printf(MSG_DEBUG, "Invalid UDHL"); wpa_printf(MSG_DEBUG, "Invalid UDHL");
return 0; return 0;
} }
@ -764,12 +769,12 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2], plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
imsi, mnc_len); imsi, mnc_len);
while (pos + 2 <= end) { while (end - pos >= 2) {
u8 iei, len; u8 iei, len;
const u8 *l_end; const u8 *l_end;
iei = *pos++; iei = *pos++;
len = *pos++ & 0x7f; len = *pos++ & 0x7f;
if (pos + len > end) if (len > end - pos)
break; break;
l_end = pos + len; l_end = pos + len;
@ -780,7 +785,7 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
pos, len); pos, len);
num = *pos++; num = *pos++;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (pos + 3 > l_end) if (l_end - pos < 3)
break; break;
if (os_memcmp(pos, plmn, 3) == 0 || if (os_memcmp(pos, plmn, 3) == 0 ||
os_memcmp(pos, plmn2, 3) == 0) os_memcmp(pos, plmn2, 3) == 0)
@ -1082,12 +1087,12 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
* OI #1, [OI #2], [OI #3] * OI #1, [OI #2], [OI #3]
*/ */
if (pos + 2 > end) if (end - pos < 2)
return 0; return 0;
pos++; /* skip Number of ANQP OIs */ pos++; /* skip Number of ANQP OIs */
lens = *pos++; lens = *pos++;
if (pos + (lens & 0x0f) + (lens >> 4) > end) if ((lens & 0x0f) + (lens >> 4) > end - pos)
return 0; return 0;
if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
@ -1121,7 +1126,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
/* Set of <OI Length, OI> duples */ /* Set of <OI Length, OI> duples */
while (pos < end) { while (pos < end) {
len = *pos++; len = *pos++;
if (pos + len > end) if (len > end - pos)
break; break;
if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
return 1; return 1;
@ -1266,7 +1271,7 @@ static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
static int has_proto_match(const u8 *pos, const u8 *end, u8 proto) static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
{ {
while (pos + 4 <= end) { while (end - pos >= 4) {
if (pos[0] == proto && pos[3] == 1 /* Open */) if (pos[0] == proto && pos[3] == 1 /* Open */)
return 1; return 1;
pos += 4; pos += 4;
@ -1279,7 +1284,7 @@ static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto, static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
u16 port) u16 port)
{ {
while (pos + 4 <= end) { while (end - pos >= 4) {
if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port && if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
pos[3] == 1 /* Open */) pos[3] == 1 /* Open */)
return 1; return 1;
@ -2133,23 +2138,27 @@ int domain_name_list_contains(struct wpabuf *domain_names,
pos = wpabuf_head(domain_names); pos = wpabuf_head(domain_names);
end = pos + wpabuf_len(domain_names); end = pos + wpabuf_len(domain_names);
while (pos + 1 < end) { while (end - pos > 1) {
if (pos + 1 + pos[0] > end) u8 elen;
elen = *pos++;
if (elen > end - pos)
break; break;
wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name", wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
pos + 1, pos[0]); pos, elen);
if (pos[0] == len && if (elen == len &&
os_strncasecmp(domain, (const char *) (pos + 1), len) == 0) os_strncasecmp(domain, (const char *) pos, len) == 0)
return 1; return 1;
if (!exact_match && pos[0] > len && pos[pos[0] - len] == '.') { if (!exact_match && elen > len && pos[elen - len - 1] == '.') {
const char *ap = (const char *) (pos + 1); const char *ap = (const char *) pos;
int offset = pos[0] - len; int offset = elen - len;
if (os_strncasecmp(domain, ap + offset, len) == 0) if (os_strncasecmp(domain, ap + offset, len) == 0)
return 1; return 1;
} }
pos += 1 + pos[0]; pos += elen;
} }
return 0; return 0;