From: Wouter Wijngaards Date: Fri, 9 Apr 2010 09:04:07 +0000 (+0000) Subject: Fix bug#305: pkt_dname_tolower could read beyond end of buffer or X-Git-Tag: release-1.4.4rc1~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36c46a8f710cbe65d1faadab6e6f4c74dd98ec52;p=thirdparty%2Funbound.git Fix bug#305: pkt_dname_tolower could read beyond end of buffer or 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 --- diff --git a/testcode/unitdname.c b/testcode/unitdname.c index d4c745fca..bd8a5404d 100644 --- a/testcode/unitdname.c +++ b/testcode/unitdname.c @@ -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); } diff --git a/util/data/dname.c b/util/data/dname.c index b78897919..e6dbc3dd7 100644 --- a/util/data/dname.c +++ b/util/data/dname.c @@ -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++; } }