]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Fix bug#305: pkt_dname_tolower could read beyond end of buffer or
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Apr 2010 09:04:07 +0000 (09:04 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 9 Apr 2010 09:04:07 +0000 (09:04 +0000)
  get into an endless loop, if 0x20 was enabled, and buffers are small
  or particular broken packets are received.

git-svn-id: file:///svn/unbound/trunk@2072 be551aaa-1e26-0410-a405-d3ace91eadb9

testcode/unitdname.c
util/data/dname.c

index d4c745fca57835bc856fe2f72bdcebe9fa552e4d..bd8a5404d4729f8e67a3885795344a087501352a 100644 (file)
@@ -795,12 +795,53 @@ dname_test_valid()
                , 4096) == 0);
 }
 
+/** test pkt_dname_tolower */
+static void
+dname_test_pdtl(ldns_buffer* loopbuf, ldns_buffer* boundbuf)
+{
+       unit_show_func("util/data/dname.c", "pkt_dname_tolower");
+       pkt_dname_tolower(loopbuf, ldns_buffer_at(loopbuf, 12));
+       pkt_dname_tolower(boundbuf, ldns_buffer_at(boundbuf, 12));
+}
+
+/** setup looped dname and out-of-bounds dname ptr */
+static void
+dname_setup_bufs(ldns_buffer* loopbuf, ldns_buffer* boundbuf)
+{
+       ldns_buffer_write_u16(loopbuf, 0xd54d);  /* id */
+       ldns_buffer_write_u16(loopbuf, 0x12);    /* flags  */
+       ldns_buffer_write_u16(loopbuf, 1);       /* qdcount */
+       ldns_buffer_write_u16(loopbuf, 0);       /* ancount */
+       ldns_buffer_write_u16(loopbuf, 0);       /* nscount */
+       ldns_buffer_write_u16(loopbuf, 0);       /* arcount */
+       ldns_buffer_write_u8(loopbuf, 0xc0); /* PTR back at itself */
+       ldns_buffer_write_u8(loopbuf, 0x0c);
+       ldns_buffer_flip(loopbuf);
+
+       ldns_buffer_write_u16(boundbuf, 0xd54d);  /* id */
+       ldns_buffer_write_u16(boundbuf, 0x12);    /* flags  */
+       ldns_buffer_write_u16(boundbuf, 1);       /* qdcount */
+       ldns_buffer_write_u16(boundbuf, 0);       /* ancount */
+       ldns_buffer_write_u16(boundbuf, 0);       /* nscount */
+       ldns_buffer_write_u16(boundbuf, 0);       /* arcount */
+       ldns_buffer_write_u8(boundbuf, 0x01); /* len=1 */
+       ldns_buffer_write_u8(boundbuf, 'A'); /* A. label */
+       ldns_buffer_write_u8(boundbuf, 0xc0); /* PTR out of bounds */
+       ldns_buffer_write_u8(boundbuf, 0xcc);
+       ldns_buffer_flip(boundbuf);
+}
+
 void dname_test()
 {
+       ldns_buffer* loopbuf = ldns_buffer_new(14);
+       ldns_buffer* boundbuf = ldns_buffer_new(16);
        ldns_buffer* buff = ldns_buffer_new(65800);
+       unit_assert(loopbuf && boundbuf && buff);
        ldns_buffer_flip(buff);
+       dname_setup_bufs(loopbuf, boundbuf);
        dname_test_qdl(buff);
        dname_test_qdtl(buff);
+       dname_test_pdtl(loopbuf, boundbuf);
        dname_test_query_dname_compare();
        dname_test_count_labels();
        dname_test_count_size_labels();
@@ -816,4 +857,6 @@ void dname_test()
        dname_test_topdomain();
        dname_test_valid();
        ldns_buffer_free(buff);
+       ldns_buffer_free(loopbuf);
+       ldns_buffer_free(boundbuf);
 }
index b7889791961edd2af5a2c2b7d19b58743bd63ecb..e6dbc3dd709738d0325f5cf7284ab9d0b5fc63c7 100644 (file)
@@ -148,17 +148,28 @@ void
 pkt_dname_tolower(ldns_buffer* pkt, uint8_t* dname)
 {
        uint8_t lablen;
+       int count = 0;
+       if(dname >= ldns_buffer_end(pkt))
+               return;
        lablen = *dname++;
        while(lablen) {
                if(LABEL_IS_PTR(lablen)) {
+                       if(PTR_OFFSET(lablen, *dname) >= ldns_buffer_limit(pkt))
+                               return;
                        dname = ldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
                        lablen = *dname++;
+                       if(count++ > MAX_COMPRESS_PTRS)
+                               return;
                        continue;
                }
+               if(dname+lablen >= ldns_buffer_end(pkt))
+                       return;
                while(lablen--) {
                        *dname = (uint8_t)tolower((int)*dname);
                        dname++;
                }
+               if(dname >= ldns_buffer_end(pkt))
+                       return;
                lablen = *dname++;
        }
 }