summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVirendra Thakur <virendrak@kpit.com>2025-03-04 14:42:08 +0530
committerArmin Kuster <akuster808@gmail.com>2025-03-07 19:40:44 -0500
commit454cc113175e42d803fe09d5a6c495c369b5a68a (patch)
treeae4cba2c5d49264c2959602ff3454250d979ba72
parent6c9f1f8d4538119803bf793747b65e4d23c33544 (diff)
downloadmeta-openembedded-454cc113175e42d803fe09d5a6c495c369b5a68a.tar.gz
unbound: Fix CVE-2024-8508
Malicious upstreams responses with very large RRsets can cause Unbound to spend a considerable time applying name compression to downstream replies. This can lead to degraded performance and eventually denial of service in well orchestrated attacks. Reference: https://nvd.nist.gov/vuln/detail/cve-2024-8508 Signed-off-by: Virendra Thakur <virendrak@kpit.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-networking/recipes-support/unbound/unbound/CVE-2024-8508.patch247
-rw-r--r--meta-networking/recipes-support/unbound/unbound_1.19.3.bb4
2 files changed, 250 insertions, 1 deletions
diff --git a/meta-networking/recipes-support/unbound/unbound/CVE-2024-8508.patch b/meta-networking/recipes-support/unbound/unbound/CVE-2024-8508.patch
new file mode 100644
index 0000000000..65219fc98c
--- /dev/null
+++ b/meta-networking/recipes-support/unbound/unbound/CVE-2024-8508.patch
@@ -0,0 +1,247 @@
1Description: Limit name compression calculations to avoid DoS
2 Introduces a hard limit on the number of name compression calculations
3 per packet to prevent CPU lockup from maliciously crafted large RRsets.
4 This mitigates potential denial of service attacks.
5Author: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
6Fixes: CVE-2024-8508
7CVE: CVE-2024-8508
8Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259]
9Signed-off-by: Virendra Thakur <virendrak@kpit.com>
10---
11
12Index: unbound-1.19.3/util/data/msgencode.c
13===================================================================
14--- unbound-1.19.3.orig/util/data/msgencode.c
15+++ unbound-1.19.3/util/data/msgencode.c
16@@ -62,6 +62,10 @@
17 #define RETVAL_TRUNC -4
18 /** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
19 #define RETVAL_OK 0
20+/** Max compressions we are willing to perform; more than that will result
21+ * in semi-compressed messages, or truncated even on TCP for huge messages, to
22+ * avoid locking the CPU for long */
23+#define MAX_COMPRESSION_PER_MESSAGE 120
24
25 /**
26 * Data structure to help domain name compression in outgoing messages.
27@@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt
28
29 /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
30 static int
31-compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
32- struct regional* region, struct compress_tree_node** tree,
33- size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
34+compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
35+ struct regional* region, struct compress_tree_node** tree,
36+ size_t owner_pos, uint16_t* owner_ptr, int owner_labs,
37+ size_t* compress_count)
38 {
39 struct compress_tree_node* p;
40 struct compress_tree_node** insertpt = NULL;
41 if(!*owner_ptr) {
42 /* compress first time dname */
43- if((p = compress_tree_lookup(tree, key->rk.dname,
44+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
45+ (p = compress_tree_lookup(tree, key->rk.dname,
46 owner_labs, &insertpt))) {
47 if(p->labs == owner_labs)
48 /* avoid ptr chains, since some software is
49@@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_ke
50 if(!write_compressed_dname(pkt, key->rk.dname,
51 owner_labs, p))
52 return RETVAL_TRUNC;
53+ (*compress_count)++;
54 /* check if typeclass+4 ttl + rdatalen is available */
55 if(sldns_buffer_remaining(pkt) < 4+4+2)
56 return RETVAL_TRUNC;
57@@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_ke
58 if(owner_pos <= PTR_MAX_OFFSET)
59 *owner_ptr = htons(PTR_CREATE(owner_pos));
60 }
61- if(!compress_tree_store(key->rk.dname, owner_labs,
62+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
63+ !compress_tree_store(key->rk.dname, owner_labs,
64 owner_pos, region, p, insertpt))
65 return RETVAL_OUTMEM;
66 } else {
67@@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_ke
68
69 /** compress any domain name to the packet, return RETVAL_* */
70 static int
71-compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
72- struct regional* region, struct compress_tree_node** tree)
73+compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
74+ struct regional* region, struct compress_tree_node** tree,
75+ size_t* compress_count)
76 {
77 struct compress_tree_node* p;
78 struct compress_tree_node** insertpt = NULL;
79 size_t pos = sldns_buffer_position(pkt);
80- if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
81+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
82+ (p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
83 if(!write_compressed_dname(pkt, dname, labs, p))
84 return RETVAL_TRUNC;
85+ (*compress_count)++;
86 } else {
87 if(!dname_buffer_write(pkt, dname))
88 return RETVAL_TRUNC;
89 }
90- if(!compress_tree_store(dname, labs, pos, region, p, insertpt))
91+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
92+ !compress_tree_store(dname, labs, pos, region, p, insertpt))
93 return RETVAL_OUTMEM;
94 return RETVAL_OK;
95 }
96@@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed
97
98 /** compress domain names in rdata, return RETVAL_* */
99 static int
100-compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
101- struct regional* region, struct compress_tree_node** tree,
102- const sldns_rr_descriptor* desc)
103+compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
104+ struct regional* region, struct compress_tree_node** tree,
105+ const sldns_rr_descriptor* desc, size_t* compress_count)
106 {
107 int labs, r, rdf = 0;
108 size_t dname_len, len, pos = sldns_buffer_position(pkt);
109@@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_
110 switch(desc->_wireformat[rdf]) {
111 case LDNS_RDF_TYPE_DNAME:
112 labs = dname_count_size_labels(rdata, &dname_len);
113- if((r=compress_any_dname(rdata, pkt, labs, region,
114- tree)) != RETVAL_OK)
115+ if((r=compress_any_dname(rdata, pkt, labs, region,
116+ tree, compress_count)) != RETVAL_OK)
117 return r;
118 rdata += dname_len;
119 todolen -= dname_len;
120@@ -449,7 +461,8 @@ static int
121 packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
122 uint16_t* num_rrs, time_t timenow, struct regional* region,
123 int do_data, int do_sig, struct compress_tree_node** tree,
124- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
125+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
126+ size_t* compress_count)
127 {
128 size_t i, j, owner_pos;
129 int r, owner_labs;
130@@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrs
131 for(i=0; i<data->count; i++) {
132 /* rrset roundrobin */
133 j = (i + rr_offset) % data->count;
134- if((r=compress_owner(key, pkt, region, tree,
135- owner_pos, &owner_ptr, owner_labs))
136- != RETVAL_OK)
137+ if((r=compress_owner(key, pkt, region, tree,
138+ owner_pos, &owner_ptr, owner_labs,
139+ compress_count)) != RETVAL_OK)
140 return r;
141 sldns_buffer_write(pkt, &key->rk.type, 2);
142 sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
143@@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrs
144 else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust);
145 if(c) {
146 if((r=compress_rdata(pkt, data->rr_data[j],
147- data->rr_len[j], region, tree, c))
148- != RETVAL_OK)
149+ data->rr_len[j], region, tree, c,
150+ compress_count)) != RETVAL_OK)
151 return r;
152 } else {
153 if(sldns_buffer_remaining(pkt) < data->rr_len[j])
154@@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrs
155 return RETVAL_TRUNC;
156 sldns_buffer_write(pkt, &owner_ptr, 2);
157 } else {
158- if((r=compress_any_dname(key->rk.dname,
159- pkt, owner_labs, region, tree))
160- != RETVAL_OK)
161+ if((r=compress_any_dname(key->rk.dname,
162+ pkt, owner_labs, region, tree,
163+ compress_count)) != RETVAL_OK)
164 return r;
165 if(sldns_buffer_remaining(pkt) <
166 4+4+data->rr_len[i])
167@@ -544,7 +557,8 @@ static int
168 insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
169 sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
170 struct regional* region, struct compress_tree_node** tree,
171- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
172+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
173+ size_t* compress_count)
174 {
175 int r;
176 size_t i, setstart;
177@@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, s
178 setstart = sldns_buffer_position(pkt);
179 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
180 pkt, num_rrs, timenow, region, 1, 1, tree,
181- s, qtype, dnssec, rr_offset))
182+ s, qtype, dnssec, rr_offset, compress_count))
183 != RETVAL_OK) {
184 /* Bad, but if due to size must set TC bit */
185 /* trim off the rrset neatly. */
186@@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, s
187 setstart = sldns_buffer_position(pkt);
188 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
189 pkt, num_rrs, timenow, region, 1, 0, tree,
190- s, qtype, dnssec, rr_offset))
191+ s, qtype, dnssec, rr_offset, compress_count))
192 != RETVAL_OK) {
193 sldns_buffer_set_position(pkt, setstart);
194 return r;
195@@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, s
196 setstart = sldns_buffer_position(pkt);
197 if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
198 pkt, num_rrs, timenow, region, 0, 1, tree,
199- s, qtype, dnssec, rr_offset))
200+ s, qtype, dnssec, rr_offset, compress_count))
201 != RETVAL_OK) {
202 sldns_buffer_set_position(pkt, setstart);
203 return r;
204@@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qin
205 struct compress_tree_node* tree = 0;
206 int r;
207 size_t rr_offset;
208+ size_t compress_count=0;
209
210 sldns_buffer_clear(buffer);
211 if(udpsize < sldns_buffer_limit(buffer))
212@@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qin
213 arep.rrsets = &qinfo->local_alias->rrset;
214 if((r=insert_section(&arep, 1, &ancount, buffer, 0,
215 timezero, region, &tree, LDNS_SECTION_ANSWER,
216- qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
217+ qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
218 if(r == RETVAL_TRUNC) {
219 /* create truncated message */
220 sldns_buffer_write_u16_at(buffer, 6, ancount);
221@@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qin
222 /* insert answer section */
223 if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
224 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
225- dnssec, rr_offset)) != RETVAL_OK) {
226+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
227 if(r == RETVAL_TRUNC) {
228 /* create truncated message */
229 sldns_buffer_write_u16_at(buffer, 6, ancount);
230@@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qin
231 if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
232 rep->an_numrrsets, timenow, region, &tree,
233 LDNS_SECTION_AUTHORITY, qinfo->qtype,
234- dnssec, rr_offset)) != RETVAL_OK) {
235+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
236 if(r == RETVAL_TRUNC) {
237 /* create truncated message */
238 sldns_buffer_write_u16_at(buffer, 8, nscount);
239@@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qin
240 if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
241 rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
242 &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
243- dnssec, rr_offset)) != RETVAL_OK) {
244+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
245 if(r == RETVAL_TRUNC) {
246 /* no need to set TC bit, this is the additional */
247 sldns_buffer_write_u16_at(buffer, 10, arcount);
diff --git a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
index ffdc78e9d6..6f54038c6c 100644
--- a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
+++ b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb
@@ -9,7 +9,9 @@ SECTION = "net"
9LICENSE = "BSD-3-Clause" 9LICENSE = "BSD-3-Clause"
10LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06" 10LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06"
11 11
12SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3" 12SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3 \
13 file://CVE-2024-8508.patch \
14 "
13SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" 15SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd"
14 16
15inherit autotools pkgconfig systemd update-rc.d 17inherit autotools pkgconfig systemd update-rc.d