]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
Fix crash in DNSSEC code when attempting to verify large RRs.
authorSimon Kelley <simon@thekelleys.org.uk>
Sun, 21 Dec 2014 16:11:52 +0000 (16:11 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Sun, 21 Dec 2014 16:11:52 +0000 (16:11 +0000)
CHANGELOG
src/dnssec.c

index 01f5208ec0061db84beba8e5fc9d1fbfc4adc864..956b71a151dbc0a3bcd28ab958a9b050f38b674b 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -19,6 +19,9 @@ version 2.73
            the answers given by --interface-name. Note that reverse queries
            (ie looking for names, given addresses) are not affected. 
            Thanks to Michael Gorbach for the suggestion.
+
+           Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
+           for the bug report.
        
 
 version 2.72
index 69bfc29e355f43b93eb1161232d276054dcc05a2..3208ac70114921ed29a0113470c40f0489efbf20 100644 (file)
@@ -456,16 +456,27 @@ static u16 *get_desc(int type)
 
 /* Return bytes of canonicalised rdata, when the return value is zero, the remaining 
    data, pointed to by *p, should be used raw. */
-static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, 
+static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
                     unsigned char **p, u16 **desc)
 {
   int d = **desc;
   
-  (*desc)++;
-  
   /* No more data needs mangling */
   if (d == (u16)-1)
-    return 0;
+    {
+      /* If there's more data than we have space for, just return what fits,
+        we'll get called again for more chunks */
+      if (end - *p > bufflen)
+       {
+         memcpy(buff, *p, bufflen);
+         *p += bufflen;
+         return bufflen;
+       }
+      
+      return 0;
+    }
+  (*desc)++;
   
   if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
     /* domain-name, canonicalise */
@@ -560,7 +571,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
              if (left1 != 0)
                memmove(buff1, buff1 + len1 - left1, left1);
              
-             if ((len1 = get_rdata(header, plen, end1, buff1 + left1, &p1, &dp1)) == 0)
+             if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
                {
                  quit = 1;
                  len1 = end1 - p1;
@@ -571,7 +582,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
              if (left2 != 0)
                memmove(buff2, buff2 + len2 - left2, left2);
              
-             if ((len2 = get_rdata(header, plen, end2, buff2 + left2, &p2, &dp2)) == 0)
+             if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
                {
                  quit = 1;
                  len2 = end2 - p2;
@@ -808,7 +819,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
          /* canonicalise rdata and calculate length of same, use name buffer as workspace */
          cp = p;
          dp = rr_desc;
-         for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
+         for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
          len += end - cp;
          len = htons(len);
          hash->update(ctx, 2, (unsigned char *)&len); 
@@ -816,7 +827,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
          /* Now canonicalise again and digest. */
          cp = p;
          dp = rr_desc;
-         while ((seg = get_rdata(header, plen, end, name, &cp, &dp)))
+         while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
            hash->update(ctx, seg, (unsigned char *)name);
          if (cp != end)
            hash->update(ctx, end - cp, cp);