summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/.gitlab-ci.yml5
-rw-r--r--debian/changelog13
-rw-r--r--debian/gbp.conf4
-rw-r--r--debian/patches/0039-CVE-2023-2828.patch159
-rw-r--r--debian/patches/series1
-rw-r--r--debian/tests/control10
-rwxr-xr-xdebian/tests/simpletest18
-rw-r--r--debian/tests/validation28
8 files changed, 221 insertions, 17 deletions
diff --git a/debian/.gitlab-ci.yml b/debian/.gitlab-ci.yml
new file mode 100644
index 0000000..c4b0edf
--- /dev/null
+++ b/debian/.gitlab-ci.yml
@@ -0,0 +1,5 @@
+include:
+ - https://salsa.debian.org/lts-team/pipeline/raw/master/recipes/buster.yml
+
+variables:
+ SALSA_CI_BLHC_ARGS: --ignore-flag -D_FORTIFY_SOURCE=2
diff --git a/debian/changelog b/debian/changelog
index 5859a09..2606883 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+bind9 (1:9.11.5.P4+dfsg-5.1+deb10u9) buster-security; urgency=high
+
+ * Non-maintainer upload by the Debian LTS Team.
+ * CVE-2023-2828: It was discovered that the effectiveness of the
+ cache-cleaning algorithm used in named(5) can be severely diminished by
+ querying the resolver for specific RRsets in a certain order, effectively
+ allowing the configured max-cache-size limit to be significantly exceeded.
+ * Add debian/.gitlab-ci.yml
+ * Allow blhc failures; "CPPFLAGS missing", etc.
+ * Backport a1dbd6d68 and ef4eef07f4 from bind9.git to make autopkgtests pass.
+
+ -- Chris Lamb <lamby@debian.org> Fri, 07 Jul 2023 17:14:33 +0100
+
bind9 (1:9.11.5.P4+dfsg-5.1+deb10u8) buster-security; urgency=medium
* Non-maintainer upload by the LTS Team.
diff --git a/debian/gbp.conf b/debian/gbp.conf
deleted file mode 100644
index bddd585..0000000
--- a/debian/gbp.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-debian-branch = debian/buster
-pristine-tar = True
-upstream-branch = upstream/buster
diff --git a/debian/patches/0039-CVE-2023-2828.patch b/debian/patches/0039-CVE-2023-2828.patch
new file mode 100644
index 0000000..48aa263
--- /dev/null
+++ b/debian/patches/0039-CVE-2023-2828.patch
@@ -0,0 +1,159 @@
+---
+ lib/dns/rbtdb.c | 106 +++++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 63 insertions(+), 43 deletions(-)
+
+diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
+index b1b928c..3165e26 100644
+--- a/lib/dns/rbtdb.c
++++ b/lib/dns/rbtdb.c
+@@ -792,7 +792,7 @@ static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
+ static void expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
+ bool tree_locked, expire_t reason);
+ static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,
+- isc_stdtime_t now, bool tree_locked);
++ size_t purgesize, bool tree_locked);
+ static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx,
+ rdatasetheader_t *newheader);
+ static void resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
+@@ -6784,6 +6784,16 @@ addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
+
+ static dns_dbmethods_t zone_methods;
+
++static size_t
++rdataset_size(rdatasetheader_t *header) {
++ if (!NONEXISTENT(header)) {
++ return (dns_rdataslab_size((unsigned char *)header,
++ sizeof(*header)));
++ }
++
++ return (sizeof(*header));
++}
++
+ static isc_result_t
+ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+@@ -6932,7 +6942,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ }
+
+ if (cache_is_overmem)
+- overmem_purge(rbtdb, rbtnode->locknum, now, tree_locked);
++ overmem_purge(rbtdb, rbtnode->locknum, rdataset_size(newheader),
++ tree_locked);
+
+ NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+ isc_rwlocktype_write);
+@@ -6947,9 +6958,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ cleanup_dead_nodes(rbtdb, rbtnode->locknum);
+
+ header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1);
+- if (header && header->rdh_ttl < now - RBTDB_VIRTUAL)
+- expire_header(rbtdb, header, tree_locked,
+- expire_ttl);
++ if (header != NULL) {
++ dns_ttl_t rdh_ttl = header->rdh_ttl;
++
++ if (rdh_ttl < now - RBTDB_VIRTUAL) {
++ expire_header(rbtdb, header, tree_locked,
++ expire_ttl);
++ }
++ }
+
+ /*
+ * If we've been holding a write lock on the tree just for
+@@ -10388,54 +10404,58 @@ update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
+ ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum], header, link);
+ }
+
++static size_t
++expire_lru_headers(dns_rbtdb_t *rbtdb, unsigned int locknum, size_t purgesize,
++ bool tree_locked) {
++ rdatasetheader_t *header, *header_prev;
++ size_t purged = 0;
++
++ for (header = ISC_LIST_TAIL(rbtdb->rdatasets[locknum]);
++ header != NULL && purged <= purgesize; header = header_prev)
++ {
++ header_prev = ISC_LIST_PREV(header, link);
++ /*
++ * Unlink the entry at this point to avoid checking it
++ * again even if it's currently used someone else and
++ * cannot be purged at this moment. This entry won't be
++ * referenced any more (so unlinking is safe) since the
++ * TTL was reset to 0.
++ */
++ ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header, link);
++ size_t header_size = rdataset_size(header);
++ expire_header(rbtdb, header, tree_locked, expire_lru);
++ purged += header_size;
++ }
++
++ return (purged);
++}
++
+ /*%
+- * Purge some expired and/or stale (i.e. unused for some period) cache entries
+- * under an overmem condition. To recover from this condition quickly, up to
+- * 2 entries will be purged. This process is triggered while adding a new
+- * entry, and we specifically avoid purging entries in the same LRU bucket as
+- * the one to which the new entry will belong. Otherwise, we might purge
+- * entries of the same name of different RR types while adding RRsets from a
+- * single response (consider the case where we're adding A and AAAA glue records
+- * of the same NS name).
+- */
++ * Purge some stale (i.e. unused for some period - LRU based cleaning) cache
++ * entries under the overmem condition. To recover from this condition quickly,
++ * we cleanup entries up to the size of newly added rdata (passed as purgesize).
++ *
++ * This process is triggered while adding a new entry, and we specifically avoid
++ * purging entries in the same LRU bucket as the one to which the new entry will
++ * belong. Otherwise, we might purge entries of the same name of different RR
++ * types while adding RRsets from a single response (consider the case where
++ * we're adding A and AAAA glue records of the same NS name).
++*/
+ static void
+-overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,
+- isc_stdtime_t now, bool tree_locked)
++overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, size_t purgesize,
++ bool tree_locked)
+ {
+- rdatasetheader_t *header, *header_prev;
+ unsigned int locknum;
+- int purgecount = 2;
++ size_t purged = 0;
+
+ for (locknum = (locknum_start + 1) % rbtdb->node_lock_count;
+- locknum != locknum_start && purgecount > 0;
++ locknum != locknum_start && purged <= purgesize;
+ locknum = (locknum + 1) % rbtdb->node_lock_count) {
+ NODE_LOCK(&rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
+
+- header = isc_heap_element(rbtdb->heaps[locknum], 1);
+- if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) {
+- expire_header(rbtdb, header, tree_locked,
+- expire_ttl);
+- purgecount--;
+- }
+-
+- for (header = ISC_LIST_TAIL(rbtdb->rdatasets[locknum]);
+- header != NULL && purgecount > 0;
+- header = header_prev) {
+- header_prev = ISC_LIST_PREV(header, link);
+- /*
+- * Unlink the entry at this point to avoid checking it
+- * again even if it's currently used someone else and
+- * cannot be purged at this moment. This entry won't be
+- * referenced any more (so unlinking is safe) since the
+- * TTL was reset to 0.
+- */
+- ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header,
+- link);
+- expire_header(rbtdb, header, tree_locked,
+- expire_lru);
+- purgecount--;
+- }
++ purged += expire_lru_headers(rbtdb, locknum, purgesize - purged,
++ tree_locked);
+
+ NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
+ isc_rwlocktype_write);
diff --git a/debian/patches/series b/debian/patches/series
index ee6bb91..238f7b9 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -36,3 +36,4 @@
0036-CVE-2022-2795.patch
0037-CVE-2022-38177.patch
0038-CVE-2022-38178.patch
+0039-CVE-2023-2828.patch
diff --git a/debian/tests/control b/debian/tests/control
index 2fad418..d086b28 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -1,3 +1,9 @@
Tests: simpletest
-Restrictions: needs-root, isolation-container
-Depends: bind9, dnsutils
+Restrictions: isolation-container, needs-internet, needs-root
+Depends: bind9,
+ dnsutils
+
+Tests: validation
+Restrictions: isolation-container, needs-internet, needs-root, flaky
+Depends: bind9,
+ dnsutils
diff --git a/debian/tests/simpletest b/debian/tests/simpletest
index 468a7c5..10951e7 100755
--- a/debian/tests/simpletest
+++ b/debian/tests/simpletest
@@ -2,25 +2,21 @@
set -e
-setup() {
+setup() (
service bind9 stop
service bind9 start
-}
+ sleep 1
+)
-run() {
+run() (
# Make a query against a local zone
dig -x 127.0.0.1 @127.0.0.1
+)
- # Make a query against an external nameserver and check for DNSSEC validation
- echo "Checking for DNSSEC validation status of internetsociety.org"
- dig -t a internetsociety.org @127.0.0.1 | egrep 'flags:.+ad; QUERY'
-}
-
-teardown() {
+teardown() (
service bind9 stop
-}
+)
setup
run
teardown
-
diff --git a/debian/tests/validation b/debian/tests/validation
new file mode 100644
index 0000000..bf10e12
--- /dev/null
+++ b/debian/tests/validation
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+
+setup() (
+ service bind9 stop
+ service bind9 start
+)
+
+run() (
+ repeats=10
+ while [ "${repeats}" -gt "0" ]; do
+ # Make a query against an external nameserver and check for DNSSEC validation
+ echo "Checking for DNSSEC validation status of internetsociety.org"
+ dig -t a internetsociety.org @127.0.0.1 | grep -E 'flags:.+ad; QUERY' && break
+ repeats=$((repeats-1))
+ sleep 1
+ done
+ [ "$repeats" -eq "0" ] && exit 1
+)
+
+teardown() (
+ service bind9 stop
+)
+
+setup
+run
+teardown