Made packet parsing code more robust.
This commit is contained in:
parent
70b254aec8
commit
f1f39e0caa
37
mdns.c
37
mdns.c
@ -575,6 +575,7 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off,
|
|||||||
uint8_t *name;
|
uint8_t *name;
|
||||||
size_t rr_data_len = 0;
|
size_t rr_data_len = 0;
|
||||||
struct rr_data_txt *txt_rec;
|
struct rr_data_txt *txt_rec;
|
||||||
|
int parse_error = 0;
|
||||||
|
|
||||||
assert(pkt != NULL);
|
assert(pkt != NULL);
|
||||||
|
|
||||||
@ -601,24 +602,54 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off,
|
|||||||
// RR data
|
// RR data
|
||||||
rr_data_len = ntohs( * (uint16_t *) p );
|
rr_data_len = ntohs( * (uint16_t *) p );
|
||||||
p += sizeof(uint16_t);
|
p += sizeof(uint16_t);
|
||||||
|
|
||||||
|
if (p + rr_data_len > e) {
|
||||||
|
DEBUG_PRINTF("rr_data_len goes beyond packet buffer: %lu > %lu\n", rr_data_len, e - p);
|
||||||
|
rr_entry_destroy(rr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
e = p + rr_data_len;
|
e = p + rr_data_len;
|
||||||
|
|
||||||
// see if we can parse the RR data
|
// see if we can parse the RR data
|
||||||
switch (rr->type) {
|
switch (rr->type) {
|
||||||
case RR_A:
|
case RR_A:
|
||||||
|
if (rr_data_len < sizeof(uint32_t)) {
|
||||||
|
DEBUG_PRINTF("invalid rr_data_len=%lu for A record\n", rr_data_len);
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
rr->data.A.addr = ntohl( * (uint32_t *) p );
|
rr->data.A.addr = ntohl( * (uint32_t *) p );
|
||||||
p += sizeof(uint32_t);
|
p += sizeof(uint32_t);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RR_PTR:
|
case RR_PTR:
|
||||||
rr->data.PTR.name = uncompress_nlabel(pkt_buf, pkt_len, p - pkt_buf);
|
rr->data.PTR.name = uncompress_nlabel(pkt_buf, pkt_len, p - pkt_buf);
|
||||||
|
if (rr->data.PTR.name == NULL) {
|
||||||
|
DEBUG_PRINTF("unable to parse/uncompress label for PTR name\n");
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
p += rr_data_len;
|
p += rr_data_len;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RR_TXT:
|
case RR_TXT:
|
||||||
txt_rec = &rr->data.TXT;
|
txt_rec = &rr->data.TXT;
|
||||||
|
|
||||||
|
// not supposed to happen, but we should handle it
|
||||||
|
if (rr_data_len == 0) {
|
||||||
|
DEBUG_PRINTF("WARN: rr_data_len for TXT is 0\n");
|
||||||
|
txt_rec->txt = create_label("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
txt_rec->txt = copy_label(pkt_buf, pkt_len, p - pkt_buf);
|
txt_rec->txt = copy_label(pkt_buf, pkt_len, p - pkt_buf);
|
||||||
|
if (txt_rec->txt == NULL) {
|
||||||
|
DEBUG_PRINTF("unable to copy label for TXT record\n");
|
||||||
|
parse_error = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
p += txt_rec->txt[0] + 1;
|
p += txt_rec->txt[0] + 1;
|
||||||
|
|
||||||
if (p >= e)
|
if (p >= e)
|
||||||
@ -636,6 +667,12 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off,
|
|||||||
p = e;
|
p = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there was a parse error, destroy partial rr_entry
|
||||||
|
if (parse_error) {
|
||||||
|
rr_entry_destroy(rr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
rr_list_append(&pkt->rr_ans, rr);
|
rr_list_append(&pkt->rr_ans, rr);
|
||||||
|
|
||||||
return p - (pkt_buf + off);
|
return p - (pkt_buf + off);
|
||||||
|
Loading…
Reference in New Issue
Block a user