Package: release.debian.org Severity: normal Tags: buster User: release.debian....@packages.debian.org Usertags: pu
Fixes for low-severity issues CVE-2019-10203 and CVE-2020-17482. Both using upstream patches for the 4.1 branch. Maybe it should be pointed out in the stable update notes that manual action is needed to remedy CVE-2019-10203 for existing installations using postgres. "Manual schema update required for PostgreSQL"? Chris diff -Nru pdns-4.1.6/debian/changelog pdns-4.1.6/debian/changelog --- pdns-4.1.6/debian/changelog 2019-06-21 19:07:07.000000000 +0000 +++ pdns-4.1.6/debian/changelog 2020-09-22 19:07:45.000000000 +0000 @@ -1,3 +1,13 @@ +pdns (4.1.6-3+deb10u1) buster; urgency=medium + + * Apply upstream patches to fix CVE-2019-10203. + To actually fix this problem in existing installations, the newly + supplied schema file 4.1.10_to_4.1.11.schema.pgsql.sql has to be + manually applied to the backing PostgreSQL database. (Closes: #970729) + * Apply upstream patches to fix CVE-2020-17482 (Closes: #970737) + + -- Chris Hofstaedtler <z...@debian.org> Tue, 22 Sep 2020 19:07:45 +0000 + pdns (4.1.6-3) unstable; urgency=medium * Fix Denial of service via crafted zone records (CVE-2019-10162) diff -Nru pdns-4.1.6/debian/patches/CVE-2019-10203.patch pdns-4.1.6/debian/patches/CVE-2019-10203.patch --- pdns-4.1.6/debian/patches/CVE-2019-10203.patch 1970-01-01 00:00:00.000000000 +0000 +++ pdns-4.1.6/debian/patches/CVE-2019-10203.patch 2020-09-22 19:07:45.000000000 +0000 @@ -0,0 +1,54 @@ +From 6b48327a0da913d8eeb1c1a4938d3f22d80f9fb3 Mon Sep 17 00:00:00 2001 +From: Peter van Dijk <peter.van.d...@powerdns.com> +Date: Tue, 30 Jul 2019 15:40:09 +0200 +Subject: [PATCH] adjust gpgsql schema for advisory 2019-06 + +--- + modules/gpgsqlbackend/4.1.10_to_4.1.11.schema.pgsql.sql | 1 + + modules/gpgsqlbackend/schema.pgsql.sql | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + create mode 100644 modules/gpgsqlbackend/4.1.10_to_4.1.11.schema.pgsql.sql + +diff --git a/modules/gpgsqlbackend/4.1.10_to_4.1.11.schema.pgsql.sql b/modules/gpgsqlbackend/4.1.10_to_4.1.11.schema.pgsql.sql +new file mode 100644 +index 0000000000..b0c2ee1efa +--- /dev/null ++++ b/modules/gpgsqlbackend/4.1.10_to_4.1.11.schema.pgsql.sql +@@ -0,0 +1 @@ ++ALTER TABLE domains ALTER notified_serial TYPE bigint USING CASE WHEN notified_serial >= 0 THEN notified_serial::bigint END; +diff --git a/modules/gpgsqlbackend/schema.pgsql.sql b/modules/gpgsqlbackend/schema.pgsql.sql +index b105d87951..cad35d5f19 100644 +--- a/modules/gpgsqlbackend/schema.pgsql.sql ++++ b/modules/gpgsqlbackend/schema.pgsql.sql +@@ -4,7 +4,7 @@ CREATE TABLE domains ( + master VARCHAR(128) DEFAULT NULL, + last_check INT DEFAULT NULL, + type VARCHAR(6) NOT NULL, +- notified_serial INT DEFAULT NULL, ++ notified_serial BIGINT DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) + ); + + +From 15b1f3607691e6b0443696d6edca40cc3a04bbb0 Mon Sep 17 00:00:00 2001 +From: tcely <tc...@users.noreply.github.com> +Date: Sun, 4 Aug 2019 05:12:30 -0400 +Subject: [PATCH] gpgsqlbackend: add missing schema file to Makefile + +--- + modules/gpgsqlbackend/Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/modules/gpgsqlbackend/Makefile.am b/modules/gpgsqlbackend/Makefile.am +index 8a820d516b..9e2f271702 100644 +--- a/modules/gpgsqlbackend/Makefile.am ++++ b/modules/gpgsqlbackend/Makefile.am +@@ -12,6 +12,7 @@ dist_doc_DATA = \ + schema.pgsql.sql \ + nodnssec-3.x_to_3.4.0_schema.pgsql.sql \ + dnssec-3.x_to_3.4.0_schema.pgsql.sql \ ++ 4.1.10_to_4.1.11.schema.pgsql.sql \ + 3.4.0_to_4.1.0_schema.pgsql.sql + + libgpgsqlbackend_la_SOURCES = \ diff -Nru pdns-4.1.6/debian/patches/CVE-2020-17482.patch pdns-4.1.6/debian/patches/CVE-2020-17482.patch --- pdns-4.1.6/debian/patches/CVE-2020-17482.patch 1970-01-01 00:00:00.000000000 +0000 +++ pdns-4.1.6/debian/patches/CVE-2020-17482.patch 2020-09-22 19:07:45.000000000 +0000 @@ -0,0 +1,153 @@ +From 3b88cb8c8cdd166b566ef7bd87f47732b2783f6a Mon Sep 17 00:00:00 2001 +From: Remi Gacogne <remi.gaco...@powerdns.com> +Date: Tue, 11 Aug 2020 11:25:06 +0200 +Subject: [PATCH 1/2] Raise an exception on invalid hex content in unknown + records + +Otherwise we can end up reading uninitialised memory from the stack, +possibly leaking information. +This is only an issue if the content is read from an untrusted source +and can be passed back to an attacker. +--- + pdns/dnsparser.cc | 24 ++++++++++++++++-------- + pdns/test-dnsrecords_cc.cc | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 48 insertions(+), 8 deletions(-) + +diff --git a/pdns/dnsparser.cc b/pdns/dnsparser.cc +index b6108d8c6b..3a4e193f01 100644 +--- a/pdns/dnsparser.cc ++++ b/pdns/dnsparser.cc +@@ -40,17 +40,25 @@ class UnknownRecordContent : public DNSRecordContent + // parse the input + vector<string> parts; + stringtok(parts, zone); +- if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) ) +- throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+std::to_string(parts.size())+": "+zone ); +- const string& relevant=(parts.size() > 2) ? parts[2] : ""; +- unsigned int total=pdns_stou(parts[1]); +- if(relevant.size() % 2 || relevant.size() / 2 != total) ++ // we need exactly 3 parts, except if the length field is set to 0 then we only need 2 ++ if (parts.size() != 3 && !(parts.size() == 2 && equals(parts[1], "0"))) { ++ throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got " + std::to_string(parts.size()) + ": " + zone); ++ } ++ ++ const string& relevant = (parts.size() > 2) ? parts[2] : ""; ++ unsigned int total = pdns_stou(parts[1]); ++ if (relevant.size() % 2 || (relevant.size() / 2) != total) { + throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str()); ++ } ++ + string out; +- out.reserve(total+1); +- for(unsigned int n=0; n < total; ++n) { ++ out.reserve(total + 1); ++ ++ for (unsigned int n = 0; n < total; ++n) { + int c; +- sscanf(relevant.c_str()+2*n, "%02x", &c); ++ if (sscanf(relevant.c_str()+2*n, "%02x", &c) != 1) { ++ throw MOADNSException("unable to read data at position " + std::to_string(2 * n) + " from unknown record of size " + std::to_string(relevant.size())); ++ } + out.append(1, (char)c); + } + +diff --git a/pdns/test-dnsrecords_cc.cc b/pdns/test-dnsrecords_cc.cc +index df4102a4fb..854de2125e 100644 +--- a/pdns/test-dnsrecords_cc.cc ++++ b/pdns/test-dnsrecords_cc.cc +@@ -327,4 +327,36 @@ BOOST_AUTO_TEST_CASE(test_opt_record_out) { + BOOST_CHECK_EQUAL(makeHexDump(std::string(pak.begin(),pak.end())), makeHexDump(packet)); + } + ++// special record test, because Unknown record types are the worst ++BOOST_AUTO_TEST_CASE(test_unknown_records_in) { ++ ++ auto validUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 42"); ++ ++ // we need at least two parts ++ BOOST_CHECK_THROW(auto notEnoughPartsUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\#"), MOADNSException); ++ ++ // two parts are OK when the RDATA size is 0, not OK otherwise ++ auto validEmptyUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 0"); ++ BOOST_CHECK_THROW(auto twoPartsNotZeroUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1"), MOADNSException); ++ ++ // RDATA length is not even ++ BOOST_CHECK_THROW(auto unevenUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 A"), MOADNSException); ++ ++ // RDATA length is not equal to the expected size ++ BOOST_CHECK_THROW(auto wrongRDATASizeUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 2 AA"), MOADNSException); ++ ++ // RDATA is invalid (invalid hex value) ++ try { ++ auto invalidRDATAUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 JJ"); ++ // we should not reach that code ++ BOOST_CHECK(false); ++ // but if we do let's see what we got (likely what was left over on the stack) ++ BOOST_CHECK_EQUAL(invalidRDATAUnknown->getZoneRepresentation(), "\\# 1 jj"); ++ } ++ catch (const MOADNSException& e) ++ { ++ // it's expected to end up there ++ } ++} ++ + BOOST_AUTO_TEST_SUITE_END() + +From 11e1d5c7b676c1f51365b54aada0af4f63852ea0 Mon Sep 17 00:00:00 2001 +From: Remi Gacogne <remi.gaco...@powerdns.com> +Date: Tue, 11 Aug 2020 14:07:32 +0200 +Subject: [PATCH 2/2] Raise an exception on invalid first part (!= \#) in + unknown records + +--- + pdns/dnsparser.cc | 12 ++++++++---- + pdns/test-dnsrecords_cc.cc | 3 +++ + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/pdns/dnsparser.cc b/pdns/dnsparser.cc +index 3a4e193f01..356e4a6cef 100644 +--- a/pdns/dnsparser.cc ++++ b/pdns/dnsparser.cc +@@ -41,12 +41,16 @@ class UnknownRecordContent : public DNSRecordContent + vector<string> parts; + stringtok(parts, zone); + // we need exactly 3 parts, except if the length field is set to 0 then we only need 2 +- if (parts.size() != 3 && !(parts.size() == 2 && equals(parts[1], "0"))) { ++ if (parts.size() != 3 && !(parts.size() == 2 && equals(parts.at(1), "0"))) { + throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got " + std::to_string(parts.size()) + ": " + zone); + } + +- const string& relevant = (parts.size() > 2) ? parts[2] : ""; +- unsigned int total = pdns_stou(parts[1]); ++ if (parts.at(0) != "\\#") { ++ throw MOADNSException("Unknown record was stored incorrectly, first part should be '\\#', got '" + parts.at(0) + "'"); ++ } ++ ++ const string& relevant = (parts.size() > 2) ? parts.at(2) : ""; ++ unsigned int total = pdns_stou(parts.at(1)); + if (relevant.size() % 2 || (relevant.size() / 2) != total) { + throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str()); + } +@@ -56,7 +60,7 @@ class UnknownRecordContent : public DNSRecordContent + + for (unsigned int n = 0; n < total; ++n) { + int c; +- if (sscanf(relevant.c_str()+2*n, "%02x", &c) != 1) { ++ if (sscanf(&relevant.at(2*n), "%02x", &c) != 1) { + throw MOADNSException("unable to read data at position " + std::to_string(2 * n) + " from unknown record of size " + std::to_string(relevant.size())); + } + out.append(1, (char)c); +diff --git a/pdns/test-dnsrecords_cc.cc b/pdns/test-dnsrecords_cc.cc +index 854de2125e..770102f1fd 100644 +--- a/pdns/test-dnsrecords_cc.cc ++++ b/pdns/test-dnsrecords_cc.cc +@@ -339,6 +339,9 @@ BOOST_AUTO_TEST_CASE(test_unknown_records_in) { + auto validEmptyUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 0"); + BOOST_CHECK_THROW(auto twoPartsNotZeroUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1"), MOADNSException); + ++ // the first part has to be "\#" ++ BOOST_CHECK_THROW(auto invalidFirstPartUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\$ 0"), MOADNSException); ++ + // RDATA length is not even + BOOST_CHECK_THROW(auto unevenUnknown = DNSRecordContent::mastermake(static_cast<QType::typeenum>(65534), QClass::IN, "\\# 1 A"), MOADNSException); + diff -Nru pdns-4.1.6/debian/patches/series pdns-4.1.6/debian/patches/series --- pdns-4.1.6/debian/patches/series 2019-06-21 19:07:07.000000000 +0000 +++ pdns-4.1.6/debian/patches/series 2020-09-22 19:07:45.000000000 +0000 @@ -1,3 +1,5 @@ CVE-2019-3871-auth-4.1.6.patch CVE-2019-10162-4.1.8-invalidrecords.patch CVE-2019-10163-4.1.8-busyloop.patch +CVE-2019-10203.patch +CVE-2020-17482.patch