On Sat, Oct 30, 2010 at 07:26:00PM +0200, Peter J. Philipp wrote:

> I had a look at the pack.c file where the DNS compression is being handled.
> It looks good to me.  But I have one concern that needs to be confirmed.
> In function dname_expand() on lines:
> 
>     54                          ptr = 256 * (n & ~0xc0) + data[offset + 1];
>     55                          if (ptr >= offset)
>     56                                  return (-1);
> 
> The pointer is checked against offset meaning that a compression loop can't 
> occur.  This is good.  However what happens if you have a DNS reply packet
> with a name with two labels in it, one being a normal label of a name and the 
> second being a compression pointer that points back to the first label, 
> kinda like so..
> 
> [8]centroid[C0 back to 8]
> 
> I'm worried it might go into an infinite loop or crash even.
> 
> Perhaps it should check that it cannot go back to a label inside a dns name 
> that
> is being parsed.

You are totally right. The following patch should fix it. Thanks a lot.

Eric.

--- pack.c.orig Sat Oct 30 21:22:14 2010
+++ pack.c      Sat Oct 30 21:22:06 2010
@@ -38,21 +38,21 @@ ssize_t
 dname_expand(const unsigned char *data, size_t len, size_t offset,
     size_t *newoffset, char *dst, size_t max)
 {
-       size_t           n, count, end, ptr;
+       size_t           n, count, end, ptr, start;
        ssize_t          res;
 
        if (offset >= len)
                return (-1);
 
        res = 0;
-       end = offset;
+       end = start = offset;
 
        for(; (n = data[offset]); ) {
                if ((n & 0xc0) == 0xc0) {
                        if (offset + 2 > len)
                                return (-1);
                        ptr = 256 * (n & ~0xc0) + data[offset + 1];
-                       if (ptr >= offset)
+                       if (ptr >= start)
                                return (-1);
                        if (end < offset + 2)
                                end = offset + 2;
@@ -91,8 +91,9 @@ const char *
 dname_nthlabel(int n, const unsigned char *data, size_t len, size_t offset)
 {
        int              i;
-       size_t           c, ptr;
+       size_t           c, ptr, start;
 
+       start = offset;
        for(i = 0;;) {
                c = data[offset];
                if (c == 0)
@@ -101,7 +102,7 @@ dname_nthlabel(int n, const unsigned char *data, size_
                        if (len < offset + 2)
                                return (NULL);
                        ptr = 256 * (c & ~0xc0) + data[offset + 1];
-                       if (ptr >= offset)
+                       if (ptr >= start)
                                return (NULL);
                        offset = ptr;
                        continue;
@@ -117,14 +118,15 @@ dname_nthlabel(int n, const unsigned char *data, size_
 ssize_t
 dname_count_labels(const unsigned char *data, size_t len, size_t offset)
 {
-       size_t c, n, ptr;
+       size_t c, n, ptr, start;
 
+       start = offset;
        for(n = 0; (c = data[offset]); ) {
                if ((c & 0xc0) == 0xc0) {
                        if (len < offset + 2)
                                return (-1);
                        ptr = 256 * (c & ~0xc0) + data[offset + 1];
-                       if (ptr >= offset)
+                       if (ptr >= start)
                                return (-1);
                        offset = ptr;
                        continue;

Reply via email to