From 922840efb951807fa1e6a29d269b892311da37e2 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 30 Jan 2025 13:56:42 +0000 Subject: [PATCH] import UBI unbound-1.16.2-5.8.el8_10 --- SOURCES/unbound-1.21-CVE-2024-8508.patch | 249 +++++++++++++++++++++++ SPECS/unbound.spec | 23 +-- 2 files changed, 260 insertions(+), 12 deletions(-) create mode 100644 SOURCES/unbound-1.21-CVE-2024-8508.patch diff --git a/SOURCES/unbound-1.21-CVE-2024-8508.patch b/SOURCES/unbound-1.21-CVE-2024-8508.patch new file mode 100644 index 0000000..36b3cdd --- /dev/null +++ b/SOURCES/unbound-1.21-CVE-2024-8508.patch @@ -0,0 +1,249 @@ +From 34de24d58bb5aa6fe3551512fc17cac08f65d93e Mon Sep 17 00:00:00 2001 +From: Yorgos Thessalonikefs +Date: Thu, 3 Oct 2024 14:46:57 +0200 +Subject: [PATCH] - Fix CVE-2024-8508, unbounded name compression could lead to + denial of service. + +--- + unbound-1.16.2/util/data/msgencode.c | 77 +++++++++++++++++----------- + 1 file changed, 46 insertions(+), 31 deletions(-) + +diff --git a/unbound-1.16.2/util/data/msgencode.c b/unbound-1.16.2/util/data/msgencode.c +index fe21cfb..f9e95e6 100644 +--- a/unbound-1.16.2/util/data/msgencode.c ++++ b/unbound-1.16.2/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); +-- +2.47.0 + diff --git a/SPECS/unbound.spec b/SPECS/unbound.spec index 3397bd1..e5e3dba 100644 --- a/SPECS/unbound.spec +++ b/SPECS/unbound.spec @@ -34,7 +34,7 @@ Summary: Validating, recursive, and caching DNS(SEC) resolver Name: unbound Version: 1.16.2 -Release: 5%{?extra_version:.%{extra_version}}%{?dist}.6 +Release: 5.8%{?extra_version:.%{extra_version}}%{?dist} License: BSD Url: https://www.unbound.net/ Source: https://www.unbound.net/downloads/%{name}-%{version}%{?extra_version}.tar.gz @@ -65,6 +65,8 @@ Patch2: unbound-1.15-source-compat.patch Patch3: unbound-1.16-CVE-2022-3204.patch # https://nlnetlabs.nl/downloads/unbound/patch_CVE-2023-50387_CVE-2023-50868.diff Patch4: unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch +# https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259 +Patch5: unbound-1.21-CVE-2024-8508.patch BuildRequires: gdb BuildRequires: gcc, make @@ -168,6 +170,7 @@ pushd %{pkgname} %patch2 -p1 -b .srccompat %patch3 -p2 -b .CVE-2022-3204 %patch4 -p2 -b .CVE-2023-50387-CVE-2023-50868 +%patch5 -p2 -b .CVE-2024-8508 # copy common doc files - after here, since it may be patched @@ -435,27 +438,23 @@ popd %verify(not md5 size mtime) %{_sharedstatedir}/%{name}/root.key %changelog -* Wed Apr 03 2024 Petr Menšík - 1.16.2-5.6 -- Rebuilt again with z-stream target +* Tue Nov 12 2024 Petr Menšík - 1.16.2-5.8 +- Prevent unbounded name compression (CVE-2024-8508) -* Wed Apr 03 2024 Petr Menšík - 1.16.2-5.5 -- Correct typo in new config file +* Tue May 28 2024 Petr Menšík - 1.16.2-5.7 +- Rebuild to propagate to CentOS Stream (RHEL-25500) -* Mon Mar 11 2024 Petr Menšík - 1.16.2-5.4 +* Mon Mar 11 2024 Petr Menšík - 1.16.2-5.6 - Ensure group access correction reaches also updated configs (CVE-2024-1488) * Wed Feb 28 2024 Petr Menšík - 1.16.2-5.3 - Ensure only unbound group can change configuration (CVE-2024-1488) -* Mon Feb 19 2024 Tomas Korbar - 1.16.2-5.2 -- Fix wrong entry in changelog -- Resolves: RHEL-25634 - * Fri Feb 16 2024 Tomas Korbar - 1.16.2-5.1 - Fix KeyTrap - Extreme CPU consumption in DNSSEC validator CVE-2023-50387 - Fix Preparing an NSEC3 closest encloser proof can exhaust CPU resources CVE-2023-50868 -- Resolves: RHEL-25660 -- Resolves: RHEL-25634 +- Resolves: RHEL-25428 +- Resolves: RHEL-25423 * Sat Oct 15 2022 Petr Menšík - 1.16.2-5 - Stop creating wrong devel manual pages (#2135322)