mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-05 22:29:49 +00:00
added more out of range checks to dns_recv() (see bug #48924)
This commit is contained in:
parent
9078f31544
commit
23147b0e21
@ -601,11 +601,14 @@ dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addr
|
|||||||
static u16_t
|
static u16_t
|
||||||
dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
|
dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
|
||||||
{
|
{
|
||||||
unsigned char n;
|
int n;
|
||||||
u16_t response_offset = start_offset;
|
u16_t response_offset = start_offset;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
n = pbuf_get_at(p, response_offset++);
|
n = pbuf_try_get_at(p, response_offset++);
|
||||||
|
if (n < 0) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
/** @see RFC 1035 - 4.1.4. Message compression */
|
/** @see RFC 1035 - 4.1.4. Message compression */
|
||||||
if ((n & 0xc0) == 0xc0) {
|
if ((n & 0xc0) == 0xc0) {
|
||||||
/* Compressed name: cannot be equal since we don't send them */
|
/* Compressed name: cannot be equal since we don't send them */
|
||||||
@ -613,7 +616,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
|
|||||||
} else {
|
} else {
|
||||||
/* Not compressed name */
|
/* Not compressed name */
|
||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
if ((*query) != pbuf_get_at(p, response_offset)) {
|
int c = pbuf_try_get_at(p, response_offset);
|
||||||
|
if (c < 0) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
if ((*query) != (u8_t)c) {
|
||||||
return 0xFFFF;
|
return 0xFFFF;
|
||||||
}
|
}
|
||||||
++response_offset;
|
++response_offset;
|
||||||
@ -622,7 +629,11 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
|
|||||||
}
|
}
|
||||||
++query;
|
++query;
|
||||||
}
|
}
|
||||||
} while (pbuf_get_at(p, response_offset) != 0);
|
n = pbuf_try_get_at(p, response_offset);
|
||||||
|
if (n < 0) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
} while (n != 0);
|
||||||
|
|
||||||
return response_offset + 1;
|
return response_offset + 1;
|
||||||
}
|
}
|
||||||
@ -635,28 +646,34 @@ dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
|
|||||||
* @return index to end of the name
|
* @return index to end of the name
|
||||||
*/
|
*/
|
||||||
static u16_t
|
static u16_t
|
||||||
dns_parse_name(struct pbuf* p, u16_t query_idx)
|
dns_skip_name(struct pbuf* p, u16_t query_idx)
|
||||||
{
|
{
|
||||||
unsigned char n;
|
int n;
|
||||||
|
u16_t offset = query_idx;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* pbuf_get_at() returns 0 on out-of-bounds access, so we will terminate */
|
n = pbuf_try_get_at(p, offset++);
|
||||||
n = pbuf_get_at(p, query_idx++);
|
if (n < 0) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
/** @see RFC 1035 - 4.1.4. Message compression */
|
/** @see RFC 1035 - 4.1.4. Message compression */
|
||||||
if ((n & 0xc0) == 0xc0) {
|
if ((n & 0xc0) == 0xc0) {
|
||||||
/* Compressed name */
|
/* Compressed name: since we only want to skip it (not check it), stop here */
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
/* Not compressed name */
|
/* Not compressed name */
|
||||||
while (n > 0) {
|
if (offset + n >= p->tot_len) {
|
||||||
++query_idx;
|
return 0xFFFF;
|
||||||
--n;
|
|
||||||
}
|
}
|
||||||
|
offset = (u16_t)(offset + n);
|
||||||
}
|
}
|
||||||
/* pbuf_get_at() returns 0 on out-of-bounds access, so we will terminate */
|
n = pbuf_try_get_at(p, offset);
|
||||||
} while (pbuf_get_at(p, query_idx) != 0);
|
if (n < 0) {
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
} while (n != 0);
|
||||||
|
|
||||||
return query_idx + 1;
|
return offset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1116,10 +1133,10 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
|
|||||||
} else {
|
} else {
|
||||||
while ((nanswers > 0) && (res_idx < p->tot_len)) {
|
while ((nanswers > 0) && (res_idx < p->tot_len)) {
|
||||||
/* skip answer resource record's host name */
|
/* skip answer resource record's host name */
|
||||||
res_idx = dns_parse_name(p, res_idx);
|
res_idx = dns_skip_name(p, res_idx);
|
||||||
/* dns_parse_name() may return an res_idx out of pbuf bounds.
|
if (res_idx == 0xFFFF) {
|
||||||
* This will be caught in pbuf_copy_partial() below.
|
goto memerr; /* ignore this packet */
|
||||||
*/
|
}
|
||||||
|
|
||||||
/* Check for IP address type and Internet class. Others are discarded. */
|
/* Check for IP address type and Internet class. Others are discarded. */
|
||||||
if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
|
if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
|
||||||
@ -1168,6 +1185,9 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr,
|
|||||||
#endif /* LWIP_IPV6 */
|
#endif /* LWIP_IPV6 */
|
||||||
}
|
}
|
||||||
/* skip this answer */
|
/* skip this answer */
|
||||||
|
if ((int)(res_idx + htons(ans.len)) > 0xFFFF) {
|
||||||
|
goto memerr; /* ignore this packet */
|
||||||
|
}
|
||||||
res_idx += htons(ans.len);
|
res_idx += htons(ans.len);
|
||||||
--nanswers;
|
--nanswers;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user