Made packet parsing code more robust.

This commit is contained in:
Darell Tan 2012-11-27 23:58:33 +08:00
parent 70b254aec8
commit f1f39e0caa

37
mdns.c
View File

@ -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);