Commit faf924ec authored by Roel Postelmans's avatar Roel Postelmans Committed by GitHub

Merge pull request #473 from shachy12/mdns_stack_overflow_fix

Fixed stack overflow in pico_dns_decompress_name
parents c8f589fb b5b3393c
......@@ -20,9 +20,16 @@
#endif
/* MARK: v NAME & IP FUNCTIONS */
/* ****************************************************************************
* Iterates over labels, stops when:
* - Label is compressed
* - length greater than 63
* - arriving to null terminator
* - exceeding maxlen
* ****************************************************************************/
#define dns_name_foreach_label_safe(label, name, next, maxlen) \
for ((label) = (name), (next) = (char *)((name) + *(unsigned char*)(name) + 1); \
(*(label) != '\0') && ((uint16_t)((label) - (name)) < (maxlen)); \
(*(label) != '\0') && ((uint16_t)((label) - (name)) < (maxlen)) && (((*label) & 0xC0) != 0xC0) && (*label <= 63); \
(label) = (next), (next) = (char *)((next) + *(unsigned char*)(next) + 1))
/* ****************************************************************************
......@@ -72,6 +79,7 @@ pico_dns_namelen_comp( char *name )
return len;
}
/* ****************************************************************************
* Returns the uncompressed name in DNS name format when DNS name compression
* is applied to the packet-buffer.
......@@ -87,31 +95,47 @@ pico_dns_decompress_name( char *name, pico_dns_packet *packet )
0
};
char *return_name = NULL;
uint8_t *dest_iterator = NULL;
uint8_t *iterator = NULL;
uint16_t ptr = 0, nslen = 0;
uint16_t decompressed_index = 0;
char *label = NULL, *next = NULL;
/* Reading labels until reaching to pointer or NULL terminator.
* Only one pointer is allowed in DNS compression, the pointer is always the last according to the RFC */
dns_name_foreach_label_safe(label, name, next, sizeof(decompressed_name)) {
uint8_t label_size = (uint8_t)(*label) + 1;
if (decompressed_index + label_size >= sizeof(decompressed_name)) {
return NULL;
}
memcpy(&decompressed_name[decompressed_index], label, label_size);
decompressed_index += label_size;
}
if (decompressed_index >= sizeof(decompressed_name)) {
return NULL;
}
if (*label & 0xC0) {
/* Found compression bits */
ptr = (uint16_t)((((uint16_t) *label) & 0x003F) << 8);
ptr = (uint16_t)(ptr | (uint16_t) *(label + 1));
label = (uint8_t *)((uint8_t *)packet + ptr);
/* Initialise iterators */
iterator = (uint8_t *) name;
dest_iterator = (uint8_t *) decompressed_name;
while (*iterator != '\0') {
if ((*iterator) & 0xC0) {
/* We have a pointer */
ptr = (uint16_t)((((uint16_t) *iterator) & 0x003F) << 8);
ptr = (uint16_t)(ptr | (uint16_t) *(iterator + 1));
iterator = (uint8_t *)((uint8_t *)packet + ptr);
} else {
/* We want to keep the label lengths */
*dest_iterator = (uint8_t) *iterator;
/* Copy the label */
memcpy(dest_iterator + 1, iterator + 1, *iterator);
/* Move to next length label */
dest_iterator += (*iterator) + 1;
iterator += (*iterator) + 1;
dns_name_foreach_label_safe(label, label, next, sizeof(decompressed_name) - decompressed_index) {
uint8_t label_size = (uint8_t)(*label) + 1;
if (decompressed_index + label_size >= sizeof(decompressed_name)) {
return NULL;
}
memcpy(&decompressed_name[decompressed_index], label, label_size);
decompressed_index += label_size;
}
}
if (decompressed_index >= sizeof(decompressed_name)) {
return NULL;
}
/* Append final zero-byte */
*dest_iterator = (uint8_t) '\0';
decompressed_name[decompressed_index] = (uint8_t) '\0';
/* Provide storage for the name to return */
nslen = (uint16_t)(pico_dns_strlen(decompressed_name) + 1);
......@@ -651,9 +675,7 @@ pico_dns_question_decompress( struct pico_dns_question *question,
char *qname_original = question->qname;
/* Try to decompress the question name */
if (!(question->qname = pico_dns_decompress_name(question->qname, packet))) {
question->qname = qname_original;
}
question->qname = pico_dns_decompress_name(question->qname, packet);
return qname_original;
}
......@@ -970,9 +992,7 @@ pico_dns_record_decompress( struct pico_dns_record *record,
char *rname_original = record->rname;
/* Try to decompress the record name */
if (!(record->rname = pico_dns_decompress_name(record->rname, packet))) {
record->rname = rname_original;
}
record->rname = pico_dns_decompress_name(record->rname, packet);
return rname_original;
}
......
......@@ -1971,19 +1971,21 @@ pico_mdns_handle_single_question( struct pico_dns_question *question,
/* Decompress single DNS question */
qname_original = pico_dns_question_decompress(question, packet);
mdns_dbg("Question RCVD for '%s'\n", question->qname);
if (NULL != question->qname) {
/* Find currently active query cookie */
if ((cookie = pico_mdns_ctree_find_cookie(question->qname,
PICO_MDNS_PACKET_TYPE_QUERY))) {
mdns_dbg("Query cookie found for question, suppress duplicate.\n");
cookie->status = PICO_MDNS_COOKIE_STATUS_CANCELLED;
} else {
qtype = short_be(question->qsuffix->qtype);
qclass = short_be(question->qsuffix->qclass);
antree = pico_mdns_populate_antree(question->qname, qtype, qclass);
}
/* Find currently active query cookie */
if ((cookie = pico_mdns_ctree_find_cookie(question->qname,
PICO_MDNS_PACKET_TYPE_QUERY))) {
mdns_dbg("Query cookie found for question, suppress duplicate.\n");
cookie->status = PICO_MDNS_COOKIE_STATUS_CANCELLED;
} else {
qtype = short_be(question->qsuffix->qtype);
qclass = short_be(question->qsuffix->qclass);
antree = pico_mdns_populate_antree(question->qname, qtype, qclass);
}
PICO_FREE(question->qname);
PICO_FREE(question->qname);
}
question->qname = qname_original;
return antree;
}
......@@ -2195,27 +2197,29 @@ pico_mdns_handle_data_as_answers_generic( uint8_t **ptr,
/* Make an mDNS record from the DNS answer */
orname = pico_dns_record_decompress(&answer, packet);
mdns_answer.record = &answer;
mdns_answer.record->rname_length = (uint16_t)(pico_dns_strlen(answer.rname) + 1u);
/* Handle a single aswer */
switch (type) {
case 1:
pico_mdns_handle_single_authority(&mdns_answer);
break;
case 2:
pico_mdns_handle_single_additional(&mdns_answer);
break;
default:
pico_mdns_handle_single_answer(&mdns_answer);
if (NULL != answer.rname) {
mdns_answer.record = &answer;
mdns_answer.record->rname_length = (uint16_t)(pico_dns_strlen(answer.rname) + 1u);
/* Handle a single aswer */
switch (type) {
case 1:
pico_mdns_handle_single_authority(&mdns_answer);
break;
case 2:
pico_mdns_handle_single_additional(&mdns_answer);
break;
default:
pico_mdns_handle_single_answer(&mdns_answer);
#if PICO_MDNS_ALLOW_CACHING == 1
pico_mdns_cache_add_record(&mdns_answer);
pico_mdns_cache_add_record(&mdns_answer);
#endif
break;
}
break;
}
/* Free decompressed name and mDNS record */
PICO_FREE(mdns_answer.record->rname);
/* Free decompressed name and mDNS record */
PICO_FREE(mdns_answer.record->rname);
}
answer.rname = orname;
/* Move to next record */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment