diff options
Diffstat (limited to '')
36 files changed, 5032 insertions, 0 deletions
diff --git a/debian/patches/0001-non-linux.diff b/debian/patches/0001-non-linux.diff new file mode 100644 index 0000000..9a5c95f --- /dev/null +++ b/debian/patches/0001-non-linux.diff @@ -0,0 +1,42 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:53 +0000 +Subject: _non-linux + + FTBFS on kfreebsd, hurd + + Addresses-Debian-Bug: 741285, 746540 + Signed-off-by: LaMont Jones <lamont@debian.org> +--- + configure.in | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/configure.in b/configure.in +index 9aa7e2d..bf028fe 100644 +--- a/configure.in ++++ b/configure.in +@@ -462,7 +462,7 @@ case "$host" in + # as it breaks how the two halves (Basic and Advanced) of the IPv6 + # Socket API were designed to be used but we have to live with it. + # Define _GNU_SOURCE to pull in the IPv6 Advanced Socket API. +- *-linux* | *-kfreebsd*-gnu*) ++ *-linux* | *-kfreebsd*-gnu* | *-gnu*) + STD_CDEFINES="$STD_CDEFINES -D_GNU_SOURCE" + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + ;; +@@ -1327,7 +1327,7 @@ then + # LinuxThreads requires some changes to the way we + # deal with signals. + # +- *-linux*) ++ *-linux*|*-kfreebsd*-gnu) + AC_DEFINE(HAVE_LINUXTHREADS) + ;; + # +@@ -2780,7 +2780,6 @@ case "$host" in + ;; + *) + AC_CHECK_LIB(socket, socket) +- AC_CHECK_LIB(nsl, inet_addr) + ;; + esac + diff --git a/debian/patches/0002-multiarch.diff b/debian/patches/0002-multiarch.diff new file mode 100644 index 0000000..3ba24f4 --- /dev/null +++ b/debian/patches/0002-multiarch.diff @@ -0,0 +1,29 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:53 +0000 +Subject: _multiarch + +--- + isc-config.sh.in | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/isc-config.sh.in b/isc-config.sh.in +index a8a0a89..1e7903e 100644 +--- a/isc-config.sh.in ++++ b/isc-config.sh.in +@@ -13,7 +13,6 @@ prefix=@prefix@ + exec_prefix=@exec_prefix@ + exec_prefix_set= + includedir=@includedir@ +-libdir=@libdir@ + + usage() + { +@@ -132,7 +131,7 @@ if test x"$echo_libs" = x"true"; then + if test x"${exec_prefix_set}" = x"true"; then + libs="-L${exec_prefix}/lib" + else +- libs="-L${libdir}" ++ libs= + fi + if test x"$libirs" = x"true" ; then + libs="$libs -lirs" diff --git a/debian/patches/0003-min-cache-ttl.diff b/debian/patches/0003-min-cache-ttl.diff new file mode 100644 index 0000000..13453fd --- /dev/null +++ b/debian/patches/0003-min-cache-ttl.diff @@ -0,0 +1,254 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _min-cache-ttl + + Add min-cache-ttl and min-ncache-ttl keywords + + Sometimes it is useful to set a 'floor' on the TTL for records + to be cached. Some sites like to use ridiculously low TTLs for + some reason, and that often is not compatible with slow links. + + Signed-off-by: Michael Milligan <milli@acmeps.com> + Signed-off-by: LaMont Jones <lamont@debian.org> +--- + bin/named/config.c | 2 ++ + bin/named/server.c | 12 ++++++++++++ + bin/tests/named.conf | 2 ++ + lib/dns/include/dns/ncache.h | 6 ++++-- + lib/dns/include/dns/view.h | 2 ++ + lib/dns/ncache.c | 18 ++++++++++++------ + lib/dns/resolver.c | 22 ++++++++++++++++------ + lib/isccfg/namedconf.c | 2 ++ + 8 files changed, 52 insertions(+), 14 deletions(-) + +diff --git a/bin/named/config.c b/bin/named/config.c +index 2732a8f..d22ee4b 100644 +--- a/bin/named/config.c ++++ b/bin/named/config.c +@@ -182,6 +182,8 @@ options {\n\ + max-recursion-depth 7;\n\ + max-recursion-queries 75;\n\ + message-compression yes;\n\ ++ min-ncache-ttl 0; /* 0 hours */\n\ ++ min-cache-ttl 0; /* 0 seconds */\n\ + # min-roots <obsolete>;\n\ + minimal-any false;\n\ + minimal-responses false;\n\ +diff --git a/bin/named/server.c b/bin/named/server.c +index 7f87ccf..149458e 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -3706,6 +3706,18 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, + if (view->maxncachettl > 7 * 24 * 3600) + view->maxncachettl = 7 * 24 * 3600; + ++ obj = NULL; ++ result = ns_config_get(maps, "min-cache-ttl", &obj); ++ INSIST(result == ISC_R_SUCCESS); ++ view->mincachettl = cfg_obj_asuint32(obj); ++ ++ obj = NULL; ++ result = ns_config_get(maps, "min-ncache-ttl", &obj); ++ INSIST(result == ISC_R_SUCCESS); ++ view->minncachettl = cfg_obj_asuint32(obj); ++ if (view->minncachettl > 7 * 24 * 3600) ++ view->minncachettl = 7 * 24 * 3600; ++ + /* + * Configure the view's cache. + * +diff --git a/bin/tests/named.conf b/bin/tests/named.conf +index 5673e98..34435b6 100644 +--- a/bin/tests/named.conf ++++ b/bin/tests/named.conf +@@ -46,6 +46,7 @@ options { + memstatistics-file "named.memstats"; // _PATH_MEMSTATS + + max-cache-ttl 999; ++ min-cache-ttl 666; + auth-nxdomain yes; // always set AA on NXDOMAIN. + // don't set this to 'no' unless + // you know what you're doing -- older +@@ -148,6 +149,7 @@ options { + min-refresh-time 777; + + max-ncache-ttl 333; ++ min-ncache-ttl 222; + min-roots 15; + serial-queries 34; + +diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h +index 2942c26..c2e1e7b 100644 +--- a/lib/dns/include/dns/ncache.h ++++ b/lib/dns/include/dns/ncache.h +@@ -56,12 +56,14 @@ ISC_LANG_BEGINDECLS + + isc_result_t + dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, +- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, ++ dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + dns_rdataset_t *addedrdataset); + isc_result_t + dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, +- isc_stdtime_t now, dns_ttl_t maxttl, ++ isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, dns_rdataset_t *addedrdataset); + /*%< + * Convert the authority data from 'message' into a negative cache +diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h +index 8e21298..3b3ecc9 100644 +--- a/lib/dns/include/dns/view.h ++++ b/lib/dns/include/dns/view.h +@@ -153,6 +153,8 @@ struct dns_view { + bool sendcookie; + dns_ttl_t maxcachettl; + dns_ttl_t maxncachettl; ++ dns_ttl_t mincachettl; ++ dns_ttl_t minncachettl; + uint32_t nta_lifetime; + uint32_t nta_recheck; + char *nta_file; +diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c +index c5078de..9cde098 100644 +--- a/lib/dns/ncache.c ++++ b/lib/dns/ncache.c +@@ -45,7 +45,8 @@ + + static isc_result_t + addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, +- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, ++ dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, bool secure, + dns_rdataset_t *addedrdataset); + +@@ -95,26 +96,29 @@ copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { + + isc_result_t + dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, +- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, ++ dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + dns_rdataset_t *addedrdataset) + { +- return (addoptout(message, cache, node, covers, now, maxttl, ++ return (addoptout(message, cache, node, covers, now, minttl, maxttl, + false, false, addedrdataset)); + } + + isc_result_t + dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, +- isc_stdtime_t now, dns_ttl_t maxttl, ++ isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, dns_rdataset_t *addedrdataset) + { +- return (addoptout(message, cache, node, covers, now, maxttl, ++ return (addoptout(message, cache, node, covers, now, minttl, maxttl, + optout, true, addedrdataset)); + } + + static isc_result_t + addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, +- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, ++ dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, bool secure, + dns_rdataset_t *addedrdataset) + { +@@ -181,6 +185,8 @@ addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, + type == dns_rdatatype_nsec3) { + if (ttl > rdataset->ttl) + ttl = rdataset->ttl; ++ if (ttl < minttl) ++ ttl = minttl; + if (trust > rdataset->trust) + trust = rdataset->trust; + /* +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 0abf4de..1d76504 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -564,7 +564,9 @@ static bool fctx_unlink(fetchctx_t *fctx); + static isc_result_t ncache_adderesult(dns_message_t *message, + dns_db_t *cache, dns_dbnode_t *node, + dns_rdatatype_t covers, +- isc_stdtime_t now, dns_ttl_t maxttl, ++ isc_stdtime_t now, ++ dns_ttl_t minttl, ++ dns_ttl_t maxttl, + bool optout, + bool secure, + dns_rdataset_t *ardataset, +@@ -5015,7 +5017,7 @@ validated(isc_task_t *task, isc_event_t *event) { + ttl = 0; + + result = ncache_adderesult(fctx->rmessage, fctx->cache, node, +- covers, now, ttl, vevent->optout, ++ covers, now, fctx->res->view->minncachettl, ttl, vevent->optout, + vevent->secure, ardataset, &eresult); + if (result != ISC_R_SUCCESS) + goto noanswer_response; +@@ -5480,6 +5482,12 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, + rdataset->ttl = res->view->maxcachettl; + } + ++ /* ++ * Enforce configured minimum cache TTL. ++ */ ++ if (rdataset->ttl < res->view->mincachettl) ++ rdataset->ttl = res->view->mincachettl; ++ + /* + * Mark the rdataset as being prefetch eligible. + */ +@@ -5868,7 +5876,8 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) + */ + static isc_result_t + ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, +- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, ++ dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, bool secure, + dns_rdataset_t *ardataset, isc_result_t *eresultp) + { +@@ -5881,10 +5890,10 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, + } + if (secure) + result = dns_ncache_addoptout(message, cache, node, covers, +- now, maxttl, optout, ardataset); ++ now, minttl, maxttl, optout, ardataset); + else + result = dns_ncache_add(message, cache, node, covers, now, +- maxttl, ardataset); ++ minttl, maxttl, ardataset); + if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { + /* + * If the cache now contains a negative entry and we +@@ -6059,7 +6068,8 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, + ttl = 0; + + result = ncache_adderesult(fctx->rmessage, fctx->cache, node, +- covers, now, ttl, false, ++ covers, now, ttl, ++ fctx->res->view->minncachettl, false, + false, ardataset, &eresult); + if (result != ISC_R_SUCCESS) + goto unlock; +diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c +index cd797a6..fdaf8ff 100644 +--- a/lib/isccfg/namedconf.c ++++ b/lib/isccfg/namedconf.c +@@ -1780,6 +1780,8 @@ view_clauses[] = { + { "max-recursion-queries", &cfg_type_uint32, 0 }, + { "max-udp-size", &cfg_type_uint32, 0 }, + { "message-compression", &cfg_type_boolean, 0 }, ++ { "min-cache-ttl", &cfg_type_uint32, 0 }, ++ { "min-ncache-ttl", &cfg_type_uint32, 0 }, + { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, + { "minimal-any", &cfg_type_boolean, 0 }, + { "minimal-responses", &cfg_type_minimal, 0 }, diff --git a/debian/patches/0004-library_paths.diff b/debian/patches/0004-library_paths.diff new file mode 100644 index 0000000..abc8d66 --- /dev/null +++ b/debian/patches/0004-library_paths.diff @@ -0,0 +1,136 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _library_paths + + Makefile.in: be explicit about library paths + + Debian policy requires that all dependent libs be in the .so, not just the + immediately depended ones. + + Signed-off-by: LaMont Jones <lamont@debian.org> +--- + lib/dns/Makefile.in | 4 +++- + lib/irs/Makefile.in | 4 +++- + lib/isc/Makefile.in | 3 +++ + lib/isccc/Makefile.in | 4 +++- + lib/isccfg/Makefile.in | 2 +- + 5 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in +index 4a8549e..e0fcca4 100644 +--- a/lib/dns/Makefile.in ++++ b/lib/dns/Makefile.in +@@ -37,7 +37,7 @@ ISCLIBS = ../../lib/isc/libisc.@A@ + + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + +-LIBS = @LIBS@ ++LIBS = @LIBS@ -L../../lib/isc -lcrypto + + # Alphabetically + +@@ -155,6 +155,7 @@ libdns.la: ${OBJS} + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} ++ ln -sf .libs/libdns.so . + + include: gen + ${MAKE} include/dns/enumtype.h +@@ -206,6 +207,7 @@ clean distclean:: + newrr:: + rm -f code.h include/dns/enumtype.h include/dns/enumclass.h + rm -f include/dns/rdatastruct.h ++ rm -f libdns.so + + rdata.@O@: include + +diff --git a/lib/irs/Makefile.in b/lib/irs/Makefile.in +index fc11447..4bb85b1 100644 +--- a/lib/irs/Makefile.in ++++ b/lib/irs/Makefile.in +@@ -36,7 +36,7 @@ SRCS = context.c \ + gai_strerror.c getaddrinfo.c getnameinfo.c \ + resconf.c + +-LIBS = @LIBS@ ++LIBS = @LIBS@ -L../../lib/isc -L../../lib/dns -L../../lib/isccfg -lcrypto -lisc -ldns -lisccfg + + SUBDIRS = include + TESTDIRS = @UNITTESTS@ +@@ -61,6 +61,7 @@ libirs.la: ${OBJS} version.@O@ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libirs.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} version.@O@ ${LIBS} ++ ln -sf .libs/libirs.so . + + timestamp: libirs.@A@ + touch timestamp +@@ -78,3 +79,4 @@ uninstall:: + + clean distclean:: + rm -f libirs.@A@ libirs.la timestamp ++ rm -f libdns.so +diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in +index ba53ef1..ba3f013 100644 +--- a/lib/isc/Makefile.in ++++ b/lib/isc/Makefile.in +@@ -120,12 +120,14 @@ libisc.la: ${OBJS} ${SYMTBLOBJS} + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${SYMTBLOBJS} ${LIBS} ++ ln -sf .libs/libisc.so . + + libisc-nosymtbl.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} ++ ln -sf .libs/libisc-nosymtbl.so . + + timestamp: libisc.@A@ libisc-nosymtbl.@A@ + touch timestamp +@@ -144,3 +146,4 @@ uninstall:: + clean distclean:: + rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \ + libisc-nosymtbl.la timestamp ++ rm -f libisc.so libisc-nosymtbl.so +diff --git a/lib/isccc/Makefile.in b/lib/isccc/Makefile.in +index ca88e98..8d875bc 100644 +--- a/lib/isccc/Makefile.in ++++ b/lib/isccc/Makefile.in +@@ -31,7 +31,7 @@ ISCCCLIBS = ../../lib/isccc/libisccc.@A@ + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + ISCCCDEPLIBS = libisccc.@A@ + +-LIBS = @LIBS@ ++LIBS = @LIBS@ -L../../lib/isc + + SUBDIRS = include + +@@ -67,6 +67,7 @@ libisccc.la: ${OBJS} + ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccc.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${ISCLIBS} ${LIBS} ++ ln -sf .libs/libisccc.so . + + timestamp: libisccc.@A@ + touch timestamp +@@ -82,3 +83,4 @@ uninstall:: + + clean distclean:: + rm -f libisccc.@A@ timestamp ++ rm -f libisccc.so +diff --git a/lib/isccfg/Makefile.in b/lib/isccfg/Makefile.in +index f459bd5..0c42b2a 100644 +--- a/lib/isccfg/Makefile.in ++++ b/lib/isccfg/Makefile.in +@@ -29,7 +29,7 @@ ISCCFGLIBS = ../../lib/cfg/libisccfg.@A@ + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + ISCCFGDEPLIBS = libisccfg.@A@ + +-LIBS = @LIBS@ ++LIBS = @LIBS@ -L../dns -L../isc -L../isccc + + SUBDIRS = include + TESTDIRS = @UNITTESTS@ diff --git a/debian/patches/0005-resource_missing_include.diff b/debian/patches/0005-resource_missing_include.diff new file mode 100644 index 0000000..cc1fe91 --- /dev/null +++ b/debian/patches/0005-resource_missing_include.diff @@ -0,0 +1,24 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _resource_missing_include + + lib/isc/unix/resource.c was missing inttypes.h include. + + Addresses-Ubuntu-Bug: 674199 + Signed-off-by: LaMont Jones <lamont@debian.org> +--- + lib/isc/unix/resource.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/isc/unix/resource.c b/lib/isc/unix/resource.c +index 6d5c5aa..a4302c6 100644 +--- a/lib/isc/unix/resource.c ++++ b/lib/isc/unix/resource.c +@@ -25,6 +25,7 @@ + #include <isc/util.h> + + #ifdef __linux__ ++#include <inttypes.h> + #include <linux/fs.h> /* To get the large NR_OPEN. */ + #endif + diff --git a/debian/patches/0006-prepare_native_pkcs11.diff b/debian/patches/0006-prepare_native_pkcs11.diff new file mode 100644 index 0000000..9cd63b6 --- /dev/null +++ b/debian/patches/0006-prepare_native_pkcs11.diff @@ -0,0 +1,246 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _prepare_native_pkcs11 + +--- + bin/Makefile.in | 2 +- + bin/dnssec/Makefile.in | 2 +- + bin/named/Makefile.in | 2 +- + bin/pkcs11/Makefile.in | 6 +++--- + configure.in | 51 +++++++++++++++++++++++++++++++++++--------------- + lib/Makefile.in | 2 +- + make/includes.in | 10 ++++++++++ + 7 files changed, 53 insertions(+), 22 deletions(-) + +diff --git a/bin/Makefile.in b/bin/Makefile.in +index f0c504a..ef6bf5f 100644 +--- a/bin/Makefile.in ++++ b/bin/Makefile.in +@@ -11,7 +11,7 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-SUBDIRS = named rndc dig delv dnssec tools nsupdate check confgen \ ++SUBDIRS = named named-pkcs11 rndc dig delv dnssec dnssec-pkcs11 tools nsupdate check confgen \ + @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ tests + TARGETS = + +diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in +index 2239ad1..1ded1fa 100644 +--- a/bin/dnssec/Makefile.in ++++ b/bin/dnssec/Makefile.in +@@ -19,7 +19,7 @@ VERSION=@BIND9_VERSION@ + + CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = -DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \ ++CDEFINES = -DVERSION=\"${VERSION}\" \ + @CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\" + CWARNINGS = + +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index 1c41397..5e6e84c 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -47,7 +47,7 @@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@ ++CDEFINES = @CONTRIB_DLZ@ @CRYPTO@ + + CWARNINGS = + +diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in +index ae90616..4bc1256 100644 +--- a/bin/pkcs11/Makefile.in ++++ b/bin/pkcs11/Makefile.in +@@ -15,13 +15,13 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = ${ISC_INCLUDES} ++CINCLUDES = ${ISC_PKCS11_INCLUDES} + + CDEFINES = + +-ISCLIBS = ../../lib/isc/libisc.@A@ @ISC_OPENSSL_LIBS@ ++ISCLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ @ISC_OPENSSL_LIBS@ + +-ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++ISCDEPLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + + DEPLIBS = ${ISCDEPLIBS} + +diff --git a/configure.in b/configure.in +index bf028fe..f8603b8 100644 +--- a/configure.in ++++ b/configure.in +@@ -1109,12 +1109,14 @@ AC_SUBST(USE_GSSAPI) + AC_SUBST(DST_GSSAPI_INC) + AC_SUBST(DNS_GSSAPI_LIBS) + DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS" ++DNS_CRYPTO_PK11_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_PK11_LIBS" + + # + # Applications linking with libdns also need to link with these libraries. + # + + AC_SUBST(DNS_CRYPTO_LIBS) ++AC_SUBST(DNS_CRYPTO_PK11_LIBS) + + # + # was --with-randomdev specified? +@@ -1499,11 +1501,6 @@ fi + AC_MSG_CHECKING(for OpenSSL library) + OPENSSL_WARNING= + openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw" +-if test "yes" = "$want_native_pkcs11" +-then +- use_openssl="native_pkcs11" +- AC_MSG_RESULT(use of native PKCS11 instead) +-fi + + if test "auto" = "$use_openssl" + then +@@ -1516,6 +1513,7 @@ then + fi + done + fi ++CRYPTO_PK11="" + OPENSSL_ECDSA="" + OPENSSL_GOST="" + OPENSSL_ED25519="" +@@ -1537,11 +1535,10 @@ case "$with_gost" in + ;; + esac + +-case "$use_openssl" in +- native_pkcs11) +- AC_MSG_RESULT(disabled because of native PKCS11) ++if test "$want_native_pkcs11" = "yes" ++then + DST_OPENSSL_INC="" +- CRYPTO="-DPKCS11CRYPTO" ++ CRYPTO_PK11="-DPKCS11CRYPTO" + OPENSSLECDSALINKOBJS="" + OPENSSLECDSALINKSRCS="" + OPENSSLEDDSALINKOBJS="" +@@ -1550,7 +1547,9 @@ case "$use_openssl" in + OPENSSLGOSTLINKSRCS="" + OPENSSLLINKOBJS="" + OPENSSLLINKSRCS="" +- ;; ++fi ++ ++case "$use_openssl" in + no) + AC_MSG_RESULT(no) + DST_OPENSSL_INC="" +@@ -1580,11 +1579,6 @@ case "$use_openssl" in + If you don't want OpenSSL, use --without-openssl]) + ;; + *) +- if test "yes" = "$want_native_pkcs11" +- then +- AC_MSG_RESULT() +- AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.]) +- fi + if test "yes" = "$use_openssl" + then + # User did not specify a path - guess it +@@ -2007,6 +2001,7 @@ AC_SUBST(OPENSSL_ED25519) + AC_SUBST(OPENSSL_GOST) + + DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DST_OPENSSL_LIBS" ++DNS_CRYPTO_PK11_LIBS="$DNS_CRYPTO_LIBS" + + ISC_PLATFORM_WANTAES="#undef ISC_PLATFORM_WANTAES" + if test "yes" = "$with_aes" +@@ -2326,6 +2321,7 @@ esac + AC_SUBST(PKCS11LINKOBJS) + AC_SUBST(PKCS11LINKSRCS) + AC_SUBST(CRYPTO) ++AC_SUBST(CRYPTO_PK11) + AC_SUBST(PKCS11_ECDSA) + AC_SUBST(PKCS11_GOST) + AC_SUBST(PKCS11_ED25519) +@@ -5331,8 +5327,11 @@ AC_CONFIG_FILES([ + bin/delv/Makefile + bin/dig/Makefile + bin/dnssec/Makefile ++ bin/dnssec-pkcs11/Makefile + bin/named/Makefile + bin/named/unix/Makefile ++ bin/named-pkcs11/Makefile ++ bin/named-pkcs11/unix/Makefile + bin/nsupdate/Makefile + bin/pkcs11/Makefile + bin/python/Makefile +@@ -5406,6 +5405,10 @@ AC_CONFIG_FILES([ + lib/dns/include/dns/Makefile + lib/dns/include/dst/Makefile + lib/dns/tests/Makefile ++ lib/dns-pkcs11/Makefile ++ lib/dns-pkcs11/include/Makefile ++ lib/dns-pkcs11/include/dns/Makefile ++ lib/dns-pkcs11/include/dst/Makefile + lib/irs/Makefile + lib/irs/include/Makefile + lib/irs/include/irs/Makefile +@@ -5430,6 +5433,24 @@ AC_CONFIG_FILES([ + lib/isc/unix/include/Makefile + lib/isc/unix/include/isc/Makefile + lib/isc/unix/include/pkcs11/Makefile ++ lib/isc-pkcs11/$arch/Makefile ++ lib/isc-pkcs11/$arch/include/Makefile ++ lib/isc-pkcs11/$arch/include/isc/Makefile ++ lib/isc-pkcs11/$thread_dir/Makefile ++ lib/isc-pkcs11/$thread_dir/include/Makefile ++ lib/isc-pkcs11/$thread_dir/include/isc/Makefile ++ lib/isc-pkcs11/Makefile ++ lib/isc-pkcs11/include/Makefile ++ lib/isc-pkcs11/include/isc/Makefile ++ lib/isc-pkcs11/include/isc/platform.h ++ lib/isc-pkcs11/include/pk11/Makefile ++ lib/isc-pkcs11/include/pkcs11/Makefile ++ lib/isc-pkcs11/tests/Makefile ++ lib/isc-pkcs11/nls/Makefile ++ lib/isc-pkcs11/unix/Makefile ++ lib/isc-pkcs11/unix/include/Makefile ++ lib/isc-pkcs11/unix/include/isc/Makefile ++ lib/isc-pkcs11/unix/include/pkcs11/Makefile + lib/isccc/Makefile + lib/isccc/include/Makefile + lib/isccc/include/isccc/Makefile +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 81270a0..bcb5312 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -15,7 +15,7 @@ top_srcdir = @top_srcdir@ + # Attempt to disable parallel processing. + .NOTPARALLEL: + .NO_PARALLEL: +-SUBDIRS = isc isccc dns isccfg bind9 lwres irs samples ++SUBDIRS = isc isc-pkcs11 isccc dns dns-pkcs11 isccfg bind9 lwres irs samples + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/make/includes.in b/make/includes.in +index fa86ad1..3cfbe9f 100644 +--- a/make/includes.in ++++ b/make/includes.in +@@ -43,3 +43,13 @@ BIND9_INCLUDES = @BIND9_BIND9_BUILDINCLUDE@ \ + + TEST_INCLUDES = \ + -I${top_srcdir}/lib/tests/include ++ ++ISC_PKCS11_INCLUDES = @BIND9_ISC_BUILDINCLUDE@ \ ++ -I${top_srcdir}/lib/isc-pkcs11 \ ++ -I${top_srcdir}/lib/isc-pkcs11/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/unix/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/@ISC_THREAD_DIR@/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/@ISC_ARCH_DIR@/include ++ ++DNS_PKCS11_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \ ++ -I${top_srcdir}/lib/dns-pkcs11/include diff --git a/debian/patches/0007-ctxstart_no_sighandling.diff b/debian/patches/0007-ctxstart_no_sighandling.diff new file mode 100644 index 0000000..9304fea --- /dev/null +++ b/debian/patches/0007-ctxstart_no_sighandling.diff @@ -0,0 +1,22 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _ctxstart_no_sighandling + +--- + lib/isc/unix/app.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c +index 7e5a0ee..8574141 100644 +--- a/lib/isc/unix/app.c ++++ b/lib/isc/unix/app.c +@@ -262,6 +262,9 @@ isc__app_ctxstart(isc_appctx_t *ctx0) { + ctx->want_reload = false; + ctx->blocked = false; + ++ if (!isc_bind9) ++ return (ISC_R_SUCCESS); ++ + #ifndef HAVE_SIGWAIT + /* + * Install do-nothing handlers for SIGINT and SIGTERM. diff --git a/debian/patches/0008-reproducible_build.diff b/debian/patches/0008-reproducible_build.diff new file mode 100644 index 0000000..94d8b58 --- /dev/null +++ b/debian/patches/0008-reproducible_build.diff @@ -0,0 +1,68 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:54 +0000 +Subject: _reproducible_build + +--- + lib/dns/gen.c | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/lib/dns/gen.c b/lib/dns/gen.c +index 2a3b94b..b26a509 100644 +--- a/lib/dns/gen.c ++++ b/lib/dns/gen.c +@@ -32,6 +32,8 @@ + #include <stdlib.h> + #include <string.h> + #include <time.h> ++#include <errno.h> ++#include <limits.h> + + #ifdef WIN32 + #include "gen-win32.h" +@@ -528,6 +530,9 @@ main(int argc, char **argv) { + char *prefix = NULL; + char *suffix = NULL; + char *file = NULL; ++ char *source_date_epoch; ++ unsigned long long epoch; ++ char *endptr; + isc_dir_t dir; + + for (i = 0; i < TYPENAMES; i++) +@@ -618,8 +623,34 @@ main(int argc, char **argv) { + INSIST(n > 0 && (unsigned)n < sizeof(srcdir)); + sd(0, "", buf, filetype); + +- if (time(&now) != -1) { +- if ((tm = localtime(&now)) != NULL && tm->tm_year > 104) { ++ source_date_epoch = getenv("SOURCE_DATE_EPOCH"); ++ if (source_date_epoch) { ++ errno = 0; ++ epoch = strtoull(source_date_epoch, &endptr, 10); ++ if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) ++ || (errno != 0 && epoch == 0)) { ++ fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n", strerror(errno)); ++ exit(EXIT_FAILURE); ++ } ++ if (endptr == source_date_epoch) { ++ fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n", endptr); ++ exit(EXIT_FAILURE); ++ } ++ if (*endptr != '\0') { ++ fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n", endptr); ++ exit(EXIT_FAILURE); ++ } ++ if (epoch > ULONG_MAX) { ++ fprintf(stderr, "Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to: %lu but was found to be: %llu \n", ULONG_MAX, epoch); ++ exit(EXIT_FAILURE); ++ } ++ now = epoch; ++ } else { ++ time(&now); ++ } ++ ++ if (now != -1) { ++ if ((tm = gmtime(&now)) != NULL && tm->tm_year > 104) { + n = snprintf(year, sizeof(year), "-%d", + tm->tm_year + 1900); + INSIST(n > 0 && (unsigned)n < sizeof(year)); diff --git a/debian/patches/0009-Add_--install-layout=deb_to_setup.py_call.patch b/debian/patches/0009-Add_--install-layout=deb_to_setup.py_call.patch new file mode 100644 index 0000000..d64e51d --- /dev/null +++ b/debian/patches/0009-Add_--install-layout=deb_to_setup.py_call.patch @@ -0,0 +1,24 @@ +From: Debian DNS Packaging <pkg-dns-devel@lists.alioth.debian.org> +Date: Fri, 24 Nov 2017 16:26:55 +0000 +Subject: Add_--install-layout=deb_to_setup.py_call + +--- + bin/python/Makefile.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/bin/python/Makefile.in b/bin/python/Makefile.in +index aa678d4..a58d72f 100644 +--- a/bin/python/Makefile.in ++++ b/bin/python/Makefile.in +@@ -56,9 +56,9 @@ install:: ${TARGETS} installdirs + ${INSTALL_DATA} ${srcdir}/dnssec-keymgr.8 ${DESTDIR}${mandir}/man8 + if test -n "${PYTHON}" ; then \ + if test -n "${DESTDIR}" ; then \ +- ${PYTHON} ${srcdir}/setup.py install --root=${DESTDIR} --prefix=${prefix} @PYTHON_INSTALL_LIB@ ; \ ++ ${PYTHON} ${srcdir}/setup.py install --root=${DESTDIR} --prefix=${prefix} --install-layout=deb @PYTHON_INSTALL_LIB@ ; \ + else \ +- ${PYTHON} ${srcdir}/setup.py install --prefix=${prefix} @PYTHON_INSTALL_LIB@ ; \ ++ ${PYTHON} ${srcdir}/setup.py install --prefix=${prefix} --install-layout=deb @PYTHON_INSTALL_LIB@ ; \ + fi ; \ + rm -rf build ; \ + fi diff --git a/debian/patches/0010-skip-rtld-deepbind-for-dyndb.diff b/debian/patches/0010-skip-rtld-deepbind-for-dyndb.diff new file mode 100644 index 0000000..4455d46 --- /dev/null +++ b/debian/patches/0010-skip-rtld-deepbind-for-dyndb.diff @@ -0,0 +1,24 @@ +From: BIND 9 Package <bind9@package.debian.org> +Date: Fri, 31 Aug 2018 08:42:51 +0000 +Subject: skip-rtld-deepbind-for-dyndb + +https://bugzilla.redhat.com/show_bug.cgi?id=1410433 +https://bugs.launchpad.net/bugs/1769440 +--- + lib/dns/dyndb.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c +index 93ad795..11ba0f5 100644 +--- a/lib/dns/dyndb.c ++++ b/lib/dns/dyndb.c +@@ -133,9 +133,6 @@ load_library(isc_mem_t *mctx, const char *filename, const char *instname, + instname, filename); + + flags = RTLD_NOW|RTLD_LOCAL; +-#ifdef RTLD_DEEPBIND +- flags |= RTLD_DEEPBIND; +-#endif + + handle = dlopen(filename, flags); + if (handle == NULL) diff --git a/debian/patches/0011-keymgr-dont-immediately-delete.diff b/debian/patches/0011-keymgr-dont-immediately-delete.diff new file mode 100644 index 0000000..e0a9cb8 --- /dev/null +++ b/debian/patches/0011-keymgr-dont-immediately-delete.diff @@ -0,0 +1,236 @@ +From: Debian DNS Team <team+dns@tracker.debian.org> +Date: Wed, 20 Nov 2019 22:17:10 +0100 +Subject: keymgr-dont-immediately-delete + +--- + bin/python/isc/keyseries.py.in | 28 ++++++++++++++++++-- + bin/tests/system/keymgr/19-old-keys/README | 7 +++++ + bin/tests/system/keymgr/19-old-keys/expect | 12 +++++++++ + bin/tests/system/keymgr/19-old-keys/extra.sh | 19 ++++++++++++++ + bin/tests/system/keymgr/19-old-keys/policy.conf | 18 +++++++++++++ + bin/tests/system/keymgr/clean.sh | 2 ++ + bin/tests/system/keymgr/setup.sh | 10 ++++++++ + bin/tests/system/keymgr/tests.sh | 34 +++++++++++++++---------- + 8 files changed, 114 insertions(+), 16 deletions(-) + create mode 100644 bin/tests/system/keymgr/19-old-keys/README + create mode 100644 bin/tests/system/keymgr/19-old-keys/expect + create mode 100644 bin/tests/system/keymgr/19-old-keys/extra.sh + create mode 100644 bin/tests/system/keymgr/19-old-keys/policy.conf + +diff --git a/bin/python/isc/keyseries.py.in b/bin/python/isc/keyseries.py.in +index e1241f0..74ccc64 100644 +--- a/bin/python/isc/keyseries.py.in ++++ b/bin/python/isc/keyseries.py.in +@@ -77,15 +77,39 @@ class keyseries: + a = key.activate() + if not p or p > now: + key.setpublish(now) ++ p = now + if not a or a > now: + key.setactivate(now) ++ a = now + ++ i = key.inactive() + if not rp: + key.setinactive(None, **kwargs) + key.setdelete(None, **kwargs) ++ elif not i or a + rp != i: ++ if not i and a + rp > now + prepub: ++ key.setinactive(a + rp, **kwargs) ++ key.setdelete(a + rp + postpub, **kwargs) ++ elif not i: ++ key.setinactive(now + prepub, **kwargs) ++ key.setdelete(now + prepub + postpub, **kwargs) ++ elif a + rp > i: ++ key.setinactive(a + rp, **kwargs) ++ key.setdelete(a + rp + postpub, **kwargs) ++ elif a + rp > now + prepub: ++ key.setinactive(a + rp, **kwargs) ++ key.setdelete(a + rp + postpub, **kwargs) ++ else: ++ key.setinactive(now + prepub, **kwargs) ++ key.setdelete(now + prepub + postpub, **kwargs) + else: +- key.setinactive(a + rp, **kwargs) +- key.setdelete(a + rp + postpub, **kwargs) ++ d = key.delete() ++ if not d or i + postpub > now: ++ key.setdelete(i + postpub, **kwargs) ++ elif not d: ++ key.setdelete(now + postpub, **kwargs) ++ elif d < i + postpub: ++ key.setdelete(i + postpub, **kwargs) + + if policy.keyttl != key.ttl: + key.setttl(policy.keyttl) +diff --git a/bin/tests/system/keymgr/19-old-keys/README b/bin/tests/system/keymgr/19-old-keys/README +new file mode 100644 +index 0000000..424b70c +--- /dev/null ++++ b/bin/tests/system/keymgr/19-old-keys/README +@@ -0,0 +1,7 @@ ++Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++ ++See COPYRIGHT in the source root or http://isc.org/copyright.html for terms. ++ ++This directory has a key set which is valid, but which was published ++and activated more than one rollover period ago. dnssec-keymgr should ++not mark the keys as already being inactive and deleted. +diff --git a/bin/tests/system/keymgr/19-old-keys/expect b/bin/tests/system/keymgr/19-old-keys/expect +new file mode 100644 +index 0000000..f3e49b3 +--- /dev/null ++++ b/bin/tests/system/keymgr/19-old-keys/expect +@@ -0,0 +1,12 @@ ++kargs="-c policy.conf example.com" ++kmatch="" ++kret=0 ++cargs="-d 1w -m 2w example.com" ++cmatch="4,Publish ++4,Activate ++2,Inactive ++2,Delete" ++cret=0 ++warn=0 ++error=0 ++ok=2 +diff --git a/bin/tests/system/keymgr/19-old-keys/extra.sh b/bin/tests/system/keymgr/19-old-keys/extra.sh +new file mode 100644 +index 0000000..8da6aa1 +--- /dev/null ++++ b/bin/tests/system/keymgr/19-old-keys/extra.sh +@@ -0,0 +1,19 @@ ++# Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++# ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++# ++# See the COPYRIGHT file distributed with this work for additional ++# information regarding copyright ownership. ++ ++now=`$PERL -e 'print time()."\n";'` ++for keyfile in K*.key; do ++ inactive=`$SETTIME -upI $keyfile | awk '{print $2}'` ++ if [ "$inactive" = UNSET ]; then ++ continue ++ elif [ "$inactive" -lt "$now" ]; then ++ echo_d "inactive date is in the past" ++ ret=1 ++ fi ++done +diff --git a/bin/tests/system/keymgr/19-old-keys/policy.conf b/bin/tests/system/keymgr/19-old-keys/policy.conf +new file mode 100644 +index 0000000..91817ff +--- /dev/null ++++ b/bin/tests/system/keymgr/19-old-keys/policy.conf +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ * ++ * See the COPYRIGHT file distributed with this work for additional ++ * information regarding copyright ownership. ++ */ ++ ++policy default { ++ policy global; ++ algorithm nsec3rsasha1; ++ pre-publish zsk 2w; ++ roll-period zsk 6mo; ++ coverage 364d; ++}; +diff --git a/bin/tests/system/keymgr/clean.sh b/bin/tests/system/keymgr/clean.sh +index dc9f0a0..3b9b1a2 100644 +--- a/bin/tests/system/keymgr/clean.sh ++++ b/bin/tests/system/keymgr/clean.sh +@@ -11,5 +11,7 @@ + + rm -f */K*.key + rm -f */K*.private ++rm -f Kexample.com.*.key ++rm -f Kexample.com.*.private + rm -f coverage.* keymgr.* + rm -f policy.out +diff --git a/bin/tests/system/keymgr/setup.sh b/bin/tests/system/keymgr/setup.sh +index 24e6c7c..ea6e566 100644 +--- a/bin/tests/system/keymgr/setup.sh ++++ b/bin/tests/system/keymgr/setup.sh +@@ -214,3 +214,13 @@ rm -f $dir/K*.private + ksk1=`$KEYGEN -K $dir -3fk example.com` + zsk1=`$KEYGEN -K $dir -3 example.com` + $SETTIME -K $dir -I now+2mo -D now+3mo $zsk1 > /dev/null ++ ++# Test 19: Key has been published/active a long time ++dir=19-old-keys ++echo_i "set up $dir" ++rm -f $dir/K*.key ++rm -f $dir/K*.private ++ksk1=`$KEYGEN -K $dir -a rsasha1 -3fk example.com` ++zsk1=`$KEYGEN -K $dir -a rsasha1 -3 example.com` ++$SETTIME -K $dir -P now-2y -A now-2y $ksk1 > /dev/null ++$SETTIME -K $dir -P now-2y -A now-2y $zsk1 > /dev/null +diff --git a/bin/tests/system/keymgr/tests.sh b/bin/tests/system/keymgr/tests.sh +index 88b43d9..89fedd3 100644 +--- a/bin/tests/system/keymgr/tests.sh ++++ b/bin/tests/system/keymgr/tests.sh +@@ -16,13 +16,19 @@ status=0 + n=1 + + matchall () { ++ match_result=ok + file=$1 +- echo "$2" | while read matchline; do +- grep "$matchline" $file > /dev/null 2>&1 || { +- echo "FAIL" +- return ++ while IFS="," read expect matchline; do ++ [ -z "$matchline" ] && continue ++ matches=`grep "$matchline" $file | wc -l` ++ [ "$matches" -ne "$expect" ] && { ++ echo "'$matchline': expected $expect found $matches" ++ return 1 + } +- done ++ done << EOF ++ $2 ++EOF ++ return 0 + } + + echo_i "checking for DNSSEC key coverage issues" +@@ -51,11 +57,8 @@ for dir in [0-9][0-9]-*; do + ret=1 + fi + +- found=`matchall keymgr.$n "$kmatch"` +- if [ "$found" = "FAIL" ]; then +- echo "no match on '$kmatch'" +- ret=1 +- fi ++ # check for matches in keymgr output ++ matchall keymgr.$n "$kmatch" || ret=1 + + # now check coverage + $COVERAGE -K $dir $cargs > coverage.$n 2>&1 +@@ -87,10 +90,13 @@ for dir in [0-9][0-9]-*; do + ret=1 + fi + +- found=`matchall coverage.$n "$cmatch"` +- if [ "$found" = "FAIL" ]; then +- echo "no match on '$cmatch'" +- ret=1 ++ # check for matches in coverage output ++ matchall coverage.$n "$cmatch" || ret=1 ++ ++ if [ -f $dir/extra.sh ]; then ++ cd $dir ++ . ./extra.sh ++ cd .. + fi + + n=`expr $n + 1` diff --git a/debian/patches/0012-CVE-2018-5743-Limiting-simultaneous-TCP-clients-is-i.patch b/debian/patches/0012-CVE-2018-5743-Limiting-simultaneous-TCP-clients-is-i.patch new file mode 100644 index 0000000..b451238 --- /dev/null +++ b/debian/patches/0012-CVE-2018-5743-Limiting-simultaneous-TCP-clients-is-i.patch @@ -0,0 +1,912 @@ +From: =?utf-8?q?Witold_Kr=C4=99cicki?= <wpk@isc.org> +Date: Thu, 3 Jan 2019 14:17:43 +0100 +Subject: [CVE-2018-5743]: Limiting simultaneous TCP clients is ineffective + +--- + bin/named/client.c | 427 ++++++++++++++++++++++++++------- + bin/named/include/named/client.h | 23 +- + bin/named/include/named/interfacemgr.h | 13 +- + bin/named/interfacemgr.c | 9 +- + doc/arm/Bv9ARM-book.xml | 3 +- + lib/isc/include/isc/quota.h | 7 + + lib/isc/quota.c | 33 ++- + lib/isc/win32/libisc.def.in | 1 + + 8 files changed, 396 insertions(+), 120 deletions(-) + +diff --git a/bin/named/client.c b/bin/named/client.c +index 4d26eff..020603d 100644 +--- a/bin/named/client.c ++++ b/bin/named/client.c +@@ -246,10 +246,11 @@ static void ns_client_dumpmessage(ns_client_t *client, const char *reason); + static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, + dns_dispatch_t *disp, bool tcp); + static isc_result_t get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, +- isc_socket_t *sock); ++ isc_socket_t *sock, ns_client_t *oldclient); + static inline bool +-allowed(isc_netaddr_t *addr, dns_name_t *signer, isc_netaddr_t *ecs_addr, +- uint8_t ecs_addrlen, uint8_t *ecs_scope, dns_acl_t *acl); ++allowed(isc_netaddr_t *addr, dns_name_t *signer, ++ isc_netaddr_t *ecs_addr, uint8_t ecs_addrlen, ++ uint8_t *ecs_scope, dns_acl_t *acl); + static void compute_cookie(ns_client_t *client, uint32_t when, + uint32_t nonce, const unsigned char *secret, + isc_buffer_t *buf); +@@ -298,6 +299,119 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) { + } + } + ++/*% ++ * Allocate a reference-counted object that will maintain a single pointer to ++ * the (also reference-counted) TCP client quota, shared between all the ++ * clients processing queries on a single TCP connection, so that all ++ * clients sharing the one socket will together consume only one slot in ++ * the 'tcp-clients' quota. ++ */ ++static isc_result_t ++tcpconn_init(ns_client_t *client, bool force) { ++ isc_result_t result; ++ isc_quota_t *quota = NULL; ++ ns_tcpconn_t *tconn = NULL; ++ ++ REQUIRE(client->tcpconn == NULL); ++ ++ /* ++ * Try to attach to the quota first, so we won't pointlessly ++ * allocate memory for a tcpconn object if we can't get one. ++ */ ++ if (force) { ++ result = isc_quota_force(&ns_g_server->tcpquota, "a); ++ } else { ++ result = isc_quota_attach(&ns_g_server->tcpquota, "a); ++ } ++ if (result != ISC_R_SUCCESS) { ++ return (result); ++ } ++ ++ /* ++ * A global memory context is used for the allocation as different ++ * client structures may have different memory contexts assigned and a ++ * reference counter allocated here might need to be freed by a ++ * different client. The performance impact caused by memory context ++ * contention here is expected to be negligible, given that this code ++ * is only executed for TCP connections. ++ */ ++ tconn = isc_mem_allocate(ns_g_mctx, sizeof(*tconn)); ++ ++ isc_refcount_init(&tconn->refs, 1); ++ tconn->tcpquota = quota; ++ quota = NULL; ++ tconn->pipelined = false; ++ ++ client->tcpconn = tconn; ++ ++ return (ISC_R_SUCCESS); ++} ++ ++/*% ++ * Increase the count of client structures sharing the TCP connection ++ * that 'source' is associated with; add a pointer to the same tcpconn ++ * to 'target', thus associating it with the same TCP connection. ++ */ ++static void ++tcpconn_attach(ns_client_t *source, ns_client_t *target) { ++ int refs; ++ ++ REQUIRE(source->tcpconn != NULL); ++ REQUIRE(target->tcpconn == NULL); ++ REQUIRE(source->tcpconn->pipelined); ++ ++ isc_refcount_increment(&source->tcpconn->refs, &refs); ++ INSIST(refs > 1); ++ target->tcpconn = source->tcpconn; ++} ++ ++/*% ++ * Decrease the count of client structures sharing the TCP connection that ++ * 'client' is associated with. If this is the last client using this TCP ++ * connection, we detach from the TCP quota and free the tcpconn ++ * object. Either way, client->tcpconn is set to NULL. ++ */ ++static void ++tcpconn_detach(ns_client_t *client) { ++ ns_tcpconn_t *tconn = NULL; ++ int refs; ++ ++ REQUIRE(client->tcpconn != NULL); ++ ++ tconn = client->tcpconn; ++ client->tcpconn = NULL; ++ ++ isc_refcount_decrement(&tconn->refs, &refs); ++ if (refs == 0) { ++ isc_quota_detach(&tconn->tcpquota); ++ isc_mem_free(ns_g_mctx, tconn); ++ } ++} ++ ++/*% ++ * Mark a client as active and increment the interface's 'ntcpactive' ++ * counter, as a signal that there is at least one client servicing ++ * TCP queries for the interface. If we reach the TCP client quota at ++ * some point, this will be used to determine whether a quota overrun ++ * should be permitted. ++ * ++ * Marking the client active with the 'tcpactive' flag ensures proper ++ * accounting, by preventing us from incrementing or decrementing ++ * 'ntcpactive' more than once per client. ++ */ ++static void ++mark_tcp_active(ns_client_t *client, bool active) { ++ if (active && !client->tcpactive) { ++ isc_atomic_xadd(&client->interface->ntcpactive, 1); ++ client->tcpactive = active; ++ } else if (!active && client->tcpactive) { ++ uint32_t old = ++ isc_atomic_xadd(&client->interface->ntcpactive, -1); ++ INSIST(old > 0); ++ client->tcpactive = active; ++ } ++} ++ + /*% + * Check for a deactivation or shutdown request and take appropriate + * action. Returns true if either is in progress; in this case +@@ -387,7 +501,8 @@ exit_check(ns_client_t *client) { + INSIST(client->recursionquota == NULL); + + if (NS_CLIENTSTATE_READING == client->newstate) { +- if (!client->pipelined) { ++ INSIST(client->tcpconn != NULL); ++ if (!client->tcpconn->pipelined) { + client_read(client); + client->newstate = NS_CLIENTSTATE_MAX; + return (true); /* We're done. */ +@@ -405,10 +520,13 @@ exit_check(ns_client_t *client) { + */ + INSIST(client->recursionquota == NULL); + INSIST(client->newstate <= NS_CLIENTSTATE_READY); +- if (client->nreads > 0) ++ ++ if (client->nreads > 0) { + dns_tcpmsg_cancelread(&client->tcpmsg); +- if (client->nreads != 0) { +- /* Still waiting for read cancel completion. */ ++ } ++ ++ /* Still waiting for read cancel completion. */ ++ if (client->nreads > 0) { + return (true); + } + +@@ -416,14 +534,49 @@ exit_check(ns_client_t *client) { + dns_tcpmsg_invalidate(&client->tcpmsg); + client->tcpmsg_valid = false; + } ++ ++ /* ++ * Soon the client will be ready to accept a new TCP ++ * connection or UDP request, but we may have enough ++ * clients doing that already. Check whether this client ++ * needs to remain active and allow it go inactive if ++ * not. ++ * ++ * UDP clients always go inactive at this point, but a TCP ++ * client may need to stay active and return to READY ++ * state if no other clients are available to listen ++ * for TCP requests on this interface. ++ * ++ * Regardless, if we're going to FREED state, that means ++ * the system is shutting down and we don't need to ++ * retain clients. ++ */ ++ if (client->mortal && TCP_CLIENT(client) && ++ client->newstate != NS_CLIENTSTATE_FREED && ++ !ns_g_clienttest && ++ isc_atomic_xadd(&client->interface->ntcpaccepting, 0) == 0) ++ { ++ /* Nobody else is accepting */ ++ client->mortal = false; ++ client->newstate = NS_CLIENTSTATE_READY; ++ } ++ ++ /* ++ * Detach from TCP connection and TCP client quota, ++ * if appropriate. If this is the last reference to ++ * the TCP connection in our pipeline group, the ++ * TCP quota slot will be released. ++ */ ++ if (client->tcpconn) { ++ tcpconn_detach(client); ++ } ++ + if (client->tcpsocket != NULL) { + CTRACE("closetcp"); + isc_socket_detach(&client->tcpsocket); ++ mark_tcp_active(client, false); + } + +- if (client->tcpquota != NULL) +- isc_quota_detach(&client->tcpquota); +- + if (client->timerset) { + (void)isc_timer_reset(client->timer, + isc_timertype_inactive, +@@ -431,45 +584,26 @@ exit_check(ns_client_t *client) { + client->timerset = false; + } + +- client->pipelined = false; +- + client->peeraddr_valid = false; + + client->state = NS_CLIENTSTATE_READY; +- INSIST(client->recursionquota == NULL); +- +- /* +- * Now the client is ready to accept a new TCP connection +- * or UDP request, but we may have enough clients doing +- * that already. Check whether this client needs to remain +- * active and force it to go inactive if not. +- * +- * UDP clients go inactive at this point, but TCP clients +- * may remain active if we have fewer active TCP client +- * objects than desired due to an earlier quota exhaustion. +- */ +- if (client->mortal && TCP_CLIENT(client) && !ns_g_clienttest) { +- LOCK(&client->interface->lock); +- if (client->interface->ntcpcurrent < +- client->interface->ntcptarget) +- client->mortal = false; +- UNLOCK(&client->interface->lock); +- } + + /* + * We don't need the client; send it to the inactive + * queue for recycling. + */ + if (client->mortal) { +- if (client->newstate > NS_CLIENTSTATE_INACTIVE) ++ if (client->newstate > NS_CLIENTSTATE_INACTIVE) { + client->newstate = NS_CLIENTSTATE_INACTIVE; ++ } + } + + if (NS_CLIENTSTATE_READY == client->newstate) { + if (TCP_CLIENT(client)) { + client_accept(client); +- } else ++ } else { + client_udprecv(client); ++ } + client->newstate = NS_CLIENTSTATE_MAX; + return (true); + } +@@ -481,41 +615,50 @@ exit_check(ns_client_t *client) { + /* + * We are trying to enter the inactive state. + */ +- if (client->naccepts > 0) ++ if (client->naccepts > 0) { + isc_socket_cancel(client->tcplistener, client->task, + ISC_SOCKCANCEL_ACCEPT); ++ } + + /* Still waiting for accept cancel completion. */ +- if (! (client->naccepts == 0)) ++ if (client->naccepts > 0) { + return (true); ++ } + + /* Accept cancel is complete. */ +- if (client->nrecvs > 0) ++ if (client->nrecvs > 0) { + isc_socket_cancel(client->udpsocket, client->task, + ISC_SOCKCANCEL_RECV); ++ } + + /* Still waiting for recv cancel completion. */ +- if (! (client->nrecvs == 0)) ++ if (client->nrecvs > 0) { + return (true); ++ } + + /* Still waiting for control event to be delivered */ +- if (client->nctls > 0) ++ if (client->nctls > 0) { + return (true); +- +- /* Deactivate the client. */ +- if (client->interface) +- ns_interface_detach(&client->interface); ++ } + + INSIST(client->naccepts == 0); + INSIST(client->recursionquota == NULL); +- if (client->tcplistener != NULL) ++ if (client->tcplistener != NULL) { + isc_socket_detach(&client->tcplistener); +- +- if (client->udpsocket != NULL) ++ mark_tcp_active(client, false); ++ } ++ if (client->udpsocket != NULL) { + isc_socket_detach(&client->udpsocket); ++ } ++ ++ /* Deactivate the client. */ ++ if (client->interface != NULL) { ++ ns_interface_detach(&client->interface); ++ } + +- if (client->dispatch != NULL) ++ if (client->dispatch != NULL) { + dns_dispatch_detach(&client->dispatch); ++ } + + client->attributes = 0; + client->mortal = false; +@@ -540,10 +683,13 @@ exit_check(ns_client_t *client) { + client->newstate = NS_CLIENTSTATE_MAX; + if (!ns_g_clienttest && manager != NULL && + !manager->exiting) ++ { + ISC_QUEUE_PUSH(manager->inactive, client, + ilink); +- if (client->needshutdown) ++ } ++ if (client->needshutdown) { + isc_task_shutdown(client->task); ++ } + return (true); + } + } +@@ -653,7 +799,7 @@ client_start(isc_task_t *task, isc_event_t *event) { + return; + + if (TCP_CLIENT(client)) { +- if (client->pipelined) { ++ if (client->tcpconn != NULL) { + client_read(client); + } else { + client_accept(client); +@@ -663,7 +809,6 @@ client_start(isc_task_t *task, isc_event_t *event) { + } + } + +- + /*% + * The client's task has received a shutdown event. + */ +@@ -2304,6 +2449,7 @@ client_request(isc_task_t *task, isc_event_t *event) { + client->nrecvs--; + } else { + INSIST(TCP_CLIENT(client)); ++ INSIST(client->tcpconn != NULL); + REQUIRE(event->ev_type == DNS_EVENT_TCPMSG); + REQUIRE(event->ev_sender == &client->tcpmsg); + buffer = &client->tcpmsg.buffer; +@@ -2487,18 +2633,27 @@ client_request(isc_task_t *task, isc_event_t *event) { + /* + * Pipeline TCP query processing. + */ +- if (client->message->opcode != dns_opcode_query) +- client->pipelined = false; +- if (TCP_CLIENT(client) && client->pipelined) { +- result = isc_quota_reserve(&ns_g_server->tcpquota); +- if (result == ISC_R_SUCCESS) +- result = ns_client_replace(client); ++ if (TCP_CLIENT(client) && ++ client->message->opcode != dns_opcode_query) ++ { ++ client->tcpconn->pipelined = false; ++ } ++ if (TCP_CLIENT(client) && client->tcpconn->pipelined) { ++ /* ++ * We're pipelining. Replace the client; the ++ * replacement can read the TCP socket looking ++ * for new messages and this one can process the ++ * current message asynchronously. ++ * ++ * There will now be at least three clients using this ++ * TCP socket - one accepting new connections, ++ * one reading an existing connection to get new ++ * messages, and one answering the message already ++ * received. ++ */ ++ result = ns_client_replace(client); + if (result != ISC_R_SUCCESS) { +- ns_client_log(client, NS_LOGCATEGORY_CLIENT, +- NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, +- "no more TCP clients(read): %s", +- isc_result_totext(result)); +- client->pipelined = false; ++ client->tcpconn->pipelined = false; + } + } + +@@ -3054,8 +3209,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { + client->signer = NULL; + dns_name_init(&client->signername, NULL); + client->mortal = false; +- client->pipelined = false; +- client->tcpquota = NULL; ++ client->tcpconn = NULL; + client->recursionquota = NULL; + client->interface = NULL; + client->peeraddr_valid = false; +@@ -3065,6 +3219,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { + client->filter_aaaa = dns_aaaa_ok; + #endif + client->needshutdown = ns_g_clienttest; ++ client->tcpactive = false; + + ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, + NS_EVENT_CLIENTCONTROL, client_start, client, client, +@@ -3159,9 +3314,10 @@ client_read(ns_client_t *client) { + + static void + client_newconn(isc_task_t *task, isc_event_t *event) { ++ isc_result_t result; + ns_client_t *client = event->ev_arg; + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; +- isc_result_t result; ++ uint32_t old; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); + REQUIRE(NS_CLIENT_VALID(client)); +@@ -3171,13 +3327,18 @@ client_newconn(isc_task_t *task, isc_event_t *event) { + + INSIST(client->state == NS_CLIENTSTATE_READY); + ++ /* ++ * The accept() was successful and we're now establishing a new ++ * connection. We need to make note of it in the client and ++ * interface objects so client objects can do the right thing ++ * when going inactive in exit_check() (see comments in ++ * client_accept() for details). ++ */ + INSIST(client->naccepts == 1); + client->naccepts--; + +- LOCK(&client->interface->lock); +- INSIST(client->interface->ntcpcurrent > 0); +- client->interface->ntcpcurrent--; +- UNLOCK(&client->interface->lock); ++ old = isc_atomic_xadd(&client->interface->ntcpaccepting, -1); ++ INSIST(old > 0); + + /* + * We must take ownership of the new socket before the exit +@@ -3210,6 +3371,7 @@ client_newconn(isc_task_t *task, isc_event_t *event) { + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "accept failed: %s", + isc_result_totext(nevent->result)); ++ tcpconn_detach(client); + } + + if (exit_check(client)) +@@ -3247,20 +3409,13 @@ client_newconn(isc_task_t *task, isc_event_t *event) { + * telnetting to port 53 (once per CPU) will + * deny service to legitimate TCP clients. + */ +- client->pipelined = false; +- result = isc_quota_attach(&ns_g_server->tcpquota, +- &client->tcpquota); +- if (result == ISC_R_SUCCESS) +- result = ns_client_replace(client); +- if (result != ISC_R_SUCCESS) { +- ns_client_log(client, NS_LOGCATEGORY_CLIENT, +- NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, +- "no more TCP clients(accept): %s", +- isc_result_totext(result)); +- } else if (ns_g_server->keepresporder == NULL || +- !allowed(&netaddr, NULL, NULL, 0, NULL, +- ns_g_server->keepresporder)) { +- client->pipelined = true; ++ result = ns_client_replace(client); ++ if (result == ISC_R_SUCCESS && ++ (ns_g_server->keepresporder == NULL || ++ !allowed(&netaddr, NULL, NULL, 0, NULL, ++ ns_g_server->keepresporder))) ++ { ++ client->tcpconn->pipelined = true; + } + + client_read(client); +@@ -3276,12 +3431,66 @@ client_accept(ns_client_t *client) { + + CTRACE("accept"); + ++ /* ++ * Set up a new TCP connection. This means try to attach to the ++ * TCP client quota (tcp-clients), but fail if we're over quota. ++ */ ++ result = tcpconn_init(client, false); ++ if (result != ISC_R_SUCCESS) { ++ bool exit; ++ ++ ns_client_log(client, NS_LOGCATEGORY_CLIENT, ++ NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, ++ "TCP client quota reached: %s", ++ isc_result_totext(result)); ++ ++ /* ++ * We have exceeded the system-wide TCP client quota. But, ++ * we can't just block this accept in all cases, because if ++ * we did, a heavy TCP load on other interfaces might cause ++ * this interface to be starved, with no clients able to ++ * accept new connections. ++ * ++ * So, we check here to see if any other clients are ++ * already servicing TCP queries on this interface (whether ++ * accepting, reading, or processing). If we find that at ++ * least one client other than this one is active, then ++ * it's okay *not* to call accept - we can let this ++ * client go inactive and another will take over when it's ++ * done. ++ * ++ * If there aren't enough active clients on the interface, ++ * then we can be a little bit flexible about the quota. ++ * We'll allow *one* extra client through to ensure we're ++ * listening on every interface; we do this by setting the ++ * 'force' option to tcpconn_init(). ++ * ++ * (Note: In practice this means that the real TCP client ++ * quota is tcp-clients plus the number of listening ++ * interfaces plus 1.) ++ */ ++ exit = (isc_atomic_xadd(&client->interface->ntcpactive, 0) > ++ (client->tcpactive ? 1 : 0)); ++ if (exit) { ++ client->newstate = NS_CLIENTSTATE_INACTIVE; ++ (void)exit_check(client); ++ return; ++ } ++ ++ result = tcpconn_init(client, true); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ } ++ ++ /* ++ * If this client was set up using get_client() or get_worker(), ++ * then TCP is already marked active. However, if it was restarted ++ * from exit_check(), it might not be, so we take care of it now. ++ */ ++ mark_tcp_active(client, true); ++ + result = isc_socket_accept(client->tcplistener, client->task, + client_newconn, client); + if (result != ISC_R_SUCCESS) { +- UNEXPECTED_ERROR(__FILE__, __LINE__, +- "isc_socket_accept() failed: %s", +- isc_result_totext(result)); + /* + * XXXRTH What should we do? We're trying to accept but + * it didn't work. If we just give up, then TCP +@@ -3289,13 +3498,37 @@ client_accept(ns_client_t *client) { + * + * For now, we just go idle. + */ ++ UNEXPECTED_ERROR(__FILE__, __LINE__, ++ "isc_socket_accept() failed: %s", ++ isc_result_totext(result)); ++ ++ tcpconn_detach(client); ++ mark_tcp_active(client, false); + return; + } ++ ++ /* ++ * The client's 'naccepts' counter indicates that this client has ++ * called accept() and is waiting for a new connection. It should ++ * never exceed 1. ++ */ + INSIST(client->naccepts == 0); + client->naccepts++; +- LOCK(&client->interface->lock); +- client->interface->ntcpcurrent++; +- UNLOCK(&client->interface->lock); ++ ++ /* ++ * The interface's 'ntcpaccepting' counter is incremented when ++ * any client calls accept(), and decremented in client_newconn() ++ * once the connection is established. ++ * ++ * When the client object is shutting down after handling a TCP ++ * request (see exit_check()), if this value is at least one, that ++ * means another client has called accept() and is waiting to ++ * establish the next connection. That means the client may be ++ * be free to become inactive; otherwise it may need to start ++ * listening for connections itself to prevent the interface ++ * going dead. ++ */ ++ isc_atomic_xadd(&client->interface->ntcpaccepting, 1); + } + + static void +@@ -3366,15 +3599,17 @@ ns_client_replace(ns_client_t *client) { + REQUIRE(client->manager != NULL); + + tcp = TCP_CLIENT(client); +- if (tcp && client->pipelined) { ++ if (tcp && client->tcpconn != NULL && client->tcpconn->pipelined) { + result = get_worker(client->manager, client->interface, +- client->tcpsocket); ++ client->tcpsocket, client); + } else { + result = get_client(client->manager, client->interface, + client->dispatch, tcp); ++ + } +- if (result != ISC_R_SUCCESS) ++ if (result != ISC_R_SUCCESS) { + return (result); ++ } + + /* + * The responsibility for listening for new requests is hereby +@@ -3560,9 +3795,12 @@ get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, + client->dscp = ifp->dscp; + + if (tcp) { ++ mark_tcp_active(client, true); ++ + client->attributes |= NS_CLIENTATTR_TCP; + isc_socket_attach(ifp->tcpsocket, + &client->tcplistener); ++ + } else { + isc_socket_t *sock; + +@@ -3580,7 +3818,8 @@ get_client(ns_clientmgr_t *manager, ns_interface_t *ifp, + } + + static isc_result_t +-get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *sock) ++get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *sock, ++ ns_client_t *oldclient) + { + isc_result_t result = ISC_R_SUCCESS; + isc_event_t *ev; +@@ -3588,6 +3827,7 @@ get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *sock) + MTRACE("get worker"); + + REQUIRE(manager != NULL); ++ REQUIRE(oldclient != NULL); + + if (manager->exiting) + return (ISC_R_SHUTTINGDOWN); +@@ -3620,14 +3860,15 @@ get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *sock) + ns_interface_attach(ifp, &client->interface); + client->newstate = client->state = NS_CLIENTSTATE_WORKING; + INSIST(client->recursionquota == NULL); +- client->tcpquota = &ns_g_server->tcpquota; + + client->dscp = ifp->dscp; + + client->attributes |= NS_CLIENTATTR_TCP; +- client->pipelined = true; + client->mortal = true; + ++ tcpconn_attach(oldclient, client); ++ mark_tcp_active(client, true); ++ + isc_socket_attach(ifp->tcpsocket, &client->tcplistener); + isc_socket_attach(sock, &client->tcpsocket); + isc_socket_setname(client->tcpsocket, "worker-tcp", NULL); +diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h +index b23a7b1..969ee4c 100644 +--- a/bin/named/include/named/client.h ++++ b/bin/named/include/named/client.h +@@ -9,8 +9,6 @@ + * information regarding copyright ownership. + */ + +-/* $Id: client.h,v 1.96 2012/01/31 23:47:31 tbox Exp $ */ +- + #ifndef NAMED_CLIENT_H + #define NAMED_CLIENT_H 1 + +@@ -80,6 +78,13 @@ + *** Types + ***/ + ++/*% reference-counted TCP connection object */ ++typedef struct ns_tcpconn { ++ isc_refcount_t refs; ++ isc_quota_t *tcpquota; ++ bool pipelined; ++} ns_tcpconn_t; ++ + /*% nameserver client structure */ + struct ns_client { + unsigned int magic; +@@ -94,7 +99,8 @@ struct ns_client { + int nupdates; + int nctls; + int references; +- bool needshutdown; /* ++ bool tcpactive; ++ bool needshutdown; /* + * Used by clienttest to get + * the client to go from + * inactive to free state +@@ -130,10 +136,9 @@ struct ns_client { + isc_stdtime_t now; + isc_time_t tnow; + dns_name_t signername; /*%< [T]SIG key name */ +- dns_name_t * signer; /*%< NULL if not valid sig */ +- bool mortal; /*%< Die after handling request */ +- bool pipelined; /*%< TCP queries not in sequence */ +- isc_quota_t *tcpquota; ++ dns_name_t *signer; /*%< NULL if not valid sig */ ++ bool mortal; /*%< Die after handling request */ ++ ns_tcpconn_t *tcpconn; + isc_quota_t *recursionquota; + ns_interface_t *interface; + +@@ -143,8 +148,8 @@ struct ns_client { + isc_sockaddr_t destsockaddr; + + isc_netaddr_t ecs_addr; /*%< EDNS client subnet */ +- uint8_t ecs_addrlen; +- uint8_t ecs_scope; ++ uint8_t ecs_addrlen; ++ uint8_t ecs_scope; + + struct in6_pktinfo pktinfo; + isc_dscp_t dscp; +diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h +index 7d1883e..3535ef2 100644 +--- a/bin/named/include/named/interfacemgr.h ++++ b/bin/named/include/named/interfacemgr.h +@@ -9,8 +9,6 @@ + * information regarding copyright ownership. + */ + +-/* $Id: interfacemgr.h,v 1.35 2011/07/28 23:47:58 tbox Exp $ */ +- + #ifndef NAMED_INTERFACEMGR_H + #define NAMED_INTERFACEMGR_H 1 + +@@ -77,9 +75,14 @@ struct ns_interface { + /*%< UDP dispatchers. */ + isc_socket_t * tcpsocket; /*%< TCP socket. */ + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ +- int ntcptarget; /*%< Desired number of concurrent +- TCP accepts */ +- int ntcpcurrent; /*%< Current ditto, locked */ ++ int32_t ntcpaccepting; /*%< Number of clients ++ ready to accept new ++ TCP connections on this ++ interface */ ++ int32_t ntcpactive; /*%< Number of clients ++ servicing TCP queries ++ (whether accepting or ++ connected) */ + int nudpdispatch; /*%< Number of UDP dispatches */ + ns_clientmgr_t * clientmgr; /*%< Client manager. */ + ISC_LINK(ns_interface_t) link; +diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c +index 419927b..d9f6df5 100644 +--- a/bin/named/interfacemgr.c ++++ b/bin/named/interfacemgr.c +@@ -386,8 +386,9 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + * connections will be handled in parallel even though there is + * only one client initially. + */ +- ifp->ntcptarget = 1; +- ifp->ntcpcurrent = 0; ++ ifp->ntcpaccepting = 0; ++ ifp->ntcpactive = 0; ++ + ifp->nudpdispatch = 0; + + ifp->dscp = -1; +@@ -522,9 +523,7 @@ ns_interface_accepttcp(ns_interface_t *ifp) { + */ + (void)isc_socket_filter(ifp->tcpsocket, "dataready"); + +- result = ns_clientmgr_createclients(ifp->clientmgr, +- ifp->ntcptarget, ifp, +- true); ++ result = ns_clientmgr_createclients(ifp->clientmgr, 1, ifp, true); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "TCP ns_clientmgr_createclients(): %s", +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 719b074..4b36bd0 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -8487,7 +8487,8 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; + <para> + The number of file descriptors reserved for TCP, stdio, + etc. This needs to be big enough to cover the number of +- interfaces <command>named</command> listens on, <command>tcp-clients</command> as well as ++ interfaces <command>named</command> listens on plus ++ <command>tcp-clients</command>, as well as + to provide room for outgoing TCP queries and incoming zone + transfers. The default is <literal>512</literal>. + The minimum value is <literal>128</literal> and the +diff --git a/lib/isc/include/isc/quota.h b/lib/isc/include/isc/quota.h +index b9bf598..36c5830 100644 +--- a/lib/isc/include/isc/quota.h ++++ b/lib/isc/include/isc/quota.h +@@ -100,6 +100,13 @@ isc_quota_attach(isc_quota_t *quota, isc_quota_t **p); + * quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA). + */ + ++isc_result_t ++isc_quota_force(isc_quota_t *quota, isc_quota_t **p); ++/*%< ++ * Like isc_quota_attach, but will attach '*p' to the quota ++ * even if the hard quota has been exceeded. ++ */ ++ + void + isc_quota_detach(isc_quota_t **p); + /*%< +diff --git a/lib/isc/quota.c b/lib/isc/quota.c +index 3ddff0d..556a61f 100644 +--- a/lib/isc/quota.c ++++ b/lib/isc/quota.c +@@ -74,20 +74,39 @@ isc_quota_release(isc_quota_t *quota) { + UNLOCK("a->lock); + } + +-isc_result_t +-isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) +-{ ++static isc_result_t ++doattach(isc_quota_t *quota, isc_quota_t **p, bool force) { + isc_result_t result; +- INSIST(p != NULL && *p == NULL); ++ REQUIRE(p != NULL && *p == NULL); ++ + result = isc_quota_reserve(quota); +- if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) ++ if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) { ++ *p = quota; ++ } else if (result == ISC_R_QUOTA && force) { ++ /* attach anyway */ ++ LOCK("a->lock); ++ quota->used++; ++ UNLOCK("a->lock); ++ + *p = quota; ++ result = ISC_R_SUCCESS; ++ } ++ + return (result); + } + ++isc_result_t ++isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) { ++ return (doattach(quota, p, false)); ++} ++ ++isc_result_t ++isc_quota_force(isc_quota_t *quota, isc_quota_t **p) { ++ return (doattach(quota, p, true)); ++} ++ + void +-isc_quota_detach(isc_quota_t **p) +-{ ++isc_quota_detach(isc_quota_t **p) { + INSIST(p != NULL && *p != NULL); + isc_quota_release(*p); + *p = NULL; +diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in +index a82face..7b9f23d 100644 +--- a/lib/isc/win32/libisc.def.in ++++ b/lib/isc/win32/libisc.def.in +@@ -519,6 +519,7 @@ isc_portset_removerange + isc_quota_attach + isc_quota_destroy + isc_quota_detach ++isc_quota_force + isc_quota_init + isc_quota_max + isc_quota_release diff --git a/debian/patches/0013-Replace-atomic-operations-in-bin-named-client.c-with.patch b/debian/patches/0013-Replace-atomic-operations-in-bin-named-client.c-with.patch new file mode 100644 index 0000000..4ce3abe --- /dev/null +++ b/debian/patches/0013-Replace-atomic-operations-in-bin-named-client.c-with.patch @@ -0,0 +1,128 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@sury.org> +Date: Wed, 17 Apr 2019 15:22:27 +0200 +Subject: Replace atomic operations in bin/named/client.c with isc_refcount + reference counting + +--- + bin/named/client.c | 18 +++++++----------- + bin/named/include/named/interfacemgr.h | 5 +++-- + bin/named/interfacemgr.c | 7 +++++-- + 3 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/bin/named/client.c b/bin/named/client.c +index 020603d..8155c6b 100644 +--- a/bin/named/client.c ++++ b/bin/named/client.c +@@ -402,12 +402,10 @@ tcpconn_detach(ns_client_t *client) { + static void + mark_tcp_active(ns_client_t *client, bool active) { + if (active && !client->tcpactive) { +- isc_atomic_xadd(&client->interface->ntcpactive, 1); ++ isc_refcount_increment0(&client->interface->ntcpactive, NULL); + client->tcpactive = active; + } else if (!active && client->tcpactive) { +- uint32_t old = +- isc_atomic_xadd(&client->interface->ntcpactive, -1); +- INSIST(old > 0); ++ isc_refcount_decrement(&client->interface->ntcpactive, NULL); + client->tcpactive = active; + } + } +@@ -554,7 +552,7 @@ exit_check(ns_client_t *client) { + if (client->mortal && TCP_CLIENT(client) && + client->newstate != NS_CLIENTSTATE_FREED && + !ns_g_clienttest && +- isc_atomic_xadd(&client->interface->ntcpaccepting, 0) == 0) ++ isc_refcount_current(&client->interface->ntcpaccepting) == 0) + { + /* Nobody else is accepting */ + client->mortal = false; +@@ -3317,7 +3315,6 @@ client_newconn(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + ns_client_t *client = event->ev_arg; + isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; +- uint32_t old; + + REQUIRE(event->ev_type == ISC_SOCKEVENT_NEWCONN); + REQUIRE(NS_CLIENT_VALID(client)); +@@ -3337,8 +3334,7 @@ client_newconn(isc_task_t *task, isc_event_t *event) { + INSIST(client->naccepts == 1); + client->naccepts--; + +- old = isc_atomic_xadd(&client->interface->ntcpaccepting, -1); +- INSIST(old > 0); ++ isc_refcount_decrement(&client->interface->ntcpaccepting, NULL); + + /* + * We must take ownership of the new socket before the exit +@@ -3469,8 +3465,8 @@ client_accept(ns_client_t *client) { + * quota is tcp-clients plus the number of listening + * interfaces plus 1.) + */ +- exit = (isc_atomic_xadd(&client->interface->ntcpactive, 0) > +- (client->tcpactive ? 1 : 0)); ++ exit = (isc_refcount_current(&client->interface->ntcpactive) > ++ (client->tcpactive ? 1U : 0U)); + if (exit) { + client->newstate = NS_CLIENTSTATE_INACTIVE; + (void)exit_check(client); +@@ -3528,7 +3524,7 @@ client_accept(ns_client_t *client) { + * listening for connections itself to prevent the interface + * going dead. + */ +- isc_atomic_xadd(&client->interface->ntcpaccepting, 1); ++ isc_refcount_increment0(&client->interface->ntcpaccepting, NULL); + } + + static void +diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h +index 3535ef2..6e10f21 100644 +--- a/bin/named/include/named/interfacemgr.h ++++ b/bin/named/include/named/interfacemgr.h +@@ -45,6 +45,7 @@ + #include <isc/magic.h> + #include <isc/mem.h> + #include <isc/socket.h> ++#include <isc/refcount.h> + + #include <dns/result.h> + +@@ -75,11 +76,11 @@ struct ns_interface { + /*%< UDP dispatchers. */ + isc_socket_t * tcpsocket; /*%< TCP socket. */ + isc_dscp_t dscp; /*%< "listen-on" DSCP value */ +- int32_t ntcpaccepting; /*%< Number of clients ++ isc_refcount_t ntcpaccepting; /*%< Number of clients + ready to accept new + TCP connections on this + interface */ +- int32_t ntcpactive; /*%< Number of clients ++ isc_refcount_t ntcpactive; /*%< Number of clients + servicing TCP queries + (whether accepting or + connected) */ +diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c +index d9f6df5..135533b 100644 +--- a/bin/named/interfacemgr.c ++++ b/bin/named/interfacemgr.c +@@ -386,8 +386,8 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, + * connections will be handled in parallel even though there is + * only one client initially. + */ +- ifp->ntcpaccepting = 0; +- ifp->ntcpactive = 0; ++ isc_refcount_init(&ifp->ntcpaccepting, 0); ++ isc_refcount_init(&ifp->ntcpactive, 0); + + ifp->nudpdispatch = 0; + +@@ -618,6 +618,9 @@ ns_interface_destroy(ns_interface_t *ifp) { + + ns_interfacemgr_detach(&ifp->mgr); + ++ isc_refcount_destroy(&ifp->ntcpactive); ++ isc_refcount_destroy(&ifp->ntcpaccepting); ++ + ifp->magic = 0; + isc_mem_put(mctx, ifp, sizeof(*ifp)); + } diff --git a/debian/patches/0014-Disable-broken-Ed448-support.patch b/debian/patches/0014-Disable-broken-Ed448-support.patch new file mode 100644 index 0000000..29c8289 --- /dev/null +++ b/debian/patches/0014-Disable-broken-Ed448-support.patch @@ -0,0 +1,508 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@debian.org> +Date: Fri, 26 Apr 2019 07:58:26 +0000 +Subject: Disable broken Ed448 support + +--- + config.h.in | 3 - + configure | 201 ++++++++++++++++++++++------------------------------------- + configure.in | 33 ---------- + 3 files changed, 75 insertions(+), 162 deletions(-) + +diff --git a/config.h.in b/config.h.in +index b6f1a28..8268259 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -387,9 +387,6 @@ int sigwait(const unsigned int *set, int *sig); + /* Define if your OpenSSL version supports Ed25519. */ + #undef HAVE_OPENSSL_ED25519 + +-/* Define if your OpenSSL version supports Ed448. */ +-#undef HAVE_OPENSSL_ED448 +- + /* Define if your OpenSSL version supports EVP AES */ + #undef HAVE_OPENSSL_EVP_AES + +diff --git a/configure b/configure +index 80b8eca..160e996 100755 +--- a/configure ++++ b/configure +@@ -827,6 +827,7 @@ PKCS11_TEST + PKCS11_ED25519 + PKCS11_GOST + PKCS11_ECDSA ++CRYPTO_PK11 + CRYPTO + PKCS11LINKSRCS + PKCS11LINKOBJS +@@ -865,6 +866,7 @@ THREADOPTOBJS + ISC_PLATFORM_USETHREADS + ALWAYS_DEFINES + CHECK_DSA ++DNS_CRYPTO_PK11_LIBS + DNS_CRYPTO_LIBS + DNS_GSSAPI_LIBS + DST_GSSAPI_INC +@@ -968,6 +970,7 @@ infodir + docdir + oldincludedir + includedir ++runstatedir + localstatedir + sharedstatedir + sysconfdir +@@ -1129,6 +1132,7 @@ datadir='${datarootdir}' + sysconfdir='${prefix}/etc' + sharedstatedir='${prefix}/com' + localstatedir='${prefix}/var' ++runstatedir='${localstatedir}/run' + includedir='${prefix}/include' + oldincludedir='/usr/include' + docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +@@ -1381,6 +1385,15 @@ do + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + ++ -runstatedir | --runstatedir | --runstatedi | --runstated \ ++ | --runstate | --runstat | --runsta | --runst | --runs \ ++ | --run | --ru | --r) ++ ac_prev=runstatedir ;; ++ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ ++ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ ++ | --run=* | --ru=* | --r=*) ++ runstatedir=$ac_optarg ;; ++ + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ +@@ -1518,7 +1531,7 @@ fi + for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ +- libdir localedir mandir ++ libdir localedir mandir runstatedir + do + eval ac_val=\$$ac_var + # Remove trailing slashes. +@@ -1671,6 +1684,7 @@ Fine tuning of the installation directories: + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] ++ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] +@@ -5037,7 +5051,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +-netbsd*) ++netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else +@@ -5943,11 +5957,8 @@ _LT_EOF + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm +- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 +- (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 +- ac_status=$? +- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; } && test -s "$nlist"; then ++ $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 ++ if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" +@@ -8772,6 +8783,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie + openbsd* | bitrig*) + with_gnu_ld=no + ;; ++ linux* | k*bsd*-gnu | gnu*) ++ link_all_deplibs=no ++ ;; + esac + + ld_shlibs=yes +@@ -9026,7 +9040,7 @@ _LT_EOF + fi + ;; + +- netbsd*) ++ netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= +@@ -9696,6 +9710,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi ++ link_all_deplibs=no + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' +@@ -9717,7 +9732,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; } + esac + ;; + +- netbsd*) ++ netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else +@@ -10832,6 +10847,18 @@ fi + dynamic_linker='GNU/Linux ld.so' + ;; + ++netbsdelf*-gnu) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ dynamic_linker='NetBSD ld.elf_so' ++ ;; ++ + netbsd*) + version_type=sunos + need_lib_prefix=no +@@ -13427,7 +13454,7 @@ case "$host" in + # as it breaks how the two halves (Basic and Advanced) of the IPv6 + # Socket API were designed to be used but we have to live with it. + # Define _GNU_SOURCE to pull in the IPv6 Advanced Socket API. +- *-linux* | *-kfreebsd*-gnu*) ++ *-linux* | *-kfreebsd*-gnu* | *-gnu*) + STD_CDEFINES="$STD_CDEFINES -D_GNU_SOURCE" + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + ;; +@@ -15227,6 +15254,7 @@ esac + + + DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS" ++DNS_CRYPTO_PK11_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_PK11_LIBS" + + # + # Applications linking with libdns also need to link with these libraries. +@@ -15234,6 +15262,7 @@ DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS" + + + ++ + # + # was --with-randomdev specified? + # +@@ -16330,7 +16359,7 @@ fi + # LinuxThreads requires some changes to the way we + # deal with signals. + # +- *-linux*) ++ *-linux*|*-kfreebsd*-gnu) + $as_echo "#define HAVE_LINUXTHREADS 1" >>confdefs.h + + ;; +@@ -16585,12 +16614,6 @@ fi + $as_echo_n "checking for OpenSSL library... " >&6; } + OPENSSL_WARNING= + openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw" +-if test "yes" = "$want_native_pkcs11" +-then +- use_openssl="native_pkcs11" +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: use of native PKCS11 instead" >&5 +-$as_echo "use of native PKCS11 instead" >&6; } +-fi + + if test "auto" = "$use_openssl" + then +@@ -16603,6 +16626,7 @@ then + fi + done + fi ++CRYPTO_PK11="" + OPENSSL_ECDSA="" + OPENSSL_GOST="" + OPENSSL_ED25519="" +@@ -16625,12 +16649,10 @@ $as_echo "#define PREFER_GOSTASN1 1" >>confdefs.h + ;; + esac + +-case "$use_openssl" in +- native_pkcs11) +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled because of native PKCS11" >&5 +-$as_echo "disabled because of native PKCS11" >&6; } ++if test "$want_native_pkcs11" = "yes" ++then + DST_OPENSSL_INC="" +- CRYPTO="-DPKCS11CRYPTO" ++ CRYPTO_PK11="-DPKCS11CRYPTO" + OPENSSLECDSALINKOBJS="" + OPENSSLECDSALINKSRCS="" + OPENSSLEDDSALINKOBJS="" +@@ -16639,7 +16661,9 @@ $as_echo "disabled because of native PKCS11" >&6; } + OPENSSLGOSTLINKSRCS="" + OPENSSLLINKOBJS="" + OPENSSLLINKSRCS="" +- ;; ++fi ++ ++case "$use_openssl" in + no) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + $as_echo "no" >&6; } +@@ -16669,12 +16693,6 @@ $as_echo "no" >&6; } + If you don't want OpenSSL, use --without-openssl" "$LINENO" 5 + ;; + *) +- if test "yes" = "$want_native_pkcs11" +- then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +-$as_echo "" >&6; } +- as_fn_error $? "OpenSSL and native PKCS11 cannot be used together." "$LINENO" 5 +- fi + if test "yes" = "$use_openssl" + then + # User did not specify a path - guess it +@@ -17126,60 +17144,10 @@ fi + + $as_echo "#define HAVE_OPENSSL_ED25519 1" >>confdefs.h + +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL Ed448 support" >&5 +-$as_echo_n "checking for OpenSSL Ed448 support... " >&6; } +- if test "$cross_compiling" = yes; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: using --with-eddsa" >&5 +-$as_echo "using --with-eddsa" >&6; } +-else +- cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +- +-#include <openssl/evp.h> +-#include <openssl/objects.h> +-int main() { +- EVP_PKEY_CTX *ctx; +- +- ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL); +- if (ctx == NULL) +- return (2); +- return (0); +-} +- +-_ACEOF +-if ac_fn_c_try_run "$LINENO"; then : +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +- have_ed448="yes" +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +- have_ed448="no" +-fi +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ +- conftest.$ac_objext conftest.beam conftest.$ac_ext +-fi +- +- case $with_eddsa in +- all) +- have_ed448=yes ;; +- *) +- ;; +- esac +- case $have_ed448 in +- yes) +- +-$as_echo "#define HAVE_OPENSSL_ED448 1" >>confdefs.h +- +- ;; +- *) +- ;; +- esac + ;; + *) + ;; + esac +- + have_aes="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL AES support" >&5 + $as_echo_n "checking for OpenSSL AES support... " >&6; } +@@ -17278,6 +17246,7 @@ esac + + + DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DST_OPENSSL_LIBS" ++DNS_CRYPTO_PK11_LIBS="$DNS_CRYPTO_LIBS" + + ISC_PLATFORM_WANTAES="#undef ISC_PLATFORM_WANTAES" + if test "yes" = "$with_aes" +@@ -17667,6 +17636,7 @@ esac + + + ++ + # for PKCS11 benchmarks + + have_clock_gt=no +@@ -18526,51 +18496,6 @@ _ACEOF + + LIBS="-lsocket $LIBS" + +-fi +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_addr in -lnsl" >&5 +-$as_echo_n "checking for inet_addr in -lnsl... " >&6; } +-if ${ac_cv_lib_nsl_inet_addr+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- ac_check_lib_save_LIBS=$LIBS +-LIBS="-lnsl $LIBS" +-cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +- +-/* Override any GCC internal prototype to avoid an error. +- Use char because int might match the return type of a GCC +- builtin and then its argument prototype would still apply. */ +-#ifdef __cplusplus +-extern "C" +-#endif +-char inet_addr (); +-int +-main () +-{ +-return inet_addr (); +- ; +- return 0; +-} +-_ACEOF +-if ac_fn_c_try_link "$LINENO"; then : +- ac_cv_lib_nsl_inet_addr=yes +-else +- ac_cv_lib_nsl_inet_addr=no +-fi +-rm -f core conftest.err conftest.$ac_objext \ +- conftest$ac_exeext conftest.$ac_ext +-LIBS=$ac_check_lib_save_LIBS +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_inet_addr" >&5 +-$as_echo "$ac_cv_lib_nsl_inet_addr" >&6; } +-if test "x$ac_cv_lib_nsl_inet_addr" = xyes; then : +- cat >>confdefs.h <<_ACEOF +-#define HAVE_LIBNSL 1 +-_ACEOF +- +- LIBS="-lnsl $LIBS" +- + fi + + ;; +@@ -24555,7 +24480,7 @@ ac_config_commands="$ac_config_commands chmod" + # elsewhere if there's a good reason for doing so. + # + +-ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/lwresd/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/tests/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh" ++ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/dnssec-pkcs11/Makefile bin/named/Makefile bin/named/unix/Makefile bin/named-pkcs11/Makefile bin/named-pkcs11/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/inline/checkdsa.sh bin/tests/system/lwresd/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/dns-pkcs11/Makefile lib/dns-pkcs11/include/Makefile lib/dns-pkcs11/include/dns/Makefile lib/dns-pkcs11/include/dst/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isc-pkcs11/$arch/Makefile lib/isc-pkcs11/$arch/include/Makefile lib/isc-pkcs11/$arch/include/isc/Makefile lib/isc-pkcs11/$thread_dir/Makefile lib/isc-pkcs11/$thread_dir/include/Makefile lib/isc-pkcs11/$thread_dir/include/isc/Makefile lib/isc-pkcs11/Makefile lib/isc-pkcs11/include/Makefile lib/isc-pkcs11/include/isc/Makefile lib/isc-pkcs11/include/isc/platform.h lib/isc-pkcs11/include/pk11/Makefile lib/isc-pkcs11/include/pkcs11/Makefile lib/isc-pkcs11/tests/Makefile lib/isc-pkcs11/nls/Makefile lib/isc-pkcs11/unix/Makefile lib/isc-pkcs11/unix/include/Makefile lib/isc-pkcs11/unix/include/isc/Makefile lib/isc-pkcs11/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/tests/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/Makefile unit/unittest.sh" + + + # +@@ -25567,8 +25492,11 @@ do + "bin/delv/Makefile") CONFIG_FILES="$CONFIG_FILES bin/delv/Makefile" ;; + "bin/dig/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dig/Makefile" ;; + "bin/dnssec/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dnssec/Makefile" ;; ++ "bin/dnssec-pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dnssec-pkcs11/Makefile" ;; + "bin/named/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/Makefile" ;; + "bin/named/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/unix/Makefile" ;; ++ "bin/named-pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named-pkcs11/Makefile" ;; ++ "bin/named-pkcs11/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named-pkcs11/unix/Makefile" ;; + "bin/nsupdate/Makefile") CONFIG_FILES="$CONFIG_FILES bin/nsupdate/Makefile" ;; + "bin/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/pkcs11/Makefile" ;; + "bin/python/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/Makefile" ;; +@@ -25642,6 +25570,10 @@ do + "lib/dns/include/dns/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns/include/dns/Makefile" ;; + "lib/dns/include/dst/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns/include/dst/Makefile" ;; + "lib/dns/tests/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns/tests/Makefile" ;; ++ "lib/dns-pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns-pkcs11/Makefile" ;; ++ "lib/dns-pkcs11/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns-pkcs11/include/Makefile" ;; ++ "lib/dns-pkcs11/include/dns/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns-pkcs11/include/dns/Makefile" ;; ++ "lib/dns-pkcs11/include/dst/Makefile") CONFIG_FILES="$CONFIG_FILES lib/dns-pkcs11/include/dst/Makefile" ;; + "lib/irs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/irs/Makefile" ;; + "lib/irs/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/irs/include/Makefile" ;; + "lib/irs/include/irs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/irs/include/irs/Makefile" ;; +@@ -25666,6 +25598,24 @@ do + "lib/isc/unix/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/unix/include/Makefile" ;; + "lib/isc/unix/include/isc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/unix/include/isc/Makefile" ;; + "lib/isc/unix/include/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc/unix/include/pkcs11/Makefile" ;; ++ "lib/isc-pkcs11/$arch/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$arch/Makefile" ;; ++ "lib/isc-pkcs11/$arch/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$arch/include/Makefile" ;; ++ "lib/isc-pkcs11/$arch/include/isc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$arch/include/isc/Makefile" ;; ++ "lib/isc-pkcs11/$thread_dir/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$thread_dir/Makefile" ;; ++ "lib/isc-pkcs11/$thread_dir/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$thread_dir/include/Makefile" ;; ++ "lib/isc-pkcs11/$thread_dir/include/isc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/$thread_dir/include/isc/Makefile" ;; ++ "lib/isc-pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/Makefile" ;; ++ "lib/isc-pkcs11/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/include/Makefile" ;; ++ "lib/isc-pkcs11/include/isc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/include/isc/Makefile" ;; ++ "lib/isc-pkcs11/include/isc/platform.h") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/include/isc/platform.h" ;; ++ "lib/isc-pkcs11/include/pk11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/include/pk11/Makefile" ;; ++ "lib/isc-pkcs11/include/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/include/pkcs11/Makefile" ;; ++ "lib/isc-pkcs11/tests/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/tests/Makefile" ;; ++ "lib/isc-pkcs11/nls/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/nls/Makefile" ;; ++ "lib/isc-pkcs11/unix/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/unix/Makefile" ;; ++ "lib/isc-pkcs11/unix/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/unix/include/Makefile" ;; ++ "lib/isc-pkcs11/unix/include/isc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/unix/include/isc/Makefile" ;; ++ "lib/isc-pkcs11/unix/include/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isc-pkcs11/unix/include/pkcs11/Makefile" ;; + "lib/isccc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isccc/Makefile" ;; + "lib/isccc/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isccc/include/Makefile" ;; + "lib/isccc/include/isccc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/isccc/include/isccc/Makefile" ;; +@@ -26296,7 +26246,6 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} + cat <<_LT_EOF >> "$cfgfile" + #! $SHELL + # Generated automatically by $as_me ($PACKAGE) $VERSION +-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + # NOTE: Changes made to this file will be lost: look at ltmain.sh. + + # Provide generalized library-building support services. +diff --git a/configure.in b/configure.in +index f8603b8..324ac97 100644 +--- a/configure.in ++++ b/configure.in +@@ -1889,43 +1889,10 @@ int main() { + OPENSSLEDDSALINKSRCS='${OPENSSLEDDSALINKSRCS}' + AC_DEFINE(HAVE_OPENSSL_ED25519, 1, + [Define if your OpenSSL version supports Ed25519.]) +- AC_MSG_CHECKING(for OpenSSL Ed448 support) +- AC_TRY_RUN([ +-#include <openssl/evp.h> +-#include <openssl/objects.h> +-int main() { +- EVP_PKEY_CTX *ctx; +- +- ctx = EVP_PKEY_CTX_new_id(NID_ED448, NULL); +- if (ctx == NULL) +- return (2); +- return (0); +-} +-], +- [AC_MSG_RESULT(yes) +- have_ed448="yes"], +- [AC_MSG_RESULT(no) +- have_ed448="no"], +- [AC_MSG_RESULT(using --with-eddsa)]) +- case $with_eddsa in +- all) +- have_ed448=yes ;; +- *) +- ;; +- esac +- case $have_ed448 in +- yes) +- AC_DEFINE(HAVE_OPENSSL_ED448, 1, +- [Define if your OpenSSL version supports Ed448.]) +- ;; +- *) +- ;; +- esac + ;; + *) + ;; + esac +- + have_aes="no" + AC_MSG_CHECKING(for OpenSSL AES support) + AC_TRY_RUN([ diff --git a/debian/patches/0015-move-item_out-test-inside-lock-in-dns_dispatch_getne.patch b/debian/patches/0015-move-item_out-test-inside-lock-in-dns_dispatch_getne.patch new file mode 100644 index 0000000..5b665a9 --- /dev/null +++ b/debian/patches/0015-move-item_out-test-inside-lock-in-dns_dispatch_getne.patch @@ -0,0 +1,54 @@ +From: Mark Andrews <marka@isc.org> +Date: Tue, 19 Mar 2019 14:14:21 +1100 +Subject: move item_out test inside lock in dns_dispatch_getnext() + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/3a9c7bb80d4a609b86427406d9dd783199920b5b +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2019-6471 +Bug-Debian: https://bugs.debian.org/930746 + +(cherry picked from commit 60c42f849d520564ed42e5ed0ba46b4b69c07712) +--- + lib/dns/dispatch.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c +index d1e4c16..b5a8f74 100644 +--- a/lib/dns/dispatch.c ++++ b/lib/dns/dispatch.c +@@ -134,7 +134,7 @@ struct dns_dispentry { + isc_task_t *task; + isc_taskaction_t action; + void *arg; +- bool item_out; ++ bool item_out; + dispsocket_t *dispsocket; + ISC_LIST(dns_dispatchevent_t) items; + ISC_LINK(dns_dispentry_t) link; +@@ -3422,13 +3422,14 @@ dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { + disp = resp->disp; + REQUIRE(VALID_DISPATCH(disp)); + +- REQUIRE(resp->item_out == true); +- resp->item_out = false; +- + ev = *sockevent; + *sockevent = NULL; + + LOCK(&disp->lock); ++ ++ REQUIRE(resp->item_out == true); ++ resp->item_out = false; ++ + if (ev->buffer.base != NULL) + free_buffer(disp, ev->buffer.base, ev->buffer.length); + free_devent(disp, ev); +@@ -3573,6 +3574,9 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, + isc_task_send(disp->task[0], &disp->ctlevent); + } + ++/* ++ * disp must be locked. ++ */ + static void + do_cancel(dns_dispatch_t *disp) { + dns_dispatchevent_t *ev; diff --git a/debian/patches/0016-Set-a-limit-on-number-of-simultaneous-pipelined-TCP-.patch b/debian/patches/0016-Set-a-limit-on-number-of-simultaneous-pipelined-TCP-.patch new file mode 100644 index 0000000..a57296a --- /dev/null +++ b/debian/patches/0016-Set-a-limit-on-number-of-simultaneous-pipelined-TCP-.patch @@ -0,0 +1,117 @@ +From: =?utf-8?q?Witold_Kr=C4=99cicki?= <wpk@isc.org> +Date: Wed, 16 Oct 2019 13:18:48 +0200 +Subject: Set a limit on number of simultaneous pipelined TCP queries + +There was no limit on concurrently served queries served over one pipelined TCP +connection, thus it was possible to send thousands queries over a single TCP +connection, possibly exhausting the server resources. + +(cherry picked from commit efaa67749de825073cd7f19778386d0815c4ce29) +--- + bin/named/client.c | 57 ++++++++++++++++++++++++++-------------- + bin/named/include/named/client.h | 5 +++- + 2 files changed, 42 insertions(+), 20 deletions(-) + +diff --git a/bin/named/client.c b/bin/named/client.c +index 8155c6b..30877c5 100644 +--- a/bin/named/client.c ++++ b/bin/named/client.c +@@ -101,7 +101,15 @@ + #define SEND_BUFFER_SIZE 4096 + #define RECV_BUFFER_SIZE 4096 + ++#define TCP_CLIENTS_PER_CONN 23 ++/*%< ++ * Number of simultaneous ns_clients_t (queries in flight) for one ++ * TCP connection. The number was arbitrarily picked and might be ++ * changed in the future. ++ */ ++ + #ifdef ISC_PLATFORM_USETHREADS ++ + #define NMCTXS 100 + /*%< + * Number of 'mctx pools' for clients. (Should this be configurable?) +@@ -337,7 +345,7 @@ tcpconn_init(ns_client_t *client, bool force) { + */ + tconn = isc_mem_allocate(ns_g_mctx, sizeof(*tconn)); + +- isc_refcount_init(&tconn->refs, 1); ++ isc_refcount_init(&tconn->refs, 1); /* Current client */ + tconn->tcpquota = quota; + quota = NULL; + tconn->pipelined = false; +@@ -2631,28 +2639,39 @@ client_request(isc_task_t *task, isc_event_t *event) { + /* + * Pipeline TCP query processing. + */ +- if (TCP_CLIENT(client) && +- client->message->opcode != dns_opcode_query) +- { +- client->tcpconn->pipelined = false; +- } +- if (TCP_CLIENT(client) && client->tcpconn->pipelined) { ++ if (TCP_CLIENT(client)) { ++ if (client->message->opcode != dns_opcode_query) { ++ client->tcpconn->pipelined = false; ++ } ++ + /* +- * We're pipelining. Replace the client; the +- * replacement can read the TCP socket looking +- * for new messages and this one can process the +- * current message asynchronously. +- * +- * There will now be at least three clients using this +- * TCP socket - one accepting new connections, +- * one reading an existing connection to get new +- * messages, and one answering the message already +- * received. ++ * Limit the maximum number of simultaenous pipelined ++ * queries on TCP connection to TCP_CLIENTS_PER_CONN. + */ +- result = ns_client_replace(client); +- if (result != ISC_R_SUCCESS) { ++ if ((isc_refcount_current(&client->tcpconn->refs) ++ > TCP_CLIENTS_PER_CONN)) ++ { + client->tcpconn->pipelined = false; + } ++ ++ if (client->tcpconn->pipelined) { ++ /* ++ * We're pipelining. Replace the client; the ++ * replacement can read the TCP socket looking ++ * for new messages and this one can process the ++ * current message asynchronously. ++ * ++ * There will now be at least three clients using this ++ * TCP socket - one accepting new connections, ++ * one reading an existing connection to get new ++ * messages, and one answering the message already ++ * received. ++ */ ++ result = ns_client_replace(client); ++ if (result != ISC_R_SUCCESS) { ++ client->tcpconn->pipelined = false; ++ } ++ } + } + + dns_opcodestats_increment(ns_g_server->opcodestats, +diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h +index 969ee4c..5ae10ae 100644 +--- a/bin/named/include/named/client.h ++++ b/bin/named/include/named/client.h +@@ -80,7 +80,10 @@ + + /*% reference-counted TCP connection object */ + typedef struct ns_tcpconn { +- isc_refcount_t refs; ++ isc_refcount_t refs; /* Number of clients using ++ * this connection. Conn can ++ * be freed if goes to 0 ++ */ + isc_quota_t *tcpquota; + bool pipelined; + } ns_tcpconn_t; diff --git a/debian/patches/0017-libns-Rename-ns_tcpconn-refs-member-to-clients.patch b/debian/patches/0017-libns-Rename-ns_tcpconn-refs-member-to-clients.patch new file mode 100644 index 0000000..4045792 --- /dev/null +++ b/debian/patches/0017-libns-Rename-ns_tcpconn-refs-member-to-clients.patch @@ -0,0 +1,82 @@ +From: =?utf-8?q?Witold_Kr=C4=99cicki?= <wpk@isc.org> +Date: Wed, 16 Oct 2019 13:18:48 +0200 +Subject: libns: Rename ns_tcpconn refs member to clients + +(cherry picked from commit b6d6b50c997b3a00fdde9e0d32c4594ffe94f369) +--- + bin/named/client.c | 16 ++++++++-------- + bin/named/include/named/client.h | 2 +- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/bin/named/client.c b/bin/named/client.c +index 30877c5..5dc309a 100644 +--- a/bin/named/client.c ++++ b/bin/named/client.c +@@ -345,7 +345,7 @@ tcpconn_init(ns_client_t *client, bool force) { + */ + tconn = isc_mem_allocate(ns_g_mctx, sizeof(*tconn)); + +- isc_refcount_init(&tconn->refs, 1); /* Current client */ ++ isc_refcount_init(&tconn->clients, 1); /* Current client */ + tconn->tcpquota = quota; + quota = NULL; + tconn->pipelined = false; +@@ -362,14 +362,14 @@ tcpconn_init(ns_client_t *client, bool force) { + */ + static void + tcpconn_attach(ns_client_t *source, ns_client_t *target) { +- int refs; ++ int old_clients; + + REQUIRE(source->tcpconn != NULL); + REQUIRE(target->tcpconn == NULL); + REQUIRE(source->tcpconn->pipelined); + +- isc_refcount_increment(&source->tcpconn->refs, &refs); +- INSIST(refs > 1); ++ isc_refcount_increment(&source->tcpconn->clients, &old_clients); ++ INSIST(old_clients > 1); + target->tcpconn = source->tcpconn; + } + +@@ -382,15 +382,15 @@ tcpconn_attach(ns_client_t *source, ns_client_t *target) { + static void + tcpconn_detach(ns_client_t *client) { + ns_tcpconn_t *tconn = NULL; +- int refs; ++ int old_clients; + + REQUIRE(client->tcpconn != NULL); + + tconn = client->tcpconn; + client->tcpconn = NULL; + +- isc_refcount_decrement(&tconn->refs, &refs); +- if (refs == 0) { ++ isc_refcount_decrement(&tconn->clients, &old_clients); ++ if (old_clients == 0) { + isc_quota_detach(&tconn->tcpquota); + isc_mem_free(ns_g_mctx, tconn); + } +@@ -2648,7 +2648,7 @@ client_request(isc_task_t *task, isc_event_t *event) { + * Limit the maximum number of simultaenous pipelined + * queries on TCP connection to TCP_CLIENTS_PER_CONN. + */ +- if ((isc_refcount_current(&client->tcpconn->refs) ++ if ((isc_refcount_current(&client->tcpconn->clients) + > TCP_CLIENTS_PER_CONN)) + { + client->tcpconn->pipelined = false; +diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h +index 5ae10ae..01b6141 100644 +--- a/bin/named/include/named/client.h ++++ b/bin/named/include/named/client.h +@@ -80,7 +80,7 @@ + + /*% reference-counted TCP connection object */ + typedef struct ns_tcpconn { +- isc_refcount_t refs; /* Number of clients using ++ isc_refcount_t clients; /* Number of clients using + * this connection. Conn can + * be freed if goes to 0 + */ diff --git a/debian/patches/0018-CVE-2020-8616.patch b/debian/patches/0018-CVE-2020-8616.patch new file mode 100644 index 0000000..1342140 --- /dev/null +++ b/debian/patches/0018-CVE-2020-8616.patch @@ -0,0 +1,212 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@debian.org> +Date: Thu, 14 May 2020 12:24:03 +0200 +Subject: CVE-2020-8616 + +--- + lib/dns/adb.c | 33 ++++++++++++++++------------ + lib/dns/include/dns/adb.h | 4 ++++ + lib/dns/resolver.c | 55 +++++++++++++++++++++++++++++++---------------- + 3 files changed, 60 insertions(+), 32 deletions(-) + +diff --git a/lib/dns/adb.c b/lib/dns/adb.c +index 956f368..55fa416 100644 +--- a/lib/dns/adb.c ++++ b/lib/dns/adb.c +@@ -404,14 +404,13 @@ static void log_quota(dns_adbentry_t *entry, const char *fmt, ...) + */ + #define FIND_WANTEVENT(fn) (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0) + #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) +-#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \ +- != 0) +-#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) \ +- != 0) +-#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) +-#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) +-#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) +-#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) ++#define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) != 0) ++#define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) != 0) ++#define FIND_HINTOK(fn) (((fn)->options & DNS_ADBFIND_HINTOK) != 0) ++#define FIND_GLUEOK(fn) (((fn)->options & DNS_ADBFIND_GLUEOK) != 0) ++#define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) ++#define FIND_RETURNLAME(fn) (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0) ++#define FIND_NOFETCH(fn) (((fn)->options & DNS_ADBFIND_NOFETCH) != 0) + + /* + * These are currently used on simple unsigned ints, so they are +@@ -3155,21 +3154,26 @@ dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, + * Listen to negative cache hints, and don't start + * another query. + */ +- if (NCACHE_RESULT(result) || AUTH_NX(result)) ++ if (NCACHE_RESULT(result) || AUTH_NX(result)) { + goto fetch; ++ } + +- if (!NAME_FETCH_V6(adbname)) ++ if (!NAME_FETCH_V6(adbname)) { + wanted_fetches |= DNS_ADBFIND_INET6; ++ } + } + + fetch: + if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) || + (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname))) ++ { + have_address = true; +- else ++ } else { + have_address = false; +- if (wanted_fetches != 0 && +- ! (FIND_AVOIDFETCHES(find) && have_address)) { ++ } ++ if (wanted_fetches != 0 && !(FIND_AVOIDFETCHES(find) && have_address) && ++ !FIND_NOFETCH(find)) ++ { + /* + * We're missing at least one address family. Either the + * caller hasn't instructed us to avoid fetches, or we don't +@@ -3177,8 +3181,9 @@ dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, + * be acceptable so we have to launch fetches. + */ + +- if (FIND_STARTATZONE(find)) ++ if (FIND_STARTATZONE(find)) { + start_at_zone = true; ++ } + + /* + * Start V4. +diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h +index ca35bac..3e27c9e 100644 +--- a/lib/dns/include/dns/adb.h ++++ b/lib/dns/include/dns/adb.h +@@ -207,6 +207,10 @@ struct dns_adbfind { + * lame for this query. + */ + #define DNS_ADBFIND_OVERQUOTA 0x00000400 ++/*% ++ * Don't perform a fetch even if there are no address records available. ++ */ ++#define DNS_ADBFIND_NOFETCH 0x00000800 + + /*% + * The answers to queries come back as a list of these. +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 1d76504..1e4fcab 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -177,6 +177,14 @@ + #define DEFAULT_MAX_QUERIES 75 + #endif + ++/* ++ * After NS_FAIL_LIMIT attempts to fetch a name server address, ++ * if the number of addresses in the NS RRset exceeds NS_RR_LIMIT, ++ * stop trying to fetch, in order to avoid wasting resources. ++ */ ++#define NS_FAIL_LIMIT 4 ++#define NS_RR_LIMIT 5 ++ + /* Number of hash buckets for zone counters */ + #ifndef RES_DOMAIN_BUCKETS + #define RES_DOMAIN_BUCKETS 523 +@@ -3089,8 +3097,7 @@ sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) { + static void + findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, + unsigned int options, unsigned int flags, isc_stdtime_t now, +- bool *overquota, bool *need_alternate) +-{ ++ bool *overquota, bool *need_alternate, unsigned int *no_addresses) { + dns_adbaddrinfo_t *ai; + dns_adbfind_t *find; + dns_resolver_t *res; +@@ -3178,7 +3185,12 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, + find->result_v6 != DNS_R_NXDOMAIN) || + (res->dispatches6 == NULL && + find->result_v4 != DNS_R_NXDOMAIN))) ++ { + *need_alternate = true; ++ } ++ if (no_addresses != NULL) { ++ (*no_addresses)++; ++ } + } else { + if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) { + if (overquota != NULL) +@@ -3229,6 +3241,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { + dns_rdata_ns_t ns; + bool need_alternate = false; + bool all_spilled = true; ++ unsigned int no_addresses = 0; + + FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth); + +@@ -3384,20 +3397,28 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { + * Extract the name from the NS record. + */ + result = dns_rdata_tostruct(&rdata, &ns, NULL); +- if (result != ISC_R_SUCCESS) ++ if (result != ISC_R_SUCCESS) { + continue; ++ } + +- findname(fctx, &ns.name, 0, stdoptions, 0, now, +- &overquota, &need_alternate); ++ if (no_addresses > NS_FAIL_LIMIT && ++ dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT) ++ { ++ stdoptions |= DNS_ADBFIND_NOFETCH; ++ } ++ findname(fctx, &ns.name, 0, stdoptions, 0, now, &overquota, ++ &need_alternate, &no_addresses); + +- if (!overquota) ++ if (!overquota) { + all_spilled = false; ++ } + + dns_rdata_reset(&rdata); + dns_rdata_freestruct(&ns); + } +- if (result != ISC_R_NOMORE) ++ if (result != ISC_R_NOMORE) { + return (result); ++ } + + /* + * Do we need to use 6 to 4? +@@ -3412,7 +3433,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { + if (!a->isaddress) { + findname(fctx, &a->_u._n.name, a->_u._n.port, + stdoptions, FCTX_ADDRINFO_FORWARDER, +- now, NULL, NULL); ++ now, NULL, NULL, NULL); + continue; + } + if (isc_sockaddr_pf(&a->_u.addr) != family) +@@ -3774,16 +3795,14 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { + } + } + +- if (dns_name_countlabels(&fctx->domain) > 2) { +- result = isc_counter_increment(fctx->qc); +- if (result != ISC_R_SUCCESS) { +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), +- "exceeded max queries resolving '%s'", +- fctx->info); +- fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); +- return; +- } ++ result = isc_counter_increment(fctx->qc); ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), ++ "exceeded max queries resolving '%s'", ++ fctx->info); ++ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); ++ return; + } + + bucketnum = fctx->bucketnum; diff --git a/debian/patches/0019-CVE-2020-8617.patch b/debian/patches/0019-CVE-2020-8617.patch new file mode 100644 index 0000000..63e84d3 --- /dev/null +++ b/debian/patches/0019-CVE-2020-8617.patch @@ -0,0 +1,33 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@debian.org> +Date: Thu, 14 May 2020 12:24:23 +0200 +Subject: CVE-2020-8617 + +--- + lib/dns/tsig.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c +index a94ec69..ff40b99 100644 +--- a/lib/dns/tsig.c ++++ b/lib/dns/tsig.c +@@ -1422,8 +1422,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + goto cleanup_context; + } + msg->verified_sig = 1; +- } else if (tsig.error != dns_tsigerror_badsig && +- tsig.error != dns_tsigerror_badkey) { ++ } else if (!response || (tsig.error != dns_tsigerror_badsig && ++ tsig.error != dns_tsigerror_badkey)) ++ { + tsig_log(msg->tsigkey, 2, "signature was empty"); + return (DNS_R_TSIGVERIFYFAILURE); + } +@@ -1489,7 +1490,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + } + } + +- if (tsig.error != dns_rcode_noerror) { ++ if (response && tsig.error != dns_rcode_noerror) { + msg->tsigstatus = tsig.error; + if (tsig.error == dns_tsigerror_badtime) + ret = DNS_R_CLOCKSKEW; diff --git a/debian/patches/0020-Remove-INSIST-from-from-new_reference.patch b/debian/patches/0020-Remove-INSIST-from-from-new_reference.patch new file mode 100644 index 0000000..5880fd5 --- /dev/null +++ b/debian/patches/0020-Remove-INSIST-from-from-new_reference.patch @@ -0,0 +1,568 @@ +From: Mark Andrews <marka@isc.org> +Date: Tue, 2 Jun 2020 12:38:40 +1000 +Subject: Remove INSIST from from new_reference + +RBTDB node can now appear on the deadnodes lists following the changes +to decrement_reference in 176b23b6cd98e5b58f832902fdbe964ee5f762d0 to +defer checking of node->down when the tree write lock is not held. The +node should be unlinked instead. + +(cherry picked from commit b8c4efb10fc8ef1489120a8169fea42adf97025e) +--- + lib/dns/rbtdb.c | 238 +++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 142 insertions(+), 96 deletions(-) + +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index 0861139..792c443 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -2069,11 +2069,16 @@ delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { + * Caller must be holding the node lock. + */ + static inline void +-new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { ++new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, ++ isc_rwlocktype_t locktype) { + unsigned int lockrefs, noderefs; + isc_refcount_t *lockref; + +- INSIST(!ISC_LINK_LINKED(node, deadlink)); ++ if (locktype == isc_rwlocktype_write && ISC_LINK_LINKED(node, deadlink)) ++ { ++ ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node, ++ deadlink); ++ } + dns_rbtnode_refincrement0(node, &noderefs); + if (noderefs == 1) { /* this is the first reference to the node */ + lockref = &rbtdb->node_locks[node->locknum].references; +@@ -2119,7 +2124,7 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { + prune_tree, node, + sizeof(isc_event_t)); + if (ev != NULL) { +- new_reference(rbtdb, node); ++ new_reference(rbtdb, node, isc_rwlocktype_write); + db = NULL; + attach((dns_db_t *)rbtdb, &db); + ev->ev_sender = db; +@@ -2183,7 +2188,7 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + cleanup_dead_nodes(rbtdb, node->locknum); + } + +- new_reference(rbtdb, node); ++ new_reference(rbtdb, node, locktype); + + NODE_WEAKUNLOCK(nodelock, locktype); + NODE_STRONGUNLOCK(nodelock); +@@ -2329,7 +2334,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + prune_tree, node, + sizeof(isc_event_t)); + if (ev != NULL) { +- new_reference(rbtdb, node); ++ new_reference(rbtdb, node, isc_rwlocktype_write); + db = NULL; + attach((dns_db_t *)rbtdb, &db); + ev->ev_sender = db; +@@ -2361,8 +2366,10 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + } + } else { + INSIST(node->data == NULL); +- INSIST(!ISC_LINK_LINKED(node, deadlink)); +- ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink); ++ if (!ISC_LINK_LINKED(node, deadlink)) { ++ ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, ++ deadlink); ++ } + } + + restore_locks: +@@ -2427,17 +2434,16 @@ prune_tree(isc_task_t *task, isc_event_t *event) { + + /* + * We need to gain a reference to the node before +- * decrementing it in the next iteration. In addition, +- * if the node is in the dead-nodes list, extract it +- * from the list beforehand as we do in +- * reactivate_node(). ++ * decrementing it in the next iteration. + */ +- if (ISC_LINK_LINKED(parent, deadlink)) ++ if (ISC_LINK_LINKED(parent, deadlink)) { + ISC_LIST_UNLINK(rbtdb->deadnodes[locknum], + parent, deadlink); +- new_reference(rbtdb, parent); +- } else ++ } ++ new_reference(rbtdb, parent, isc_rwlocktype_write); ++ } else { + parent = NULL; ++ } + + node = parent; + } while (node != NULL); +@@ -3219,7 +3225,7 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { + * We increment the reference count on node to ensure that + * search->zonecut_rdataset will still be valid later. + */ +- new_reference(search->rbtdb, node); ++ new_reference(search->rbtdb, node, isc_rwlocktype_read); + search->zonecut = node; + search->zonecut_rdataset = found; + search->need_cleanup = true; +@@ -3270,11 +3276,10 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { + } + + static inline void +-bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, +- rdatasetheader_t *header, isc_stdtime_t now, +- dns_rdataset_t *rdataset) +-{ +- unsigned char *raw; /* RDATASLAB */ ++bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header, ++ isc_stdtime_t now, isc_rwlocktype_t locktype, ++ dns_rdataset_t *rdataset) { ++ unsigned char *raw; /* RDATASLAB */ + + /* + * Caller must be holding the node reader lock. +@@ -3287,7 +3292,7 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + if (rdataset == NULL) + return; + +- new_reference(rbtdb, node); ++ new_reference(rbtdb, node, locktype); + + INSIST(rdataset->methods == NULL); /* We must be disassociated. */ + +@@ -3382,11 +3387,13 @@ setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep, + NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock), + isc_rwlocktype_read); + bind_rdataset(search->rbtdb, node, search->zonecut_rdataset, +- search->now, rdataset); ++ search->now, isc_rwlocktype_read, rdataset); + if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL) ++ { + bind_rdataset(search->rbtdb, node, +- search->zonecut_sigrdataset, +- search->now, sigrdataset); ++ search->zonecut_sigrdataset, search->now, ++ isc_rwlocktype_read, sigrdataset); ++ } + NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock), + isc_rwlocktype_read); + } +@@ -4045,19 +4052,22 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep, + foundname, NULL); + if (result == ISC_R_SUCCESS) { + if (nodep != NULL) { +- new_reference(search->rbtdb, +- node); ++ new_reference( ++ search->rbtdb, node, ++ isc_rwlocktype_read); + *nodep = node; + } + bind_rdataset(search->rbtdb, node, + found, search->now, ++ isc_rwlocktype_read, + rdataset); +- if (foundsig != NULL) +- bind_rdataset(search->rbtdb, +- node, +- foundsig, +- search->now, +- sigrdataset); ++ if (foundsig != NULL) { ++ bind_rdataset( ++ search->rbtdb, node, ++ foundsig, search->now, ++ isc_rwlocktype_read, ++ sigrdataset); ++ } + } + } else if (found == NULL && foundsig == NULL) { + /* +@@ -4331,7 +4341,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + * ensure that search->zonecut_rdataset will + * still be valid later. + */ +- new_reference(search.rbtdb, node); ++ new_reference(search.rbtdb, node, ++ isc_rwlocktype_read); + search.zonecut = node; + search.zonecut_rdataset = header; + search.zonecut_sigrdataset = NULL; +@@ -4504,18 +4515,19 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + goto node_exit; + } + if (nodep != NULL) { +- new_reference(search.rbtdb, node); ++ new_reference(search.rbtdb, node, isc_rwlocktype_read); + *nodep = node; + } + if ((search.rbtversion->secure == dns_db_secure && + !search.rbtversion->havensec3) || + (search.options & DNS_DBFIND_FORCENSEC) != 0) + { +- bind_rdataset(search.rbtdb, node, nsecheader, +- 0, rdataset); +- if (nsecsig != NULL) +- bind_rdataset(search.rbtdb, node, +- nsecsig, 0, sigrdataset); ++ bind_rdataset(search.rbtdb, node, nsecheader, 0, ++ isc_rwlocktype_read, rdataset); ++ if (nsecsig != NULL) { ++ bind_rdataset(search.rbtdb, node, nsecsig, 0, ++ isc_rwlocktype_read, sigrdataset); ++ } + } + if (wild) + foundname->attributes |= DNS_NAMEATTR_WILDCARD; +@@ -4581,18 +4593,21 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + } + + if (nodep != NULL) { +- if (!at_zonecut) +- new_reference(search.rbtdb, node); +- else ++ if (!at_zonecut) { ++ new_reference(search.rbtdb, node, isc_rwlocktype_read); ++ } else { + search.need_cleanup = false; ++ } + *nodep = node; + } + + if (type != dns_rdatatype_any) { +- bind_rdataset(search.rbtdb, node, found, 0, rdataset); +- if (foundsig != NULL) ++ bind_rdataset(search.rbtdb, node, found, 0, isc_rwlocktype_read, ++ rdataset); ++ if (foundsig != NULL) { + bind_rdataset(search.rbtdb, node, foundsig, 0, +- sigrdataset); ++ isc_rwlocktype_read, sigrdataset); ++ } + } + + if (wild) +@@ -4762,8 +4777,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { + * We increment the reference count on node to ensure that + * search->zonecut_rdataset will still be valid later. + */ +- new_reference(search->rbtdb, node); +- INSIST(!ISC_LINK_LINKED(node, deadlink)); ++ new_reference(search->rbtdb, node, locktype); + search->zonecut = node; + search->zonecut_rdataset = dname_header; + search->zonecut_sigrdataset = sigdname_header; +@@ -4869,14 +4883,16 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, + } + result = DNS_R_DELEGATION; + if (nodep != NULL) { +- new_reference(search->rbtdb, node); ++ new_reference(search->rbtdb, node, locktype); + *nodep = node; + } + bind_rdataset(search->rbtdb, node, found, search->now, +- rdataset); +- if (foundsig != NULL) ++ locktype, rdataset); ++ if (foundsig != NULL) { + bind_rdataset(search->rbtdb, node, foundsig, +- search->now, sigrdataset); ++ search->now, locktype, ++ sigrdataset); ++ } + if (need_headerupdate(found, search->now) || + (foundsig != NULL && + need_headerupdate(foundsig, search->now))) { +@@ -4968,14 +4984,16 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep, + if (found != NULL) { + result = dns_name_concatenate(name, origin, + foundname, NULL); +- if (result != ISC_R_SUCCESS) ++ if (result != ISC_R_SUCCESS) { + goto unlock_node; +- bind_rdataset(search->rbtdb, node, found, +- now, rdataset); +- if (foundsig != NULL) ++ } ++ bind_rdataset(search->rbtdb, node, found, now, locktype, ++ rdataset); ++ if (foundsig != NULL) { + bind_rdataset(search->rbtdb, node, foundsig, +- now, sigrdataset); +- new_reference(search->rbtdb, node); ++ now, locktype, sigrdataset); ++ } ++ new_reference(search->rbtdb, node, locktype); + *nodep = node; + result = DNS_R_COVERINGNSEC; + } else if (!empty_node) { +@@ -5230,19 +5248,21 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + */ + if (nsheader != NULL) { + if (nodep != NULL) { +- new_reference(search.rbtdb, node); +- INSIST(!ISC_LINK_LINKED(node, deadlink)); ++ new_reference(search.rbtdb, node, locktype); + *nodep = node; + } + bind_rdataset(search.rbtdb, node, nsheader, search.now, +- rdataset); +- if (need_headerupdate(nsheader, search.now)) ++ locktype, rdataset); ++ if (need_headerupdate(nsheader, search.now)) { + update = nsheader; ++ } + if (nssig != NULL) { + bind_rdataset(search.rbtdb, node, nssig, +- search.now, sigrdataset); +- if (need_headerupdate(nssig, search.now)) ++ search.now, locktype, ++ sigrdataset); ++ if (need_headerupdate(nssig, search.now)) { + updatesig = nssig; ++ } + } + result = DNS_R_DELEGATION; + goto node_exit; +@@ -5260,8 +5280,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + */ + + if (nodep != NULL) { +- new_reference(search.rbtdb, node); +- INSIST(!ISC_LINK_LINKED(node, deadlink)); ++ new_reference(search.rbtdb, node, locktype); + *nodep = node; + } + +@@ -5290,16 +5309,19 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, + } + + if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN || +- result == DNS_R_NCACHENXRRSET) { +- bind_rdataset(search.rbtdb, node, found, search.now, ++ result == DNS_R_NCACHENXRRSET) ++ { ++ bind_rdataset(search.rbtdb, node, found, search.now, locktype, + rdataset); +- if (need_headerupdate(found, search.now)) ++ if (need_headerupdate(found, search.now)) { + update = found; ++ } + if (!NEGATIVE(found) && foundsig != NULL) { + bind_rdataset(search.rbtdb, node, foundsig, search.now, +- sigrdataset); +- if (need_headerupdate(foundsig, search.now)) ++ locktype, sigrdataset); ++ if (need_headerupdate(foundsig, search.now)) { + updatesig = foundsig; ++ } + } + } + +@@ -5445,15 +5467,16 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, + } + + if (nodep != NULL) { +- new_reference(search.rbtdb, node); +- INSIST(!ISC_LINK_LINKED(node, deadlink)); ++ new_reference(search.rbtdb, node, locktype); + *nodep = node; + } + +- bind_rdataset(search.rbtdb, node, found, search.now, rdataset); +- if (foundsig != NULL) ++ bind_rdataset(search.rbtdb, node, found, search.now, locktype, ++ rdataset); ++ if (foundsig != NULL) { + bind_rdataset(search.rbtdb, node, foundsig, search.now, +- sigrdataset); ++ locktype, sigrdataset); ++ } + + if (need_headerupdate(found, search.now) || + (foundsig != NULL && need_headerupdate(foundsig, search.now))) { +@@ -5804,10 +5827,12 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + } + } + if (found != NULL) { +- bind_rdataset(rbtdb, rbtnode, found, now, rdataset); +- if (foundsig != NULL) ++ bind_rdataset(rbtdb, rbtnode, found, now, isc_rwlocktype_read, ++ rdataset); ++ if (foundsig != NULL) { + bind_rdataset(rbtdb, rbtnode, foundsig, now, +- sigrdataset); ++ isc_rwlocktype_read, sigrdataset); ++ } + } + + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, +@@ -5892,10 +5917,11 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + } + } + if (found != NULL) { +- bind_rdataset(rbtdb, rbtnode, found, now, rdataset); +- if (!NEGATIVE(found) && foundsig != NULL) +- bind_rdataset(rbtdb, rbtnode, foundsig, now, ++ bind_rdataset(rbtdb, rbtnode, found, now, locktype, rdataset); ++ if (!NEGATIVE(found) && foundsig != NULL) { ++ bind_rdataset(rbtdb, rbtnode, foundsig, now, locktype, + sigrdataset); ++ } + } + + NODE_UNLOCK(lock, locktype); +@@ -6061,6 +6087,9 @@ resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) { + return (result); + } + ++/* ++ * node write lock must be held. ++ */ + static void + resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version, + rdatasetheader_t *header) +@@ -6073,7 +6102,8 @@ resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version, + header->heap_index); + header->heap_index = 0; + if (version != NULL) { +- new_reference(rbtdb, header->node); ++ new_reference(rbtdb, header->node, ++ isc_rwlocktype_write); + ISC_LIST_APPEND(version->resigned_list, header, link); + } + } +@@ -6095,6 +6125,9 @@ update_recordsandbytes(bool add, rbtdb_version_t *rbtversion, + } + } + ++/* ++ * write lock on rbtnode must be held. ++ */ + static isc_result_t + add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + rdatasetheader_t *newheader, unsigned int options, bool loading, +@@ -6218,10 +6251,13 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + free_rdataset(rbtdb, + rbtdb->common.mctx, + newheader); +- if (addedrdataset != NULL) +- bind_rdataset(rbtdb, rbtnode, +- topheader, now, +- addedrdataset); ++ if (addedrdataset != NULL) { ++ bind_rdataset( ++ rbtdb, rbtnode, ++ topheader, now, ++ isc_rwlocktype_write, ++ addedrdataset); ++ } + return (DNS_R_UNCHANGED); + } + /* +@@ -6275,6 +6311,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); + if (addedrdataset != NULL) + bind_rdataset(rbtdb, rbtnode, header, now, ++ isc_rwlocktype_write, + addedrdataset); + return (DNS_R_UNCHANGED); + } +@@ -6374,6 +6411,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); + if (addedrdataset != NULL) + bind_rdataset(rbtdb, rbtnode, header, now, ++ isc_rwlocktype_write, + addedrdataset); + return (ISC_R_SUCCESS); + } +@@ -6420,6 +6458,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + free_rdataset(rbtdb, rbtdb->common.mctx, newheader); + if (addedrdataset != NULL) + bind_rdataset(rbtdb, rbtnode, header, now, ++ isc_rwlocktype_write, + addedrdataset); + return (ISC_R_SUCCESS); + } +@@ -6617,8 +6656,10 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, + cname_and_other_data(rbtnode, rbtversion->serial)) + return (DNS_R_CNAMEANDOTHER); + +- if (addedrdataset != NULL) +- bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset); ++ if (addedrdataset != NULL) { ++ bind_rdataset(rbtdb, rbtnode, newheader, now, ++ isc_rwlocktype_write, addedrdataset); ++ } + + return (ISC_R_SUCCESS); + } +@@ -7141,12 +7182,17 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + result = DNS_R_UNCHANGED; + } + +- if (result == ISC_R_SUCCESS && newrdataset != NULL) +- bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset); ++ if (result == ISC_R_SUCCESS && newrdataset != NULL) { ++ bind_rdataset(rbtdb, rbtnode, newheader, 0, ++ isc_rwlocktype_write, newrdataset); ++ } + + if (result == DNS_R_NXRRSET && newrdataset != NULL && + (options & DNS_DBSUB_WANTOLD) != 0) +- bind_rdataset(rbtdb, rbtnode, header, 0, newrdataset); ++ { ++ bind_rdataset(rbtdb, rbtnode, header, 0, isc_rwlocktype_write, ++ newrdataset); ++ } + + unlock: + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, +@@ -8057,7 +8103,7 @@ getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { + onode = (dns_rbtnode_t *)rbtdb->origin_node; + if (onode != NULL) { + NODE_STRONGLOCK(&rbtdb->node_locks[onode->locknum].lock); +- new_reference(rbtdb, onode); ++ new_reference(rbtdb, onode, isc_rwlocktype_none); + NODE_STRONGUNLOCK(&rbtdb->node_locks[onode->locknum].lock); + + *nodep = rbtdb->origin_node; +@@ -8222,7 +8268,7 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, + if (header == NULL) + goto unlock; + +- bind_rdataset(rbtdb, header->node, header, 0, rdataset); ++ bind_rdataset(rbtdb, header->node, header, 0, isc_rwlocktype_read, rdataset); + + if (foundname != NULL) + dns_rbt_fullnamefromnode(header->node, foundname); +@@ -9214,7 +9260,7 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) { + isc_rwlocktype_read); + + bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now, +- rdataset); ++ isc_rwlocktype_read, rdataset); + + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, + isc_rwlocktype_read); +@@ -9650,7 +9696,7 @@ dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, + result = ISC_R_SUCCESS; + + NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); +- new_reference(rbtdb, node); ++ new_reference(rbtdb, node, isc_rwlocktype_none); + NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); + + *nodep = rbtdbiter->node; +@@ -10405,7 +10451,7 @@ expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + * We first need to gain a new reference to the node to meet a + * requirement of decrement_reference(). + */ +- new_reference(rbtdb, header->node); ++ new_reference(rbtdb, header->node, isc_rwlocktype_write); + decrement_reference(rbtdb, header->node, 0, + isc_rwlocktype_write, + tree_locked ? isc_rwlocktype_write : diff --git a/debian/patches/0021-Always-keep-a-copy-of-the-message.patch b/debian/patches/0021-Always-keep-a-copy-of-the-message.patch new file mode 100644 index 0000000..4edc752 --- /dev/null +++ b/debian/patches/0021-Always-keep-a-copy-of-the-message.patch @@ -0,0 +1,55 @@ +From: Mark Andrews <marka@isc.org> +Date: Wed, 15 Jul 2020 16:07:51 +1000 +Subject: Always keep a copy of the message + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/6ed167ad0a647dff20c8cb08c944a7967df2d415 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-8622 + +this allows it to be available even when dns_message_parse() +returns a error. +--- + lib/dns/message.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/lib/dns/message.c b/lib/dns/message.c +index ac637a2..39ed80f 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1679,6 +1679,19 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, + msg->header_ok = 0; + msg->question_ok = 0; + ++ if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) { ++ isc_buffer_usedregion(&origsource, &msg->saved); ++ } else { ++ msg->saved.length = isc_buffer_usedlength(&origsource); ++ msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); ++ if (msg->saved.base == NULL) { ++ return (ISC_R_NOMEMORY); ++ } ++ memmove(msg->saved.base, isc_buffer_base(&origsource), ++ msg->saved.length); ++ msg->free_saved = 1; ++ } ++ + isc_buffer_remainingregion(source, &r); + if (r.length < DNS_MESSAGE_HEADERLEN) + return (ISC_R_UNEXPECTEDEND); +@@ -1754,17 +1767,6 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, + } + + truncated: +- if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) +- isc_buffer_usedregion(&origsource, &msg->saved); +- else { +- msg->saved.length = isc_buffer_usedlength(&origsource); +- msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length); +- if (msg->saved.base == NULL) +- return (ISC_R_NOMEMORY); +- memmove(msg->saved.base, isc_buffer_base(&origsource), +- msg->saved.length); +- msg->free_saved = 1; +- } + + if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) + return (DNS_R_RECOVERABLE); diff --git a/debian/patches/0022-Fix-crash-in-pk11_numbits-when-native-pkcs11-is-used.patch b/debian/patches/0022-Fix-crash-in-pk11_numbits-when-native-pkcs11-is-used.patch new file mode 100644 index 0000000..b321616 --- /dev/null +++ b/debian/patches/0022-Fix-crash-in-pk11_numbits-when-native-pkcs11-is-used.patch @@ -0,0 +1,400 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@isc.org> +Date: Tue, 21 Jul 2020 14:42:47 +0200 +Subject: Fix crash in pk11_numbits() when native-pkcs11 is used + +origin: https://gitlab.isc.org/isc-projects/bind9/commit/8d807cc21655eaa6e6a08afafeec3682c0f3f2ab +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-8623 + +When pk11_numbits() is passed a user provided input that contains all +zeroes (via crafted DNS message), it would crash with assertion +failure. Fix that by properly handling such input. + +[Salvatore Bonaccorso: Backport to 99.11.5.P4 which does not contain +9d15323e2484 ("Add small tweaks to the code to fix compilation when ISC +assertions are disabled")] +--- + lib/dns/pkcs11dh_link.c | 15 ++++++-- + lib/dns/pkcs11dsa_link.c | 8 ++++- + lib/dns/pkcs11rsa_link.c | 79 +++++++++++++++++++++++++++++++---------- + lib/isc/include/pk11/internal.h | 3 +- + lib/isc/pk11.c | 60 ++++++++++++++++++++----------- + 5 files changed, 121 insertions(+), 44 deletions(-) + +diff --git a/lib/dns/pkcs11dh_link.c b/lib/dns/pkcs11dh_link.c +index e2b60ea..4cd8e32 100644 +--- a/lib/dns/pkcs11dh_link.c ++++ b/lib/dns/pkcs11dh_link.c +@@ -748,6 +748,7 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) { + CK_BYTE *prime = NULL, *base = NULL, *pub = NULL; + CK_ATTRIBUTE *attr; + int special = 0; ++ unsigned int bits; + isc_result_t result; + + isc_buffer_remainingregion(data, &r); +@@ -852,7 +853,11 @@ pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) { + pub = r.base; + isc_region_consume(&r, publen); + +- key->key_size = pk11_numbits(prime, plen_); ++ result = pk11_numbits(prime, plen_, &bits); ++ if (result != ISC_R_SUCCESS) { ++ goto cleanup; ++ } ++ key->key_size = bits; + + dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); + if (dh->repr == NULL) +@@ -1012,6 +1017,7 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; + int i; ++ unsigned int bits; + pk11_object_t *dh = NULL; + CK_ATTRIBUTE *attr; + isc_mem_t *mctx; +@@ -1082,7 +1088,12 @@ pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + attr = pk11_attribute_bytype(dh, CKA_PRIME); + INSIST(attr != NULL); +- key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + return (ISC_R_SUCCESS); + +diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c +index 12d707a..24d4c14 100644 +--- a/lib/dns/pkcs11dsa_link.c ++++ b/lib/dns/pkcs11dsa_link.c +@@ -983,6 +983,7 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; + int i; ++ unsigned int bits; + pk11_object_t *dsa = NULL; + CK_ATTRIBUTE *attr; + isc_mem_t *mctx = key->mctx; +@@ -1072,7 +1073,12 @@ pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + attr = pk11_attribute_bytype(dsa, CKA_PRIME); + INSIST(attr != NULL); +- key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + return (ISC_R_SUCCESS); + +diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c +index eb782c8..57ee41d 100644 +--- a/lib/dns/pkcs11rsa_link.c ++++ b/lib/dns/pkcs11rsa_link.c +@@ -330,6 +330,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, + key->key_alg == DST_ALG_RSASHA256 || + key->key_alg == DST_ALG_RSASHA512); + #endif ++ REQUIRE(maxbits <= RSA_MAX_PUBEXP_BITS); + + /* + * Reject incorrect RSA key lengths. +@@ -373,6 +374,7 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, + for (attr = pk11_attribute_first(rsa); + attr != NULL; + attr = pk11_attribute_next(rsa, attr)) ++ { + switch (attr->type) { + case CKA_MODULUS: + INSIST(keyTemplate[5].type == attr->type); +@@ -393,12 +395,16 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, + memmove(keyTemplate[6].pValue, attr->pValue, + attr->ulValueLen); + keyTemplate[6].ulValueLen = attr->ulValueLen; +- if (pk11_numbits(attr->pValue, +- attr->ulValueLen) > maxbits && +- maxbits != 0) ++ unsigned int bits; ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, ++ &bits); ++ if (ret != ISC_R_SUCCESS || ++ (bits > maxbits && maxbits != 0)) { + DST_RET(DST_R_VERIFYFAILURE); ++ } + break; + } ++ } + pk11_ctx->object = CK_INVALID_HANDLE; + pk11_ctx->ontoken = false; + PK11_RET(pkcs_C_CreateObject, +@@ -1063,6 +1069,7 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { + keyTemplate[5].ulValueLen = attr->ulValueLen; + break; + case CKA_PUBLIC_EXPONENT: ++ unsigned int bits; + INSIST(keyTemplate[6].type == attr->type); + keyTemplate[6].pValue = isc_mem_get(dctx->mctx, + attr->ulValueLen); +@@ -1071,10 +1078,12 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { + memmove(keyTemplate[6].pValue, attr->pValue, + attr->ulValueLen); + keyTemplate[6].ulValueLen = attr->ulValueLen; +- if (pk11_numbits(attr->pValue, +- attr->ulValueLen) +- > RSA_MAX_PUBEXP_BITS) ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, ++ &bits); ++ if (ret != ISC_R_SUCCESS || bits > RSA_MAX_PUBEXP_BITS) ++ { + DST_RET(DST_R_VERIFYFAILURE); ++ } + break; + } + pk11_ctx->object = CK_INVALID_HANDLE; +@@ -1451,6 +1460,8 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + CK_BYTE *exponent = NULL, *modulus = NULL; + CK_ATTRIBUTE *attr; + unsigned int length; ++ unsigned int bits; ++ isc_result_t ret = ISC_R_SUCCESS; + + isc_buffer_remainingregion(data, &r); + if (r.length == 0) +@@ -1468,9 +1479,7 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + + if (e_bytes == 0) { + if (r.length < 2) { +- isc_safe_memwipe(rsa, sizeof(*rsa)); +- isc_mem_put(key->mctx, rsa, sizeof(*rsa)); +- return (DST_R_INVALIDPUBLICKEY); ++ DST_RET(DST_R_INVALIDPUBLICKEY); + } + e_bytes = (*r.base) << 8; + isc_region_consume(&r, 1); +@@ -1479,16 +1488,18 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + } + + if (r.length < e_bytes) { +- isc_safe_memwipe(rsa, sizeof(*rsa)); +- isc_mem_put(key->mctx, rsa, sizeof(*rsa)); +- return (DST_R_INVALIDPUBLICKEY); ++ DST_RET(DST_R_INVALIDPUBLICKEY); + } + exponent = r.base; + isc_region_consume(&r, e_bytes); + modulus = r.base; + mod_bytes = r.length; + +- key->key_size = pk11_numbits(modulus, mod_bytes); ++ ret = pk11_numbits(modulus, mod_bytes, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + isc_buffer_forward(data, length); + +@@ -1538,9 +1549,12 @@ pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + rsa->repr, + rsa->attrcnt * sizeof(*attr)); + } ++ ret = ISC_R_NOMEMORY; ++ ++ err: + isc_safe_memwipe(rsa, sizeof(*rsa)); + isc_mem_put(key->mctx, rsa, sizeof(*rsa)); +- return (ISC_R_NOMEMORY); ++ return (ret); + } + + static isc_result_t +@@ -1719,6 +1733,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, + pk11_object_t *pubrsa; + pk11_context_t *pk11_ctx = NULL; + isc_result_t ret; ++ unsigned int bits; + + if (label == NULL) + return (DST_R_NOENGINE); +@@ -1803,7 +1818,11 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, + + attr = pk11_attribute_bytype(rsa, CKA_MODULUS); + INSIST(attr != NULL); +- key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + return (ISC_R_SUCCESS); + +@@ -1889,6 +1908,7 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + CK_ATTRIBUTE *attr; + isc_mem_t *mctx = key->mctx; + const char *engine = NULL, *label = NULL; ++ unsigned int bits; + + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); +@@ -2032,12 +2052,22 @@ pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + attr = pk11_attribute_bytype(rsa, CKA_MODULUS); + INSIST(attr != NULL); +- key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); + INSIST(attr != NULL); +- if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) ++ ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ if (bits > RSA_MAX_PUBEXP_BITS) { + DST_RET(ISC_R_RANGE); ++ } + + dst__privstruct_free(&priv, mctx); + isc_safe_memwipe(&priv, sizeof(priv)); +@@ -2072,6 +2102,7 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + pk11_context_t *pk11_ctx = NULL; + isc_result_t ret; + unsigned int i; ++ unsigned int bits; + + UNUSED(pin); + +@@ -2166,12 +2197,22 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + + attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); + INSIST(attr != NULL); +- if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) ++ ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ if (bits > RSA_MAX_PUBEXP_BITS) { + DST_RET(ISC_R_RANGE); ++ } + + attr = pk11_attribute_bytype(rsa, CKA_MODULUS); + INSIST(attr != NULL); +- key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ret = pk11_numbits(attr->pValue, attr->ulValueLen, &bits); ++ if (ret != ISC_R_SUCCESS) { ++ goto err; ++ } ++ key->key_size = bits; + + pk11_return_session(pk11_ctx); + isc_safe_memwipe(pk11_ctx, sizeof(*pk11_ctx)); +diff --git a/lib/isc/include/pk11/internal.h b/lib/isc/include/pk11/internal.h +index aa8907a..7cc8ec8 100644 +--- a/lib/isc/include/pk11/internal.h ++++ b/lib/isc/include/pk11/internal.h +@@ -25,7 +25,8 @@ void pk11_mem_put(void *ptr, size_t size); + + CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype); + +-unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt); ++isc_result_t ++pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits); + + CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj); + +diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c +index c5d2310..b2ab6be 100644 +--- a/lib/isc/pk11.c ++++ b/lib/isc/pk11.c +@@ -962,13 +962,15 @@ pk11_get_best_token(pk11_optype_t optype) { + return (token->slotid); + } + +-unsigned int +-pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) { ++isc_result_t ++pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt, unsigned int *bits) { + unsigned int bitcnt, i; + CK_BYTE top; + +- if (bytecnt == 0) +- return (0); ++ if (bytecnt == 0) { ++ *bits = 0; ++ return (ISC_R_SUCCESS); ++ } + bitcnt = bytecnt * 8; + for (i = 0; i < bytecnt; i++) { + top = data[i]; +@@ -976,25 +978,41 @@ pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) { + bitcnt -= 8; + continue; + } +- if (top & 0x80) +- return (bitcnt); +- if (top & 0x40) +- return (bitcnt - 1); +- if (top & 0x20) +- return (bitcnt - 2); +- if (top & 0x10) +- return (bitcnt - 3); +- if (top & 0x08) +- return (bitcnt - 4); +- if (top & 0x04) +- return (bitcnt - 5); +- if (top & 0x02) +- return (bitcnt - 6); +- if (top & 0x01) +- return (bitcnt - 7); ++ if (top & 0x80) { ++ *bits = bitcnt; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x40) { ++ *bits = bitcnt - 1; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x20) { ++ *bits = bitcnt - 2; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x10) { ++ *bits = bitcnt - 3; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x08) { ++ *bits = bitcnt - 4; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x04) { ++ *bits = bitcnt - 5; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x02) { ++ *bits = bitcnt - 6; ++ return (ISC_R_SUCCESS); ++ } ++ if (top & 0x01) { ++ *bits = bitcnt - 7; ++ return (ISC_R_SUCCESS); ++ } + break; + } +- INSIST(0); ++ return (ISC_R_RANGE); + } + + CK_ATTRIBUTE * diff --git a/debian/patches/0023-Wait-more-than-1-second-for-NSEC3-chain-changes.patch b/debian/patches/0023-Wait-more-than-1-second-for-NSEC3-chain-changes.patch new file mode 100644 index 0000000..6f2593c --- /dev/null +++ b/debian/patches/0023-Wait-more-than-1-second-for-NSEC3-chain-changes.patch @@ -0,0 +1,71 @@ +From: =?utf-8?b?TWljaGHFgiBLxJlwaWXFhA==?= <michal@isc.org> +Date: Tue, 23 Apr 2019 14:59:05 +0200 +Subject: Wait more than 1 second for NSEC3 chain changes + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/4e2cc911d2ceb90ec04605451fb1bb518ef75cd0 + +One second may not be enough for an NSEC3 chain change triggered by an +UPDATE message to complete. Wait up to 10 seconds when checking whether +a given NSEC3 chain change is complete in the "nsupdate" system test. + +(cherry picked from commit f8746cddbce838fec2a28f00617df6af1319fbc8) +--- + bin/tests/system/nsupdate/tests.sh | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh +index 9f26572..c72753b 100755 +--- a/bin/tests/system/nsupdate/tests.sh ++++ b/bin/tests/system/nsupdate/tests.sh +@@ -454,18 +454,24 @@ grep "flags:[^;]* aa[ ;]" dig.out.ns3.$n > /dev/null || ret=1 + + n=`expr $n + 1` + ret=0 +-echo_i "add a new the NSEC3PARAM via update ($n)" ++echo_i "add a new NSEC3PARAM via update ($n)" + $NSUPDATE << EOF + server 10.53.0.3 ${PORT} + update add nsec3param.test 3600 NSEC3PARAM 1 0 4 - + send + EOF + +-sleep 1 ++_ret=1 ++for i in 0 1 2 3 4 5 6 7 8 9; do ++ $DIG $DIGOPTS +tcp +norec +time=1 +tries=1 @10.53.0.3 nsec3param.test. NSEC3PARAM > dig.out.ns3.$n || _ret=1 ++ if grep "ANSWER: 2" dig.out.ns3.$n > /dev/null; then ++ _ret=0 ++ break ++ fi ++ sleep 1 ++done + +-$DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocmd +norec nsec3param.test.\ +- @10.53.0.3 nsec3param > dig.out.ns3.$n || ret=1 +-grep "ANSWER: 2" dig.out.ns3.$n > /dev/null || ret=1 ++if [ $_ret -ne 0 ]; then ret=1; fi + grep "NSEC3PARAM 1 0 4 -" dig.out.ns3.$n > /dev/null || ret=1 + grep "flags:[^;]* aa[ ;]" dig.out.ns3.$n > /dev/null || ret=1 + if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $ret + $status`; fi +@@ -480,11 +486,17 @@ update add nsec3param.test 7200 NSEC3PARAM 1 0 5 - + send + EOF + +-sleep 1 ++_ret=1 ++for i in 0 1 2 3 4 5 6 7 8 9; do ++ $DIG $DIGOPTS +tcp +norec +time=1 +tries=1 @10.53.0.3 nsec3param.test. NSEC3PARAM > dig.out.ns3.$n || _ret=1 ++ if grep "ANSWER: 1" dig.out.ns3.$n > /dev/null; then ++ _ret=0 ++ break ++ fi ++ sleep 1 ++done + +-$DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocmd +norec nsec3param.test.\ +- @10.53.0.3 nsec3param > dig.out.ns3.$n || ret=1 +-grep "ANSWER: 1" dig.out.ns3.$n > /dev/null || ret=1 ++if [ $_ret -ne 0 ]; then ret=1; fi + grep "7200.*NSEC3PARAM 1 0 5 -" dig.out.ns3.$n > /dev/null || ret=1 + grep "flags:[^;]* aa[ ;]" dig.out.ns3.$n > /dev/null || ret=1 + $JOURNALPRINT ns3/nsec3param.test.db.signed.jnl > jp.out.ns3.$n diff --git a/debian/patches/0024-Update-policy-subdomain-was-incorrectly-treated-as-z.patch b/debian/patches/0024-Update-policy-subdomain-was-incorrectly-treated-as-z.patch new file mode 100644 index 0000000..b2e6ac9 --- /dev/null +++ b/debian/patches/0024-Update-policy-subdomain-was-incorrectly-treated-as-z.patch @@ -0,0 +1,27 @@ +From: Mark Andrews <marka@isc.org> +Date: Wed, 29 Jul 2020 23:36:03 +1000 +Subject: [1/3] Update-policy 'subdomain' was incorrectly treated as 'zonesub' + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/e4cccf9668c7adee4724a7649ec64685f82c8677 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-8624 + +resulting in names outside the specified subdomain having the wrong +restrictions for the given key. +--- + bin/named/zoneconf.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c +index e237bdb..4898447 100644 +--- a/bin/named/zoneconf.c ++++ b/bin/named/zoneconf.c +@@ -237,7 +237,8 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone, + + str = cfg_obj_asstring(matchtype); + CHECK(dns_ssu_mtypefromstring(str, &mtype)); +- if (mtype == dns_ssumatchtype_subdomain) { ++ if (mtype == dns_ssumatchtype_subdomain && ++ strcasecmp(str, "zonesub") == 0) { + usezone = true; + } + diff --git a/debian/patches/0025-Add-a-test-for-update-policy-subdomain.patch b/debian/patches/0025-Add-a-test-for-update-policy-subdomain.patch new file mode 100644 index 0000000..adcc70d --- /dev/null +++ b/debian/patches/0025-Add-a-test-for-update-policy-subdomain.patch @@ -0,0 +1,73 @@ +From: Mark Andrews <marka@isc.org> +Date: Wed, 29 Jul 2020 23:36:03 +1000 +Subject: [2/3] Add a test for update-policy 'subdomain' + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/393e8f643c02215fa4e6d4edf67be7d77085da0e +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-8624 + +The new test checks that 'update-policy subdomain' is properly enforced. +--- + bin/tests/system/nsupdate/ns1/named.conf.in | 6 ++++++ + bin/tests/system/nsupdate/tests.sh | 25 +++++++++++++++++++++++++ + 2 files changed, 31 insertions(+) + +diff --git a/bin/tests/system/nsupdate/ns1/named.conf.in b/bin/tests/system/nsupdate/ns1/named.conf.in +index 1d999ad..87904f4 100644 +--- a/bin/tests/system/nsupdate/ns1/named.conf.in ++++ b/bin/tests/system/nsupdate/ns1/named.conf.in +@@ -36,6 +36,11 @@ key altkey { + secret "1234abcd8765"; + }; + ++key restricted.example.nil { ++ algorithm hmac-md5; ++ secret "1234abcd8765"; ++}; ++ + include "ddns.key"; + + zone "example.nil" { +@@ -45,6 +50,7 @@ zone "example.nil" { + check-mx ignore; + update-policy { + grant ddns-key.example.nil subdomain example.nil ANY; ++ grant restricted.example.nil subdomain restricted.example.nil ANY; + }; + allow-transfer { any; }; + }; +diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh +index c72753b..432240e 100755 +--- a/bin/tests/system/nsupdate/tests.sh ++++ b/bin/tests/system/nsupdate/tests.sh +@@ -635,6 +635,31 @@ then + echo_i "failed"; status=1 + fi + ++n=`expr $n + 1` ++ret=0 ++echo_i "check that 'update-policy subdomain' is properly enforced ($n)" ++# "restricted.example.nil" matches "grant ... subdomain restricted.example.nil" ++# and thus this UPDATE should succeed. ++$NSUPDATE -d <<END > nsupdate.out1-$n 2>&1 || ret=1 ++server 10.53.0.1 ${PORT} ++key restricted.example.nil 1234abcd8765 ++update add restricted.example.nil 0 IN TXT everywhere. ++send ++END ++$DIG $DIGOPTS +tcp @10.53.0.1 restricted.example.nil TXT > dig.out.1.test$n || ret=1 ++grep "TXT.*everywhere" dig.out.1.test$n > /dev/null || ret=1 ++# "example.nil" does not match "grant ... subdomain restricted.example.nil" and ++# thus this UPDATE should fail. ++$NSUPDATE -d <<END > nsupdate.out2-$n 2>&1 && ret=1 ++server 10.53.0.1 ${PORT} ++key restricted.example.nil 1234abcd8765 ++update add example.nil 0 IN TXT everywhere. ++send ++END ++$DIG $DIGOPTS +tcp @10.53.0.1 example.nil TXT > dig.out.2.test$n || ret=1 ++grep "TXT.*everywhere" dig.out.2.test$n > /dev/null && ret=1 ++[ $ret = 0 ] || { echo_i "failed"; status=1; } ++ + n=`expr $n + 1` + ret=0 + echo_i "check that changes to the DNSKEY RRset TTL do not have side effects ($n)" diff --git a/debian/patches/0026-Add-a-test-for-update-policy-zonesub.patch b/debian/patches/0026-Add-a-test-for-update-policy-zonesub.patch new file mode 100644 index 0000000..771c46c --- /dev/null +++ b/debian/patches/0026-Add-a-test-for-update-policy-zonesub.patch @@ -0,0 +1,111 @@ +From: Mark Andrews <marka@isc.org> +Date: Tue, 4 Aug 2020 11:41:33 +1000 +Subject: [3/3] Add a test for update-policy 'zonesub' + +Origin: https://gitlab.isc.org/isc-projects/bind9/commit/58e560beb50873c699f3431cf57e215dc645d7aa +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2020-8624 + +The new test checks that 'update-policy zonesub' is properly enforced. +--- + bin/tests/system/nsupdate/ns1/named.conf.in | 6 +++++ + bin/tests/system/nsupdate/tests.sh | 35 +++++++++++++++++++++++++---- + 2 files changed, 37 insertions(+), 4 deletions(-) + +diff --git a/bin/tests/system/nsupdate/ns1/named.conf.in b/bin/tests/system/nsupdate/ns1/named.conf.in +index 87904f4..e90907a 100644 +--- a/bin/tests/system/nsupdate/ns1/named.conf.in ++++ b/bin/tests/system/nsupdate/ns1/named.conf.in +@@ -41,6 +41,11 @@ key restricted.example.nil { + secret "1234abcd8765"; + }; + ++key zonesub-key.example.nil { ++ algorithm hmac-md5; ++ secret "1234subk8765"; ++}; ++ + include "ddns.key"; + + zone "example.nil" { +@@ -49,6 +54,7 @@ zone "example.nil" { + check-integrity no; + check-mx ignore; + update-policy { ++ grant zonesub-key.example.nil zonesub TXT; + grant ddns-key.example.nil subdomain example.nil ANY; + grant restricted.example.nil subdomain restricted.example.nil ANY; + }; +diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh +index 432240e..f2f26ab 100755 +--- a/bin/tests/system/nsupdate/tests.sh ++++ b/bin/tests/system/nsupdate/tests.sh +@@ -430,7 +430,7 @@ sleep 1 + # this also proves that the server is still running. + $DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocmd +norec example.\ + @10.53.0.3 nsec3param > dig.out.ns3.$n || ret=1 +-grep "ANSWER: 0" dig.out.ns3.$n > /dev/null || ret=1 ++grep "ANSWER: 0," dig.out.ns3.$n > /dev/null || ret=1 + grep "flags:[^;]* aa[ ;]" dig.out.ns3.$n > /dev/null || ret=1 + [ $ret = 0 ] || { echo_i "failed"; status=1; } + +@@ -447,7 +447,7 @@ sleep 1 + + $DIG $DIGOPTS +tcp +noadd +nosea +nostat +noquest +nocmd +norec nsec3param.test.\ + @10.53.0.3 nsec3param > dig.out.ns3.$n || ret=1 +-grep "ANSWER: 1" dig.out.ns3.$n > /dev/null || ret=1 ++grep "ANSWER: 1," dig.out.ns3.$n > /dev/null || ret=1 + grep "3600.*NSEC3PARAM" dig.out.ns3.$n > /dev/null || ret=1 + grep "flags:[^;]* aa[ ;]" dig.out.ns3.$n > /dev/null || ret=1 + [ $ret = 0 ] || { echo_i "failed"; status=1; } +@@ -464,7 +464,7 @@ EOF + _ret=1 + for i in 0 1 2 3 4 5 6 7 8 9; do + $DIG $DIGOPTS +tcp +norec +time=1 +tries=1 @10.53.0.3 nsec3param.test. NSEC3PARAM > dig.out.ns3.$n || _ret=1 +- if grep "ANSWER: 2" dig.out.ns3.$n > /dev/null; then ++ if grep "ANSWER: 2," dig.out.ns3.$n > /dev/null; then + _ret=0 + break + fi +@@ -489,7 +489,7 @@ EOF + _ret=1 + for i in 0 1 2 3 4 5 6 7 8 9; do + $DIG $DIGOPTS +tcp +norec +time=1 +tries=1 @10.53.0.3 nsec3param.test. NSEC3PARAM > dig.out.ns3.$n || _ret=1 +- if grep "ANSWER: 1" dig.out.ns3.$n > /dev/null; then ++ if grep "ANSWER: 1," dig.out.ns3.$n > /dev/null; then + _ret=0 + break + fi +@@ -660,6 +660,33 @@ $DIG $DIGOPTS +tcp @10.53.0.1 example.nil TXT > dig.out.2.test$n || ret=1 + grep "TXT.*everywhere" dig.out.2.test$n > /dev/null && ret=1 + [ $ret = 0 ] || { echo_i "failed"; status=1; } + ++n=`expr $n + 1` ++ret=0 ++echo_i "check that 'update-policy zonesub' is properly enforced ($n)" ++# grant zonesub-key.example.nil zonesub TXT; ++# the A record update should be rejected as it is not in the type list ++$NSUPDATE -d <<END > nsupdate.out1-$n 2>&1 && ret=1 ++server 10.53.0.1 ${PORT} ++key zonesub-key.example.nil 1234subk8765 ++update add zonesub.example.nil 0 IN A 1.2.3.4 ++send ++END ++$DIG $DIGOPTS +tcp @10.53.0.1 zonesub.example.nil A > dig.out.1.test$n || ret=1 ++grep "status: REFUSED" nsupdate.out1-$n > /dev/null || ret=1 ++grep "ANSWER: 0," dig.out.1.test$n > /dev/null || ret=1 ++# the TXT record update should be accepted as it is in the type list ++$NSUPDATE -d <<END > nsupdate.out2-$n 2>&1 || ret=1 ++server 10.53.0.1 ${PORT} ++key zonesub-key.example.nil 1234subk8765 ++update add zonesub.example.nil 0 IN TXT everywhere. ++send ++END ++$DIG $DIGOPTS +tcp @10.53.0.1 zonesub.example.nil TXT > dig.out.2.test$n || ret=1 ++grep "status: REFUSED" nsupdate.out2-$n > /dev/null && ret=1 ++grep "ANSWER: 1," dig.out.2.test$n > /dev/null || ret=1 ++grep "TXT.*everywhere" dig.out.2.test$n > /dev/null || ret=1 ++[ $ret = 0 ] || { echo_i "failed"; status=1; } ++ + n=`expr $n + 1` + ret=0 + echo_i "check that changes to the DNSKEY RRset TTL do not have side effects ($n)" diff --git a/debian/patches/0027-CVE-2020-8625.patch b/debian/patches/0027-CVE-2020-8625.patch new file mode 100644 index 0000000..1e036c8 --- /dev/null +++ b/debian/patches/0027-CVE-2020-8625.patch @@ -0,0 +1,25 @@ +From: Debian DNS Team <team+dns@tracker.debian.org> +Date: Thu, 29 Apr 2021 13:06:03 +0200 +Subject: Buffer overflow in GSSAPI security policy negotiation + (CVE-2020-8625) + +Origin: vendor +Forwarded: not-needed +Last-Update: 2021-02-09 +--- + lib/dns/spnego.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c +index ad77f24..28ead69 100644 +--- a/lib/dns/spnego.c ++++ b/lib/dns/spnego.c +@@ -877,7 +877,7 @@ der_get_oid(const unsigned char *p, size_t len, oid *data, size_t *size) { + return (ASN1_OVERRUN); + } + +- data->components = malloc(len * sizeof(*data->components)); ++ data->components = malloc((len + 1) * sizeof(*data->components)); + if (data->components == NULL) { + return (ENOMEM); + } diff --git a/debian/patches/0028-Free-resources-when-gss_accept_sec_context-fails.patch b/debian/patches/0028-Free-resources-when-gss_accept_sec_context-fails.patch new file mode 100644 index 0000000..b8ed135 --- /dev/null +++ b/debian/patches/0028-Free-resources-when-gss_accept_sec_context-fails.patch @@ -0,0 +1,28 @@ +From: =?utf-8?b?TWljaGHFgiBLxJlwaWXFhA==?= <michal@isc.org> +Date: Thu, 8 Apr 2021 10:33:44 +0200 +Subject: Free resources when gss_accept_sec_context() fails + +Even if a call to gss_accept_sec_context() fails, it might still cause a +GSS-API response token to be allocated and left for the caller to +release. Make sure the token is released before an early return from +dst_gssapi_acceptctx(). + +(cherry picked from commit d954e152d9f2901118b1fe36d3931ec244317fab) +--- + lib/dns/gssapictx.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c +index 8bd99af..6d787d3 100644 +--- a/lib/dns/gssapictx.c ++++ b/lib/dns/gssapictx.c +@@ -746,6 +746,9 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, + default: + gss_log(3, "failed gss_accept_sec_context: %s", + gss_error_tostring(gret, minor, buf, sizeof(buf))); ++ if (gouttoken.length > 0U) { ++ (void)gss_release_buffer(&minor, &gouttoken); ++ } + return (result); + } + diff --git a/debian/patches/0029-Check-SOA-owner-names-in-zone-transfers.patch b/debian/patches/0029-Check-SOA-owner-names-in-zone-transfers.patch new file mode 100644 index 0000000..5af5d36 --- /dev/null +++ b/debian/patches/0029-Check-SOA-owner-names-in-zone-transfers.patch @@ -0,0 +1,40 @@ +From: Mark Andrews <marka@isc.org> +Date: Wed, 3 Feb 2021 11:10:20 +1100 +Subject: Check SOA owner names in zone transfers + +An IXFR containing SOA records with owner names different than the +transferred zone's origin can result in named serving a version of that +zone without an SOA record at the apex. This causes a RUNTIME_CHECK +assertion failure the next time such a zone is refreshed. Fix by +immediately rejecting a zone transfer (either an incremental or +non-incremental one) upon detecting an SOA record not placed at the apex +of the transferred zone. +--- + lib/dns/xfrin.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c +index d39ca26..0baf170 100644 +--- a/lib/dns/xfrin.c ++++ b/lib/dns/xfrin.c +@@ -477,6 +477,20 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, uint32_t ttl, + dns_rdatatype_ismeta(rdata->type)) + FAIL(DNS_R_FORMERR); + ++ /* ++ * Immediately reject the entire transfer if the RR that is currently ++ * being processed is an SOA record that is not placed at the zone ++ * apex. ++ */ ++ if (rdata->type == dns_rdatatype_soa && ++ !dns_name_equal(&xfr->name, name)) { ++ char namebuf[DNS_NAME_FORMATSIZE]; ++ dns_name_format(name, namebuf, sizeof(namebuf)); ++ xfrin_log(xfr, ISC_LOG_DEBUG(3), "SOA name mismatch: '%s'", ++ namebuf); ++ FAIL(DNS_R_NOTZONETOP); ++ } ++ + redo: + switch (xfr->state) { + case XFRST_SOAQUERY: diff --git a/debian/patches/0030-Address-inconsistencies-in-checking-added-RRsets.patch b/debian/patches/0030-Address-inconsistencies-in-checking-added-RRsets.patch new file mode 100644 index 0000000..23a1b29 --- /dev/null +++ b/debian/patches/0030-Address-inconsistencies-in-checking-added-RRsets.patch @@ -0,0 +1,46 @@ +From: Mark Andrews <marka@isc.org> +Date: Fri, 12 Feb 2021 14:51:28 +1100 +Subject: Address inconsistencies in checking added RRsets + +loading_addrdataset() rejects SOA RRsets which are not at top of zone. +addrdataset() should similarly reject such RRsets. +--- + lib/dns/rbtdb.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index 792c443..b1b928c 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -117,7 +117,7 @@ struct rbtdb_file_header { + /*% + * Note that "impmagic" is not the first four bytes of the struct, so + * ISC_MAGIC_VALID cannot be used. +- */ ++a */ + #define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \ + (rbtdb)->common.impmagic == RBTDB_MAGIC) + +@@ -6806,13 +6806,21 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + REQUIRE(VALID_RBTDB(rbtdb)); + INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb); + +- if (rbtdb->common.methods == &zone_methods) ++ if (rbtdb->common.methods == &zone_methods) { ++ /* ++ * SOA records are only allowed at top of zone. ++ */ ++ if (rdataset->type == dns_rdatatype_soa && ++ node != rbtdb->origin_node) { ++ return (DNS_R_NOTZONETOP); ++ } + REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && + (rdataset->type == dns_rdatatype_nsec3 || + rdataset->covers == dns_rdatatype_nsec3)) || + (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && + rdataset->type != dns_rdatatype_nsec3 && + rdataset->covers != dns_rdatatype_nsec3))); ++ } + + if (rbtversion == NULL) { + if (now == 0) diff --git a/debian/patches/0031-Unload-a-zone-if-a-transfer-breaks-its-SOA-record.patch b/debian/patches/0031-Unload-a-zone-if-a-transfer-breaks-its-SOA-record.patch new file mode 100644 index 0000000..93c75ec --- /dev/null +++ b/debian/patches/0031-Unload-a-zone-if-a-transfer-breaks-its-SOA-record.patch @@ -0,0 +1,40 @@ +From: Mark Andrews <marka@isc.org> +Date: Thu, 25 Feb 2021 14:11:05 +1100 +Subject: Unload a zone if a transfer breaks its SOA record + +If a zone transfer results in a zone not having any NS records, named +stops serving it because such a zone is broken. Do the same if an +incoming zone transfer results in a zone lacking an SOA record at the +apex or containing more than one SOA record. +--- + lib/dns/zone.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/lib/dns/zone.c b/lib/dns/zone.c +index 6d4426a..c3c8f94 100644 +--- a/lib/dns/zone.c ++++ b/lib/dns/zone.c +@@ -15352,11 +15352,20 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { + &retry, &expire, &minimum, NULL); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + if (result == ISC_R_SUCCESS) { +- if (soacount != 1) ++ if (soacount != 1) { + dns_zone_log(zone, ISC_LOG_ERROR, + "transferred zone " +- "has %d SOA record%s", soacount, +- (soacount != 0) ? "s" : ""); ++ "has %d SOA records", ++ soacount); ++ if (DNS_ZONE_FLAG(zone, ++ DNS_ZONEFLG_HAVETIMERS)) { ++ zone->refresh = DNS_ZONE_DEFAULTREFRESH; ++ zone->retry = DNS_ZONE_DEFAULTRETRY; ++ } ++ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS); ++ zone_unload(zone); ++ goto next_master; ++ } + if (nscount == 0) { + dns_zone_log(zone, ISC_LOG_ERROR, + "transferred zone " diff --git a/debian/patches/0032-Handle-DNAME-lookup-via-itself.patch b/debian/patches/0032-Handle-DNAME-lookup-via-itself.patch new file mode 100644 index 0000000..1b73aad --- /dev/null +++ b/debian/patches/0032-Handle-DNAME-lookup-via-itself.patch @@ -0,0 +1,41 @@ +From: Mark Andrews <marka@isc.org> +Date: Mon, 1 Mar 2021 16:46:07 +1100 +Subject: Handle DNAME lookup via itself + +When answering a query, named should never attempt to add the same RRset +to the ANSWER section more than once. However, such a situation may +arise when chasing DNAME records: one of the DNAME records placed in the +ANSWER section may turn out to be the final answer to a client query, +but there is no way to know that in advance. Tweak the relevant INSIST +assertion in query_find() so that it handles this case properly. The +rdataset is freed later anyway, so there is no need to clean it up +immediately. +--- + bin/named/query.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/bin/named/query.c b/bin/named/query.c +index f8dbef2..b674b67 100644 +--- a/bin/named/query.c ++++ b/bin/named/query.c +@@ -9087,10 +9087,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + if (noqname != NULL) + query_addnoqnameproof(client, noqname); + /* +- * We shouldn't ever fail to add 'rdataset' +- * because it's already in the answer. ++ * 'rdataset' will only be non-NULL here if the ANSWER section ++ * of the message to be sent to the client already contains an ++ * RRset with the same owner name and the same type as ++ * 'rdataset'. This should never happen, with one exception: ++ * when chasing DNAME records, one of the DNAME records placed ++ * in the ANSWER section may turn out to be the final answer to ++ * the client's query, but we have no way of knowing that until ++ * now. In such a case, 'rdataset' will be freed later, so we ++ * do not need to free it here. + */ +- INSIST(rdataset == NULL); ++ INSIST(rdataset == NULL || qtype == dns_rdatatype_dname); + } + + addauth: diff --git a/debian/patches/0033-Disable-lame-ttl-cache.patch b/debian/patches/0033-Disable-lame-ttl-cache.patch new file mode 100644 index 0000000..efd2132 --- /dev/null +++ b/debian/patches/0033-Disable-lame-ttl-cache.patch @@ -0,0 +1,70 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@sury.org> +Date: Fri, 24 Sep 2021 09:35:11 +0200 +Subject: Disable lame-ttl cache + +The lame-ttl cache is implemented in ADB as per-server locked +linked-list "indexed" with <qname,qtype>. This list has to be walked +every time there's a new query or new record added into the lame cache. +Determined attacker can use this to degrade performance of the resolver. + +Resolver testing has shown that disabling the lame cache has little +impact on the resolver performance and it's a minimal viable defense +against this kind of attack. +--- + bin/named/config.c | 2 +- + bin/named/server.c | 8 ++++++-- + doc/arm/Bv9ARM-book.xml | 9 +++------ + 3 files changed, 10 insertions(+), 9 deletions(-) + +diff --git a/bin/named/config.c b/bin/named/config.c +index d22ee4b..ba5fa8a 100644 +--- a/bin/named/config.c ++++ b/bin/named/config.c +@@ -170,7 +170,7 @@ options {\n\ + #ifdef HAVE_GEOIP + " geoip-use-ecs yes;\n" + #endif +-" lame-ttl 600;\n" ++" lame-ttl 0;\n" + #ifdef HAVE_LMDB + " lmdb-mapsize 32M;\n" + #endif +diff --git a/bin/named/server.c b/bin/named/server.c +index 149458e..748a150 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -3971,8 +3971,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, + result = ns_config_get(maps, "lame-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + lame_ttl = cfg_obj_asuint32(obj); +- if (lame_ttl > 1800) +- lame_ttl = 1800; ++ if (lame_ttl > 0) { ++ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING, ++ "disabling lame cache despite lame-ttl > 0 as it " ++ "may cause performance issues"); ++ lame_ttl = 0; ++ } + dns_resolver_setlamettl(view->resolver, lame_ttl); + + /* +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 4b36bd0..7852b5a 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -8855,12 +8855,9 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; + <term><command>lame-ttl</command></term> + <listitem> + <para> +- Sets the number of seconds to cache a +- lame server indication. 0 disables caching. (This is +- <emphasis role="bold">NOT</emphasis> recommended.) +- The default is <literal>600</literal> (10 minutes) and the +- maximum value is +- <literal>1800</literal> (30 minutes). ++ This is always set to 0. More information is available ++ in the <link xmlns:xlink="http://www.w3.org/1999/xlink" ++ xlink:href="https://kb.isc.org/docs/cve-2021-25219">security advisory for CVE-2021-25219</link>. + </para> + + </listitem> diff --git a/debian/patches/0034-Enable-lame-response-detection-even-with-disabled-la.patch b/debian/patches/0034-Enable-lame-response-detection-even-with-disabled-la.patch new file mode 100644 index 0000000..790b7c1 --- /dev/null +++ b/debian/patches/0034-Enable-lame-response-detection-even-with-disabled-la.patch @@ -0,0 +1,48 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= <ondrej@sury.org> +Date: Fri, 24 Sep 2021 09:48:50 +0200 +Subject: Enable lame response detection even with disabled lame cache + +Previously, when lame cache would be disabled by setting lame-ttl to 0, +it would also disable lame answer detection. In this commit, we enable +the lame response detection even when the lame cache is disabled. This +enables stopping answer processing early rather than going through the +whole answer processing flow. +--- + lib/dns/resolver.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 1e4fcab..bfc1ae2 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -8323,18 +8323,20 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + /* + * Is the server lame? + */ +- if (res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && +- is_lame(fctx)) { ++ if (!ISFORWARDER(query->addrinfo) && is_lame(fctx)) { + inc_stats(res, dns_resstatscounter_lame); + log_lame(fctx, query->addrinfo); +- result = dns_adb_marklame(fctx->adb, query->addrinfo, +- &fctx->name, fctx->type, +- now + res->lame_ttl); +- if (result != ISC_R_SUCCESS) +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR, +- "could not mark server as lame: %s", +- isc_result_totext(result)); ++ if (res->lame_ttl != 0) { ++ result = dns_adb_marklame(fctx->adb, query->addrinfo, ++ &fctx->name, fctx->type, ++ now + res->lame_ttl); ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR, ++ "could not mark server as lame: %s", ++ isc_result_totext(result)); ++ } ++ } + broken_server = DNS_R_LAME; + keep_trying = true; + FCTXTRACE("lame server"); diff --git a/debian/patches/0035-CVE-2021-25220.patch b/debian/patches/0035-CVE-2021-25220.patch new file mode 100644 index 0000000..48652e1 --- /dev/null +++ b/debian/patches/0035-CVE-2021-25220.patch @@ -0,0 +1,203 @@ +From: Debian DNS Team <team+dns@tracker.debian.org> +Date: Mon, 14 Mar 2022 15:31:10 +0100 +Subject: CVE-2021-25220 + +--- + lib/dns/resolver.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 120 insertions(+), 5 deletions(-) + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index bfc1ae2..cabcbdc 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -68,6 +68,7 @@ + #include <dns/stats.h> + #include <dns/tsig.h> + #include <dns/validator.h> ++#include <dns/zone.h> + + #ifdef WANT_QUERYTRACE + #define RTRACE(m) isc_log_write(dns_lctx, \ +@@ -314,6 +315,8 @@ struct fetchctx { + bool ns_ttl_ok; + uint32_t ns_ttl; + isc_counter_t * qc; ++ dns_fixedname_t fwdfname; ++ dns_name_t *fwdname; + + /*% + * The number of events we're waiting for. +@@ -3304,6 +3307,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { + if (result == ISC_R_SUCCESS) { + fwd = ISC_LIST_HEAD(forwarders->fwdrs); + fctx->fwdpolicy = forwarders->fwdpolicy; ++ dns_name_copy(domain, fctx->fwdname, NULL); + if (fctx->fwdpolicy == dns_fwdpolicy_only && + isstrictsubdomain(domain, &fctx->domain)) { + fcount_decr(fctx); +@@ -4334,6 +4338,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, + fctx->restarts = 0; + fctx->querysent = 0; + fctx->referrals = 0; ++ ++ fctx->fwdname = dns_fixedname_initname(&fctx->fwdfname); ++ + TIME_NOW(&fctx->start); + fctx->timeouts = 0; + fctx->lamecount = 0; +@@ -4386,8 +4393,10 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, + domain = dns_fixedname_initname(&fixed); + result = dns_fwdtable_find2(fctx->res->view->fwdtable, fwdname, + domain, &forwarders); +- if (result == ISC_R_SUCCESS) ++ if (result == ISC_R_SUCCESS) { + fctx->fwdpolicy = forwarders->fwdpolicy; ++ dns_name_copy(domain, fctx->fwdname, NULL); ++ } + + if (fctx->fwdpolicy != dns_fwdpolicy_only) { + /* +@@ -6144,6 +6153,107 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset, + rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL; + } + ++/* ++ * Returns true if 'name' is external to the namespace for which ++ * the server being queried can answer, either because it's not a ++ * subdomain or because it's below a forward declaration or a ++ * locally served zone. ++ */ ++static inline bool ++name_external(dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) { ++ isc_result_t result; ++ dns_forwarders_t *forwarders = NULL; ++ dns_fixedname_t fixed, zfixed; ++ dns_name_t *fname = dns_fixedname_initname(&fixed); ++ dns_name_t *zfname = dns_fixedname_initname(&zfixed); ++ dns_name_t *apex = NULL; ++ dns_name_t suffix; ++ dns_zone_t *zone = NULL; ++ unsigned int labels; ++ dns_namereln_t rel; ++ ++ apex = ISFORWARDER(fctx->addrinfo) ? fctx->fwdname : &fctx->domain; ++ ++ /* ++ * The name is outside the queried namespace. ++ */ ++ rel = dns_name_fullcompare(name, apex, &(int){ 0 }, ++ &(unsigned int){ 0U }); ++ if (rel != dns_namereln_subdomain && rel != dns_namereln_equal) { ++ return (true); ++ } ++ ++ /* ++ * If the record lives in the parent zone, adjust the name so we ++ * look for the correct zone or forward clause. ++ */ ++ labels = dns_name_countlabels(name); ++ if (dns_rdatatype_atparent(type) && labels > 1U) { ++ dns_name_init(&suffix, NULL); ++ dns_name_getlabelsequence(name, 1, labels - 1, &suffix); ++ name = &suffix; ++ } else if (rel == dns_namereln_equal) { ++ /* If 'name' is 'apex', no further checking is needed. */ ++ return (false); ++ } ++ ++ /* ++ * If there is a locally served zone between 'apex' and 'name' ++ * then don't cache. ++ */ ++ LOCK(&fctx->res->view->lock); ++ if (fctx->res->view->zonetable != NULL) { ++ unsigned int options = DNS_ZTFIND_NOEXACT; ++ result = dns_zt_find(fctx->res->view->zonetable, name, options, ++ zfname, &zone); ++ if (zone != NULL) { ++ dns_zone_detach(&zone); ++ } ++ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { ++ if (dns_name_fullcompare(zfname, apex, &(int){ 0 }, ++ &(unsigned int){ 0U }) == ++ dns_namereln_subdomain) ++ { ++ UNLOCK(&fctx->res->view->lock); ++ return (true); ++ } ++ } ++ } ++ UNLOCK(&fctx->res->view->lock); ++ ++ /* ++ * Look for a forward declaration below 'name'. ++ */ ++ result = dns_fwdtable_find2(fctx->res->view->fwdtable, name, fname, ++ &forwarders); ++ ++ if (ISFORWARDER(fctx->addrinfo)) { ++ /* ++ * See if the forwarder declaration is better. ++ */ ++ if (result == ISC_R_SUCCESS) { ++ return (!dns_name_equal(fname, fctx->fwdname)); ++ } ++ ++ /* ++ * If the lookup failed, the configuration must have ++ * changed: play it safe and don't cache. ++ */ ++ return (true); ++ } else if (result == ISC_R_SUCCESS && ++ forwarders->fwdpolicy == dns_fwdpolicy_only && ++ !ISC_LIST_EMPTY(forwarders->fwdrs)) ++ { ++ /* ++ * If 'name' is covered by a 'forward only' clause then we ++ * can't cache this repsonse. ++ */ ++ return (true); ++ } ++ ++ return (false); ++} ++ + static isc_result_t + check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type, + dns_section_t section) +@@ -6170,7 +6280,7 @@ check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type, + result = dns_message_findname(fctx->rmessage, section, addname, + dns_rdatatype_any, 0, &name, NULL); + if (result == ISC_R_SUCCESS) { +- external = !dns_name_issubdomain(name, &fctx->domain); ++ external = name_external(name, type, fctx); + if (type == dns_rdatatype_a) { + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; +@@ -7018,6 +7128,13 @@ answer_response(fetchctx_t *fctx) { + break; + + case dns_namereln_subdomain: ++ /* ++ * Don't accept DNAME from parent namespace. ++ */ ++ if (name_external(name, dns_rdatatype_dname, fctx)) { ++ continue; ++ } ++ + /* + * In-scope DNAME records must have at least + * as many labels as the domain being queried. +@@ -7246,11 +7363,9 @@ answer_response(fetchctx_t *fctx) { + */ + result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + while (!done && result == ISC_R_SUCCESS) { +- bool external; + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); +- external = !dns_name_issubdomain(name, &fctx->domain); +- if (!external) { ++ if (!name_external(name, dns_rdatatype_ns, fctx)) { + /* + * We expect to find NS or SIG NS rdatasets, and + * nothing else. diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..bce493a --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,35 @@ +0001-non-linux.diff +0002-multiarch.diff +0003-min-cache-ttl.diff +0004-library_paths.diff +0005-resource_missing_include.diff +0006-prepare_native_pkcs11.diff +0007-ctxstart_no_sighandling.diff +0008-reproducible_build.diff +0009-Add_--install-layout=deb_to_setup.py_call.patch +0010-skip-rtld-deepbind-for-dyndb.diff +0011-keymgr-dont-immediately-delete.diff +0012-CVE-2018-5743-Limiting-simultaneous-TCP-clients-is-i.patch +0013-Replace-atomic-operations-in-bin-named-client.c-with.patch +0014-Disable-broken-Ed448-support.patch +0015-move-item_out-test-inside-lock-in-dns_dispatch_getne.patch +0016-Set-a-limit-on-number-of-simultaneous-pipelined-TCP-.patch +0017-libns-Rename-ns_tcpconn-refs-member-to-clients.patch +0018-CVE-2020-8616.patch +0019-CVE-2020-8617.patch +0020-Remove-INSIST-from-from-new_reference.patch +0021-Always-keep-a-copy-of-the-message.patch +0022-Fix-crash-in-pk11_numbits-when-native-pkcs11-is-used.patch +0023-Wait-more-than-1-second-for-NSEC3-chain-changes.patch +0024-Update-policy-subdomain-was-incorrectly-treated-as-z.patch +0025-Add-a-test-for-update-policy-subdomain.patch +0026-Add-a-test-for-update-policy-zonesub.patch +0027-CVE-2020-8625.patch +0028-Free-resources-when-gss_accept_sec_context-fails.patch +0029-Check-SOA-owner-names-in-zone-transfers.patch +0030-Address-inconsistencies-in-checking-added-RRsets.patch +0031-Unload-a-zone-if-a-transfer-breaks-its-SOA-record.patch +0032-Handle-DNAME-lookup-via-itself.patch +0033-Disable-lame-ttl-cache.patch +0034-Enable-lame-response-detection-even-with-disabled-la.patch +0035-CVE-2021-25220.patch |