Version in base suite: 2.0.13-1.4 Base version: maradns_2.0.13-1.4 Target version: maradns_2.0.13-1.4+deb11u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/m/maradns/maradns_2.0.13-1.4.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/m/maradns/maradns_2.0.13-1.4+deb11u1.dsc changelog | 11 patches/0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch | 46 ++ patches/0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch | 199 ++++++++++ patches/0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch | 107 +++++ patches/series | 3 5 files changed, 366 insertions(+) diff -Nru maradns-2.0.13/debian/changelog maradns-2.0.13/debian/changelog --- maradns-2.0.13/debian/changelog 2020-01-14 12:06:54.000000000 +0000 +++ maradns-2.0.13/debian/changelog 2023-06-27 06:30:53.000000000 +0000 @@ -1,3 +1,14 @@ +maradns (2.0.13-1.4+deb11u1) bullseye-security; urgency=high + + * Non-maintainer upload by the Security Team, patches are from + Bastien Roucariès of LTS team. + * CVE-2023-31137: integer underflow in the DNS packet decompression + (Closes: #1035936). + * CVE-2022-30256: revoked and expired domains remain resolvable for + a long time (Closes: #1033252). + + -- Aron Xu Tue, 27 Jun 2023 14:30:53 +0800 + maradns (2.0.13-1.4) unstable; urgency=medium * Non-maintainer upload. diff -Nru maradns-2.0.13/debian/patches/0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch maradns-2.0.13/debian/patches/0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch --- maradns-2.0.13/debian/patches/0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch 1970-01-01 00:00:00.000000000 +0000 +++ maradns-2.0.13/debian/patches/0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch 2023-06-27 06:30:14.000000000 +0000 @@ -0,0 +1,46 @@ +From: Sam Trenholme +Date: Tue, 2 May 2023 16:35:04 -0700 +Subject: CVE-2023-31137 Integer Underflow (Wrap or Wraparound) + +Fix long standing issue in this code from 2002 + +A remotely exploitable integer underflow vulnerability in the DNS packet decompression +function allows an attacker to cause a Denial of Service by triggering an abnormal +program termination. + +The vulnerability exists in the `decomp_get_rddata` function within the `Decompress.c` file. +When handling a DNS packet with an Answer RR of qtype 16 (TXT record) and any qclass, +if the `rdlength` is smaller than `rdata`, the result of the line `Decompress.c:886` +is a negative number `len = rdlength - total;`. + +This value is then passed to the `decomp_append_bytes` function without proper validation, +causing the program to attempt to allocate a massive chunk of memory that is impossible to allocate. + +Consequently, the program exits with an error code of 64, causing a Denial of Service + +origin: https://github.com/samboy/MaraDNS/commit/bab062bde40b2ae8a91eecd522e84d8b993bab58.patch +bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1035936 +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2023-31137 +--- + dns/Decompress.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dns/Decompress.c b/dns/Decompress.c +index 24d88d5..ae8aa2e 100644 +--- a/dns/Decompress.c ++++ b/dns/Decompress.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2002-2006 Sam Trenholme ++/* Copyright (c) 2002-2023 Sam Trenholme + * + * TERMS + * +@@ -884,7 +884,7 @@ int decomp_get_rddata(js_string *compressed, js_string *out, + /* Variable length data (length determined by rdlength) */ + else if(subtype == RRSUB_VARIABLE) { + len = rdlength - total; +- if(len == 0) { ++ if(len <= 0) { + break; + } + if(decomp_append_bytes(compressed,out, diff -Nru maradns-2.0.13/debian/patches/0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch maradns-2.0.13/debian/patches/0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch --- maradns-2.0.13/debian/patches/0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch 1970-01-01 00:00:00.000000000 +0000 +++ maradns-2.0.13/debian/patches/0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch 2023-06-27 06:30:14.000000000 +0000 @@ -0,0 +1,199 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= +Date: Sun, 18 Jun 2023 14:39:18 +0000 +Subject: [1/2] CVE-2022-30256 Operation on a Resource after Expiration or + Release + +A revoked +domain name can still be resolvable for a long time, including expired +domains and taken-down malicious domains. The effects of an exploit +would be widespread and highly impactful, because the exploitation +conforms to de facto DNS specifications and operational practices, and +overcomes current mitigation patches for "Ghost" domain names. + +origin: https://raw.githubusercontent.com/samboy/MaraDNS/73af12e71890055f1728c1b7ccd900401f2fdf03/deadwood-github/update/3.4.03/deadwood-3.4.02-manylabel-TTL.patch +bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1033252 +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2022-30256 +--- + deadwood-3.2.09/src/DwRecurse.c | 30 +++++++++++++++++++----------- + deadwood-3.2.09/src/DwStr.c | 12 ++++++++---- + deadwood-3.2.09/src/DwStr_functions.h | 7 ++++--- + 3 files changed, 31 insertions(+), 18 deletions(-) + +diff --git a/deadwood-3.2.09/src/DwRecurse.c b/deadwood-3.2.09/src/DwRecurse.c +index 89c0a8e..9c9850d 100644 +--- a/deadwood-3.2.09/src/DwRecurse.c ++++ b/deadwood-3.2.09/src/DwRecurse.c +@@ -1707,6 +1707,8 @@ void dwx_handle_ns_refer_connect(int connection_number, dw_str *packet, + void dwx_handle_ns_refer(int connection_number, dw_str *action, + dw_str *query, int32_t ttl) { + dw_str *place = 0, *packet = 0; ++ int label_count = -1; ++ int_fast32_t this_max_ttl = max_ttl; + + if(rem[connection_number].ns == 0 || action == 0 + || rem[connection_number].is_upstream == 1) { +@@ -1723,7 +1725,7 @@ void dwx_handle_ns_refer(int connection_number, dw_str *action, + rem[connection_number].ns = dw_copy(action); + + /* Add this NS referral to the cache */ +- place = dw_get_dname(action->str, 0, 260); ++ place = dw_get_dname(action->str, 0, 260, &label_count); + if(place == 0) { + goto catch_dwx_handle_ns_refer; + } +@@ -1731,8 +1733,14 @@ void dwx_handle_ns_refer(int connection_number, dw_str *action, + * an hour for security reasons */ + ttl = 3600; + } +- if(ttl > max_ttl) { +- ttl = max_ttl; ++ if(label_count > 3) { ++ this_max_ttl >>= (label_count - 3); ++ if(this_max_ttl < 30) { ++ this_max_ttl = 30; ++ } ++ } ++ if(ttl > this_max_ttl) { ++ ttl = this_max_ttl; + } + dw_put_u16(place, 65395, -1); /* Add "NS refer" private RR type */ + dwh_add(cache,place,action,ttl,1); +@@ -1779,7 +1787,7 @@ dw_str *dwx_make_one_cname_rr(dw_str *question, int32_t question_offset, + goto catch_dwx_make_one_cname_rr; + } + +- temp = dw_get_dname(question->str, question_offset, size); ++ temp = dw_get_dname(question->str, question_offset, size, 0); + if(temp == 0) { + goto catch_dwx_make_one_cname_rr; + } +@@ -1795,7 +1803,7 @@ dw_str *dwx_make_one_cname_rr(dw_str *question, int32_t question_offset, + goto catch_dwx_make_one_cname_rr; + } + dw_destroy(temp); +- temp = dw_get_dname(answer->str, answer_offset, 260); ++ temp = dw_get_dname(answer->str, answer_offset, 260, 0); + if(temp == 0 || dw_put_u16(out, temp->len, -1) == -1 || + dw_append(temp,out) == -1) { + goto catch_dwx_make_one_cname_rr; +@@ -2196,7 +2204,7 @@ int dwx_handle_cname_refer(int connection_number, dw_str *action, + } + offset = dw_fetch_u16(action, -2); + offset += 2; /* Go past two-byte length */ +- real_query = dw_get_dname(action->str, offset, 260); ++ real_query = dw_get_dname(action->str, offset, 260, 0); + dwc_lower_case(real_query); + if(real_query == 0) { + goto catch_dwx_handle_cname_refer; +@@ -2268,7 +2276,7 @@ int dwx_cache_reply(dw_hash *cache, dw_str *query, dw_str *in, int32_t ttl, + ttl = max_ttl; + } + +- bailiwick = dw_get_dname(rem[connection_number].ns->str, 0, 260); ++ bailiwick = dw_get_dname(rem[connection_number].ns->str, 0, 260, 0); + if(bailiwick == 0 || bailiwick->len > 256) { + ret = -1; + goto catch_dwx_cache_reply; +@@ -2377,7 +2385,7 @@ dw_str *dwx_ns_convert_init(dw_str *bailiwick) { + return 0; + } + } else { +- dname = dw_get_dname(bailiwick->str, 0, 260); ++ dname = dw_get_dname(bailiwick->str, 0, 260, 0); + if(dname == 0) { + return 0; + } +@@ -2641,7 +2649,7 @@ ip_addr_T dwx_ns_getip_glueless(dw_str *list, int offset) { + } + + /* See if it is in the cache */ +- query = dw_get_dname(list->str + 3, offset, 256); ++ query = dw_get_dname(list->str + 3, offset, 256, 0); + dwc_lower_case(query); + if(query == 0 || dw_push_u16(type,query) == -1) { + goto catch_dwx_ns_getip_glueless; +@@ -2654,7 +2662,7 @@ ip_addr_T dwx_ns_getip_glueless(dw_str *list, int offset) { + } + } + +- addr.glueless = dw_get_dname(list->str + 3, offset, 260); ++ addr.glueless = dw_get_dname(list->str + 3, offset, 260, 0); + dw_put_u16(addr.glueless, key_n[DWM_N_ns_glueless_type], -1); + if(addr.glueless == 0) { + goto catch_dwx_ns_getip_glueless; +@@ -3205,7 +3213,7 @@ int dwx_cname_in_cache(dw_str *orig_query, dw_str *query, + /* Create new remote for solving incomplete CNAME */ + offset = dw_fetch_u16(action, -2); + offset += 2; /* Go past two-byte length */ +- real_query = dw_get_dname(action->str, offset, 260); ++ real_query = dw_get_dname(action->str, offset, 260, 0); + dwc_lower_case(real_query); + if(real_query == 0) { + goto catch_dwx_cname_in_cache; +diff --git a/deadwood-3.2.09/src/DwStr.c b/deadwood-3.2.09/src/DwStr.c +index 16fd1e8..1f2c56f 100644 +--- a/deadwood-3.2.09/src/DwStr.c ++++ b/deadwood-3.2.09/src/DwStr.c +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2007-2014 Sam Trenholme ++/* Copyright (c) 2007-2022 Sam Trenholme + * + * TERMS + * +@@ -774,10 +774,11 @@ int32_t dw_atoi(dw_str *obj, int32_t index, int base) { + * ASCII nulls, since DNS packets have those) and puts it in a newly + * created string. + * Input: Pointer to raw string; offset where we look for DNS DNAME, +- * maximum length of raw string ++ * maximum length of raw string; if label_count is not NULL, ++ * put the number of labels in this integer + * Output: A pointer to a new dw_str with NAME + */ +-dw_str *dw_get_dname(uint8_t *raw, int offset, int max) { ++dw_str *dw_get_dname(uint8_t *raw, int offset, int max, int *label_count) { + int len = 0, counter = 0; + int soffset = 0; + dw_str *out = 0; +@@ -822,6 +823,9 @@ dw_str *dw_get_dname(uint8_t *raw, int offset, int max) { + soffset++; + offset++; + } ++ if(label_count != 0) { ++ *label_count = counter; ++ } + out->len = soffset + 1; + return out; + +@@ -842,7 +846,7 @@ catch_dw_get_dname: + dw_str *dw_get_dname_type(uint8_t *raw, int offset, int max) { + dw_str *out = 0; + +- out = dw_get_dname(raw,offset,max); ++ out = dw_get_dname(raw,offset,max,0); + if(out == 0) { + goto catch_dw_get_dname_class; + } +diff --git a/deadwood-3.2.09/src/DwStr_functions.h b/deadwood-3.2.09/src/DwStr_functions.h +index 0904a8e..09e085f 100644 +--- a/deadwood-3.2.09/src/DwStr_functions.h ++++ b/deadwood-3.2.09/src/DwStr_functions.h +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2007-2010 Sam Trenholme ++/* Copyright (c) 2007-2022 Sam Trenholme + * + * TERMS + * +@@ -223,10 +223,11 @@ int32_t dw_atoi(dw_str *obj, int32_t index, int base); + * ASCII nulls, since DNS packets have those) and puts it in a newly + * created string. + * Input: Pointer to raw string; offset where we look for DNS DNAME, +- * maximum length of raw string ++ * maximum length of raw string; if label_count is not NULL, ++ * we set this int with the number of labels in the DNAME + * Output: A pointer to a new dw_str with NAME + */ +-dw_str *dw_get_dname(uint8_t *raw, int offset, int max); ++dw_str *dw_get_dname(uint8_t *raw, int offset, int max, int *label_count); + + /* This extracts a DNS DNAME, followed by a two-byte TYPE (the type of RR) + * from a raw c-string (with ASCII nulls, since DNS packets have those) diff -Nru maradns-2.0.13/debian/patches/0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch maradns-2.0.13/debian/patches/0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch --- maradns-2.0.13/debian/patches/0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch 1970-01-01 00:00:00.000000000 +0000 +++ maradns-2.0.13/debian/patches/0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch 2023-06-27 06:30:14.000000000 +0000 @@ -0,0 +1,107 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= +Date: Sun, 18 Jun 2023 14:44:12 +0000 +Subject: [2/2] CVE-2022-30256 Operation on a Resource after Expiration or + Release + +A revoked +domain name can still be resolvable for a long time, including expired +domains and taken-down malicious domains. The effects of an exploit +would be widespread and highly impactful, because the exploitation +conforms to de facto DNS specifications and operational practices, and +overcomes current mitigation patches for "Ghost" domain names. + +origin: https://raw.githubusercontent.com/samboy/MaraDNS/73af12e71890055f1728c1b7ccd900401f2fdf03/deadwood-github/update/3.4.03/deadwood-3.4.02-cname-TTL.patch +bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1033252 +bug-debian-security: https://security-tracker.debian.org/tracker/CVE-2022-30256 +--- + deadwood-3.2.09/src/DwRecurse.c | 23 ++++++++++++++++++----- + deadwood-3.2.09/src/DwRecurse.h | 4 ++-- + 2 files changed, 20 insertions(+), 7 deletions(-) + +diff --git a/deadwood-3.2.09/src/DwRecurse.c b/deadwood-3.2.09/src/DwRecurse.c +index 9c9850d..95eb453 100644 +--- a/deadwood-3.2.09/src/DwRecurse.c ++++ b/deadwood-3.2.09/src/DwRecurse.c +@@ -2069,7 +2069,7 @@ void dwx_send_glueless_cname_upstream(int conn_num, int c, int depth, + } + child_action = dwh_get(cache, cname_cache, 0, 1); + dwx_make_cname_reply(upstream, rem[upstream].query, +- child_action, uncomp, depth + 1); ++ child_action, uncomp, depth + 1, 0); + + catch_dwx_send_glueless_cname_upstream: + if(cname_cache != 0) { +@@ -2085,7 +2085,7 @@ catch_dwx_send_glueless_cname_upstream: + * send that reply out. + */ + int dwx_make_cname_reply(int conn_num, dw_str *query, +- dw_str *action, dw_str *answer, int depth) { ++ dw_str *action, dw_str *answer, int depth, int here_max_ttl) { + dw_str *uncomp = 0, *reply = 0, *comp = 0; + int ret = -1, c = 0; /* c is for counter */ + int_fast32_t ttl = 3600; +@@ -2114,6 +2114,9 @@ int dwx_make_cname_reply(int conn_num, dw_str *query, + if(ttl > max_ttl) { + ttl = max_ttl; + } ++ if(here_max_ttl > 0 && ttl > here_max_ttl) { ++ ttl = here_max_ttl; ++ } + /*ttl = 30; // DEBUG*/ + uncomp = dwx_create_cname_reply(query, action, answer, ttl); + comp = dwc_compress(query, uncomp); +@@ -2217,8 +2220,18 @@ int dwx_handle_cname_refer(int connection_number, dw_str *action, + /* See if we have the data already in the cache */ + answer = dwh_get(cache,real_query,0,1); + if(answer != 0) { /* In cache */ ++ /* Only keep new cached item in cache slightly longer ++ * than cache item it depends on */ ++ int32_t the_most_ttl; ++ the_most_ttl = dwh_get_ttl(cache,real_query) + 30; ++ if(the_most_ttl > max_ttl) { ++ the_most_ttl = max_ttl; ++ } ++ if(the_most_ttl < 30) { ++ the_most_ttl = 30; ++ } + ret = dwx_make_cname_reply(connection_number, query, +- action, answer,0); ++ action, answer,0,the_most_ttl); + goto catch_dwx_handle_cname_refer; + } else { /* Not in cache */ + ret = dwx_do_cname_glueless(real_query, connection_number); +@@ -3157,7 +3170,7 @@ void dwx_incomplete_cname_done(dw_str *query, int child, int l) { + goto catch_dwx_incomplete_cname_done; + } + +- dwx_make_cname_reply(parent, rem[parent].query, action, answer, 0); ++ dwx_make_cname_reply(parent, rem[parent].query, action, answer, 0, 0); + + catch_dwx_incomplete_cname_done: + if(cname_cache != 0) { +@@ -3300,7 +3313,7 @@ void dwx_cached_cname_done(dw_str *query, int b, int l, int depth) { + goto catch_dwx_cached_cname_done; + } + +- dwx_make_cname_reply(b,oquery,action,answer,depth + 1); ++ dwx_make_cname_reply(b,oquery,action,answer,depth + 1,0); + + catch_dwx_cached_cname_done: + dw_destroy(answer); +diff --git a/deadwood-3.2.09/src/DwRecurse.h b/deadwood-3.2.09/src/DwRecurse.h +index b3123b3..544c127 100644 +--- a/deadwood-3.2.09/src/DwRecurse.h ++++ b/deadwood-3.2.09/src/DwRecurse.h +@@ -1,4 +1,4 @@ +-/* Copyright (c) 2009-2011 Sam Trenholme ++/* Copyright (c) 2009-2022 Sam Trenholme + * + * TERMS + * +@@ -183,5 +183,5 @@ int dwx_cname_in_cache(dw_str *orig_query, dw_str *query, + * because we recursive call it from another function. + */ + int dwx_make_cname_reply(int conn_num, dw_str *query, +- dw_str *action, dw_str *answer, int depth); ++ dw_str *action, dw_str *answer, int depth, int here_max_ttl); + #endif /* __DWRECURSE_H_DEFINED__ */ diff -Nru maradns-2.0.13/debian/patches/series maradns-2.0.13/debian/patches/series --- maradns-2.0.13/debian/patches/series 2019-12-24 05:54:40.000000000 +0000 +++ maradns-2.0.13/debian/patches/series 2023-06-27 06:30:37.000000000 +0000 @@ -15,3 +15,6 @@ maradns_user_config.patch bind2csv2-py3.patch bind2csv2-use-py3.patch +0016-CVE-2023-31137-Integer-Underflow-Wrap-or-Wraparound.patch +0017-1-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch +0018-2-2-CVE-2022-30256-Operation-on-a-Resource-after-Exp.patch