dns: improve loop detection in label decompression

Previously the number of allowed pointers within a message is equal to
the data in a tvb (16575 in one example). This is still expensive, so
implement an alternative detection mechanism that looks for a direct
self-loop and limits the total pointers to about 256.

Bug: 13633
Change-Id: I803873e24ab170c7ef0b881d3bdc9dfd4014de97
Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1206
Reviewed-on: https://code.wireshark.org/review/21507
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Martin Kaiser <wireshark@kaiser.cx>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
This commit is contained in:
Peter Wu 2017-05-05 11:46:07 +02:00
parent 79eab8ca07
commit 129bdb5a16
1 changed files with 7 additions and 9 deletions

View File

@ -1134,8 +1134,7 @@ expand_dns_name(tvbuff_t *tvb, int offset, int max_len, int dns_data_offset,
int start_offset = offset;
guchar *np;
int len = -1;
int chars_processed = 0;
int data_size = tvb_reported_length_remaining(tvb, dns_data_offset);
int pointers_count = 0;
int component_len;
int indir_offset;
int maxname;
@ -1160,7 +1159,6 @@ expand_dns_name(tvbuff_t *tvb, int offset, int max_len, int dns_data_offset,
if (component_len == 0) {
break;
}
chars_processed++;
switch (component_len & 0xc0) {
case 0x00:
@ -1184,7 +1182,6 @@ expand_dns_name(tvbuff_t *tvb, int offset, int max_len, int dns_data_offset,
}
component_len--;
offset++;
chars_processed++;
}
break;
@ -1265,7 +1262,7 @@ expand_dns_name(tvbuff_t *tvb, int offset, int max_len, int dns_data_offset,
indir_offset = dns_data_offset +
(((component_len & ~0xc0) << 8) | tvb_get_guint8(tvb, offset));
offset++;
chars_processed++;
pointers_count++;
/* If "len" is negative, we are still working on the original name,
not something pointed to by a pointer, and so we should set "len"
@ -1273,10 +1270,11 @@ expand_dns_name(tvbuff_t *tvb, int offset, int max_len, int dns_data_offset,
if (len < 0) {
len = offset - start_offset;
}
/* If we've looked at every character in the message, this pointer
will make us look at some character again, which means we're
looping. */
if (chars_processed >= data_size) {
/*
* If we find a pointer to itself, it is a trivial loop. Otherwise if we
* processed a large number of pointers, assume an indirect loop.
*/
if (indir_offset == offset + 2 || pointers_count > MAXDNAME/4) {
*name="<Name contains a pointer that loops>";
*name_len = (guint)strlen(*name);
if (len < min_len) {