From 01883fb01700b4379bbcb064a6c6bf48674d2069 Mon Sep 17 00:00:00 2001 From: Yorgos Thessalonikefs Date: Thu, 3 Oct 2024 14:11:57 +0200 Subject: [PATCH 1/2] - Set version to 1.21.1 --- configure | 25 +++++++++++++------------ configure.ac | 5 +++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/configure b/configure index 63051eca8..ef250d6c6 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for unbound 1.21.0. +# Generated by GNU Autoconf 2.71 for unbound 1.21.1. # # Report bugs to . # @@ -622,8 +622,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.21.0' -PACKAGE_STRING='unbound 1.21.0' +PACKAGE_VERSION='1.21.1' +PACKAGE_STRING='unbound 1.21.1' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_URL='' @@ -1508,7 +1508,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.21.0 to adapt to many kinds of systems. +\`configure' configures unbound 1.21.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1574,7 +1574,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.21.0:";; + short | recursive ) echo "Configuration of unbound 1.21.1:";; esac cat <<\_ACEOF @@ -1822,7 +1822,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.21.0 +unbound configure 1.21.1 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2479,7 +2479,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.21.0, which was +It was created by unbound $as_me 1.21.1, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3243,11 +3243,11 @@ UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MINOR=21 -UNBOUND_VERSION_MICRO=0 +UNBOUND_VERSION_MICRO=1 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=28 +LIBUNBOUND_REVISION=29 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -3343,6 +3343,7 @@ LIBUNBOUND_AGE=1 # 1.19.3 had 9:26:1 # 1.20.0 had 9:27:1 # 1.21.0 had 9:28:1 +# 1.21.1 had 9:29:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -24644,7 +24645,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h -version=1.21.0 +version=1.21.1 date=`date +'%b %e, %Y'` @@ -25156,7 +25157,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.21.0, which was +This file was extended by unbound $as_me 1.21.1, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -25224,7 +25225,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -unbound config.status 1.21.0 +unbound config.status 1.21.1 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index c30d931de..fdded4f50 100644 --- a/configure.ac +++ b/configure.ac @@ -11,14 +11,14 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MINOR],[21]) -m4_define([VERSION_MICRO],[0]) +m4_define([VERSION_MICRO],[1]) AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=28 +LIBUNBOUND_REVISION=29 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -114,6 +114,7 @@ LIBUNBOUND_AGE=1 # 1.19.3 had 9:26:1 # 1.20.0 had 9:27:1 # 1.21.0 had 9:28:1 +# 1.21.1 had 9:29:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary From b7c61d7cc256d6a174e6179622c7fa968272c259 Mon Sep 17 00:00:00 2001 From: Yorgos Thessalonikefs Date: Thu, 3 Oct 2024 14:46:57 +0200 Subject: [PATCH 2/2] - Fix CVE-2024-8508, unbounded name compression could lead to denial of service. --- util/data/msgencode.c | 77 ++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 898ff8412..6d116fb52 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -62,6 +62,10 @@ #define RETVAL_TRUNC -4 /** return code that means all is peachy keen. Equal to DNS rcode NOERROR */ #define RETVAL_OK 0 +/** Max compressions we are willing to perform; more than that will result + * in semi-compressed messages, or truncated even on TCP for huge messages, to + * avoid locking the CPU for long */ +#define MAX_COMPRESSION_PER_MESSAGE 120 /** * Data structure to help domain name compression in outgoing messages. @@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs, /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */ static int -compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - struct regional* region, struct compress_tree_node** tree, - size_t owner_pos, uint16_t* owner_ptr, int owner_labs) +compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, + struct regional* region, struct compress_tree_node** tree, + size_t owner_pos, uint16_t* owner_ptr, int owner_labs, + size_t* compress_count) { struct compress_tree_node* p; struct compress_tree_node** insertpt = NULL; if(!*owner_ptr) { /* compress first time dname */ - if((p = compress_tree_lookup(tree, key->rk.dname, + if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && + (p = compress_tree_lookup(tree, key->rk.dname, owner_labs, &insertpt))) { if(p->labs == owner_labs) /* avoid ptr chains, since some software is @@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, if(!write_compressed_dname(pkt, key->rk.dname, owner_labs, p)) return RETVAL_TRUNC; + (*compress_count)++; /* check if typeclass+4 ttl + rdatalen is available */ if(sldns_buffer_remaining(pkt) < 4+4+2) return RETVAL_TRUNC; @@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, if(owner_pos <= PTR_MAX_OFFSET) *owner_ptr = htons(PTR_CREATE(owner_pos)); } - if(!compress_tree_store(key->rk.dname, owner_labs, + if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && + !compress_tree_store(key->rk.dname, owner_labs, owner_pos, region, p, insertpt)) return RETVAL_OUTMEM; } else { @@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, /** compress any domain name to the packet, return RETVAL_* */ static int -compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, - struct regional* region, struct compress_tree_node** tree) +compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, + struct regional* region, struct compress_tree_node** tree, + size_t* compress_count) { struct compress_tree_node* p; struct compress_tree_node** insertpt = NULL; size_t pos = sldns_buffer_position(pkt); - if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) { + if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && + (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { if(!write_compressed_dname(pkt, dname, labs, p)) return RETVAL_TRUNC; + (*compress_count)++; } else { if(!dname_buffer_write(pkt, dname)) return RETVAL_TRUNC; } - if(!compress_tree_store(dname, labs, pos, region, p, insertpt)) + if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && + !compress_tree_store(dname, labs, pos, region, p, insertpt)) return RETVAL_OUTMEM; return RETVAL_OK; } @@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed_rrset_key* key) /** compress domain names in rdata, return RETVAL_* */ static int -compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, - struct regional* region, struct compress_tree_node** tree, - const sldns_rr_descriptor* desc) +compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, + struct regional* region, struct compress_tree_node** tree, + const sldns_rr_descriptor* desc, size_t* compress_count) { int labs, r, rdf = 0; size_t dname_len, len, pos = sldns_buffer_position(pkt); @@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: labs = dname_count_size_labels(rdata, &dname_len); - if((r=compress_any_dname(rdata, pkt, labs, region, - tree)) != RETVAL_OK) + if((r=compress_any_dname(rdata, pkt, labs, region, + tree, compress_count)) != RETVAL_OK) return r; rdata += dname_len; todolen -= dname_len; @@ -449,7 +461,8 @@ static int packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, uint16_t* num_rrs, time_t timenow, struct regional* region, int do_data, int do_sig, struct compress_tree_node** tree, - sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) + sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, + size_t* compress_count) { size_t i, j, owner_pos; int r, owner_labs; @@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, for(i=0; icount; i++) { /* rrset roundrobin */ j = (i + rr_offset) % data->count; - if((r=compress_owner(key, pkt, region, tree, - owner_pos, &owner_ptr, owner_labs)) - != RETVAL_OK) + if((r=compress_owner(key, pkt, region, tree, + owner_pos, &owner_ptr, owner_labs, + compress_count)) != RETVAL_OK) return r; sldns_buffer_write(pkt, &key->rk.type, 2); sldns_buffer_write(pkt, &key->rk.rrset_class, 2); @@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust); if(c) { if((r=compress_rdata(pkt, data->rr_data[j], - data->rr_len[j], region, tree, c)) - != RETVAL_OK) + data->rr_len[j], region, tree, c, + compress_count)) != RETVAL_OK) return r; } else { if(sldns_buffer_remaining(pkt) < data->rr_len[j]) @@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, return RETVAL_TRUNC; sldns_buffer_write(pkt, &owner_ptr, 2); } else { - if((r=compress_any_dname(key->rk.dname, - pkt, owner_labs, region, tree)) - != RETVAL_OK) + if((r=compress_any_dname(key->rk.dname, + pkt, owner_labs, region, tree, + compress_count)) != RETVAL_OK) return r; if(sldns_buffer_remaining(pkt) < 4+4+data->rr_len[i]) @@ -544,7 +557,8 @@ static int insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, sldns_buffer* pkt, size_t rrsets_before, time_t timenow, struct regional* region, struct compress_tree_node** tree, - sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) + sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, + size_t* compress_count) { int r; size_t i, setstart; @@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 1, tree, - s, qtype, dnssec, rr_offset)) + s, qtype, dnssec, rr_offset, compress_count)) != RETVAL_OK) { /* Bad, but if due to size must set TC bit */ /* trim off the rrset neatly. */ @@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 0, tree, - s, qtype, dnssec, rr_offset)) + s, qtype, dnssec, rr_offset, compress_count)) != RETVAL_OK) { sldns_buffer_set_position(pkt, setstart); return r; @@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 0, 1, tree, - s, qtype, dnssec, rr_offset)) + s, qtype, dnssec, rr_offset, compress_count)) != RETVAL_OK) { sldns_buffer_set_position(pkt, setstart); return r; @@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, struct compress_tree_node* tree = 0; int r; size_t rr_offset; + size_t compress_count=0; sldns_buffer_clear(buffer); if(udpsize < sldns_buffer_limit(buffer)) @@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, arep.rrsets = &qinfo->local_alias->rrset; if((r=insert_section(&arep, 1, &ancount, buffer, 0, timezero, region, &tree, LDNS_SECTION_ANSWER, - qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { + qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 6, ancount); @@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { + dnssec, rr_offset, &compress_count)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 6, ancount); @@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, rep->an_numrrsets, timenow, region, &tree, LDNS_SECTION_AUTHORITY, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { + dnssec, rr_offset, &compress_count)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 8, nscount); @@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, - dnssec, rr_offset)) != RETVAL_OK) { + dnssec, rr_offset, &compress_count)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* no need to set TC bit, this is the additional */ sldns_buffer_write_u16_at(buffer, 10, arcount);