diff options
author | Virendra Thakur <virendrak@kpit.com> | 2025-03-04 14:42:08 +0530 |
---|---|---|
committer | Armin Kuster <akuster808@gmail.com> | 2025-03-07 19:40:44 -0500 |
commit | 454cc113175e42d803fe09d5a6c495c369b5a68a (patch) | |
tree | ae4cba2c5d49264c2959602ff3454250d979ba72 | |
parent | 6c9f1f8d4538119803bf793747b65e4d23c33544 (diff) | |
download | meta-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.patch | 247 | ||||
-rw-r--r-- | meta-networking/recipes-support/unbound/unbound_1.19.3.bb | 4 |
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 @@ | |||
1 | Description: 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. | ||
5 | Author: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl> | ||
6 | Fixes: CVE-2024-8508 | ||
7 | CVE: CVE-2024-8508 | ||
8 | Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259] | ||
9 | Signed-off-by: Virendra Thakur <virendrak@kpit.com> | ||
10 | --- | ||
11 | |||
12 | Index: 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" | |||
9 | LICENSE = "BSD-3-Clause" | 9 | LICENSE = "BSD-3-Clause" |
10 | LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06" | 10 | LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06" |
11 | 11 | ||
12 | SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3" | 12 | SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3 \ |
13 | file://CVE-2024-8508.patch \ | ||
14 | " | ||
13 | SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" | 15 | SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" |
14 | 16 | ||
15 | inherit autotools pkgconfig systemd update-rc.d | 17 | inherit autotools pkgconfig systemd update-rc.d |