git: abe4ced2b9de - stable/13 - unbound: Vendor import 1.19.1
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 17 Feb 2024 13:48:29 UTC
The branch stable/13 has been updated by cy: URL: https://cgit.FreeBSD.org/src/commit/?id=abe4ced2b9de0a3dd44d7e2068cfd7fa2b428c16 commit abe4ced2b9de0a3dd44d7e2068cfd7fa2b428c16 Author: Cy Schubert <cy@FreeBSD.org> AuthorDate: 2023-11-13 19:44:16 +0000 Commit: Cy Schubert <cy@FreeBSD.org> CommitDate: 2024-02-17 13:47:29 +0000 unbound: Vendor import 1.19.1 Release notes at https://www.nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/ Security: CVE-2023-50387, CVE-2023-50868 MFC after: 3 days (cherry picked from commit b76ef9a7cb8a7c62d10ae8101f41014f34819174) --- contrib/unbound/config.guess | 11 +- contrib/unbound/config.sub | 29 +- contrib/unbound/configure | 25 +- contrib/unbound/configure.ac | 5 +- contrib/unbound/doc/README | 2 +- contrib/unbound/doc/example.conf.in | 2 +- contrib/unbound/doc/libunbound.3.in | 4 +- contrib/unbound/doc/unbound-anchor.8.in | 2 +- contrib/unbound/doc/unbound-checkconf.8.in | 2 +- contrib/unbound/doc/unbound-control.8.in | 2 +- contrib/unbound/doc/unbound-host.1.in | 2 +- contrib/unbound/doc/unbound.8.in | 4 +- contrib/unbound/doc/unbound.conf.5.in | 2 +- contrib/unbound/services/authzone.c | 3 +- contrib/unbound/services/cache/dns.c | 22 ++ contrib/unbound/services/cache/dns.h | 9 + contrib/unbound/testdata/val_any_negcache.rpl | 3 + contrib/unbound/util/fptr_wlist.c | 1 + contrib/unbound/validator/val_nsec.c | 3 +- contrib/unbound/validator/val_nsec3.c | 316 ++++++++++++---- contrib/unbound/validator/val_nsec3.h | 60 +++- contrib/unbound/validator/val_sigcrypt.c | 37 +- contrib/unbound/validator/val_sigcrypt.h | 3 +- contrib/unbound/validator/val_utils.c | 22 +- contrib/unbound/validator/val_utils.h | 4 +- contrib/unbound/validator/validator.c | 499 ++++++++++++++++++++++---- contrib/unbound/validator/validator.h | 18 + usr.sbin/unbound/config.h | 4 +- 28 files changed, 889 insertions(+), 207 deletions(-) diff --git a/contrib/unbound/config.guess b/contrib/unbound/config.guess index cdfc4392047c..f6d217a49f8f 100755 --- a/contrib/unbound/config.guess +++ b/contrib/unbound/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2023-08-22' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -165,6 +165,8 @@ Linux|GNU|GNU/*) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include <stdarg.h> /* First heuristic to detect musl libc. */ @@ -1593,6 +1595,9 @@ EOF *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac # Do we have a guess based on uname results? diff --git a/contrib/unbound/config.sub b/contrib/unbound/config.sub index defe52c0c874..2c6a07ab3c34 100755 --- a/contrib/unbound/config.sub +++ b/contrib/unbound/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2023-09-19' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1222,6 +1222,7 @@ case $cpu-$vendor in | moxie \ | mt \ | msp430 \ + | nanomips* \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ @@ -1253,6 +1254,7 @@ case $cpu-$vendor in | ubicom32 \ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ | vax \ + | vc4 \ | visium \ | w65 \ | wasm32 | wasm64 \ @@ -1597,7 +1599,7 @@ case $cpu-$vendor in os= obj=elf ;; - mips*-*) + mips*-*|nanomips*-*) os= obj=elf ;; @@ -1721,7 +1723,7 @@ fi case $os in # Sometimes we do "kernel-libc", so those need to count as OSes. - musl* | newlib* | relibc* | uclibc*) + llvm* | musl* | newlib* | relibc* | uclibc*) ;; # Likewise for "kernel-abi" eabi* | gnueabi*) @@ -1766,12 +1768,19 @@ case $os in | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ - | fiwix* | mlibc* | cos* | mbr* ) + | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; + # This refers to builds using the UEFI calling convention + # (which depends on the architecture) and PE file format. + # Note that this is both a different calling convention and + # different file format than that of GNU-EFI + # (x86_64-w64-mingw32). + uefi) + ;; none) ;; kernel* | msvc* ) @@ -1818,8 +1827,9 @@ esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in - linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \ - | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- ) + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- ) ;; uclinux-uclibc*- ) ;; @@ -1827,7 +1837,8 @@ case $kernel-$os-$obj in ;; windows*-msvc*-) ;; - -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- ) + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 diff --git a/contrib/unbound/configure b/contrib/unbound/configure index fbe6f8697742..c87c669c8435 100755 --- a/contrib/unbound/configure +++ b/contrib/unbound/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for unbound 1.19.0. +# Generated by GNU Autoconf 2.69 for unbound 1.19.1. # # Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>. # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.19.0' -PACKAGE_STRING='unbound 1.19.0' +PACKAGE_VERSION='1.19.1' +PACKAGE_STRING='unbound 1.19.1' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_URL='' @@ -1477,7 +1477,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.19.0 to adapt to many kinds of systems. +\`configure' configures unbound 1.19.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1543,7 +1543,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.19.0:";; + short | recursive ) echo "Configuration of unbound 1.19.1:";; esac cat <<\_ACEOF @@ -1785,7 +1785,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.19.0 +unbound configure 1.19.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2494,7 +2494,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.19.0, which was +It was created by unbound $as_me 1.19.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2846,11 +2846,11 @@ UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MINOR=19 -UNBOUND_VERSION_MICRO=0 +UNBOUND_VERSION_MICRO=1 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=23 +LIBUNBOUND_REVISION=24 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -2941,6 +2941,7 @@ LIBUNBOUND_AGE=1 # 1.17.1 had 9:21:1 # 1.18.0 had 9:22:1 # 1.19.0 had 9:23:1 +# 1.19.1 had 9:24:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -21894,7 +21895,7 @@ _ACEOF -version=1.19.0 +version=1.19.1 date=`date +'%b %e, %Y'` @@ -22413,7 +22414,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.19.0, which was +This file was extended by unbound $as_me 1.19.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -22479,7 +22480,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -unbound config.status 1.19.0 +unbound config.status 1.19.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac index 1b999596d09a..70fc7e7fdf49 100644 --- a/contrib/unbound/configure.ac +++ b/contrib/unbound/configure.ac @@ -11,14 +11,14 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MINOR],[19]) -m4_define([VERSION_MICRO],[0]) +m4_define([VERSION_MICRO],[1]) AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=23 +LIBUNBOUND_REVISION=24 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -109,6 +109,7 @@ LIBUNBOUND_AGE=1 # 1.17.1 had 9:21:1 # 1.18.0 had 9:22:1 # 1.19.0 had 9:23:1 +# 1.19.1 had 9:24:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary diff --git a/contrib/unbound/doc/README b/contrib/unbound/doc/README index 592a9f4ae8d2..eef91ce02836 100644 --- a/contrib/unbound/doc/README +++ b/contrib/unbound/doc/README @@ -1,4 +1,4 @@ -README for Unbound 1.19.0 +README for Unbound 1.19.1 Copyright 2007 NLnet Labs http://unbound.net diff --git a/contrib/unbound/doc/example.conf.in b/contrib/unbound/doc/example.conf.in index fe0dde69fa19..fcfb1da815db 100644 --- a/contrib/unbound/doc/example.conf.in +++ b/contrib/unbound/doc/example.conf.in @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.19.0. +# See unbound.conf(5) man page, version 1.19.1. # # this is a comment. diff --git a/contrib/unbound/doc/libunbound.3.in b/contrib/unbound/doc/libunbound.3.in index fa090d58186f..4a55eaa9e2ca 100644 --- a/contrib/unbound/doc/libunbound.3.in +++ b/contrib/unbound/doc/libunbound.3.in @@ -1,4 +1,4 @@ -.TH "libunbound" "3" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "libunbound" "3" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" libunbound.3 -- unbound library functions manual .\" @@ -44,7 +44,7 @@ .B ub_ctx_zone_remove, .B ub_ctx_data_add, .B ub_ctx_data_remove -\- Unbound DNS validating resolver 1.19.0 functions. +\- Unbound DNS validating resolver 1.19.1 functions. .SH "SYNOPSIS" .B #include <unbound.h> .LP diff --git a/contrib/unbound/doc/unbound-anchor.8.in b/contrib/unbound/doc/unbound-anchor.8.in index a108db9faa72..fee56e9dfa51 100644 --- a/contrib/unbound/doc/unbound-anchor.8.in +++ b/contrib/unbound/doc/unbound-anchor.8.in @@ -1,4 +1,4 @@ -.TH "unbound-anchor" "8" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound-anchor" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound-anchor.8 -- unbound anchor maintenance utility manual .\" diff --git a/contrib/unbound/doc/unbound-checkconf.8.in b/contrib/unbound/doc/unbound-checkconf.8.in index b80c723cd3f0..9a14ef06bc3d 100644 --- a/contrib/unbound/doc/unbound-checkconf.8.in +++ b/contrib/unbound/doc/unbound-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "unbound-checkconf" "8" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound-checkconf" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound-checkconf.8 -- unbound configuration checker manual .\" diff --git a/contrib/unbound/doc/unbound-control.8.in b/contrib/unbound/doc/unbound-control.8.in index 44e73c93dfd5..e747ec47e25a 100644 --- a/contrib/unbound/doc/unbound-control.8.in +++ b/contrib/unbound/doc/unbound-control.8.in @@ -1,4 +1,4 @@ -.TH "unbound-control" "8" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound-control" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound-control.8 -- unbound remote control manual .\" diff --git a/contrib/unbound/doc/unbound-host.1.in b/contrib/unbound/doc/unbound-host.1.in index 36f22ee9b6d1..9c9e9e2bf4a0 100644 --- a/contrib/unbound/doc/unbound-host.1.in +++ b/contrib/unbound/doc/unbound-host.1.in @@ -1,4 +1,4 @@ -.TH "unbound\-host" "1" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound\-host" "1" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound-host.1 -- unbound DNS lookup utility .\" diff --git a/contrib/unbound/doc/unbound.8.in b/contrib/unbound/doc/unbound.8.in index 3d56b7bfa190..4967a22d328c 100644 --- a/contrib/unbound/doc/unbound.8.in +++ b/contrib/unbound/doc/unbound.8.in @@ -1,4 +1,4 @@ -.TH "unbound" "8" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound" "8" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound.8 -- unbound manual .\" @@ -9,7 +9,7 @@ .\" .SH "NAME" .B unbound -\- Unbound DNS validating resolver 1.19.0. +\- Unbound DNS validating resolver 1.19.1. .SH "SYNOPSIS" .B unbound .RB [ \-h ] diff --git a/contrib/unbound/doc/unbound.conf.5.in b/contrib/unbound/doc/unbound.conf.5.in index ac8fa7953f3c..79ca04904c96 100644 --- a/contrib/unbound/doc/unbound.conf.5.in +++ b/contrib/unbound/doc/unbound.conf.5.in @@ -1,4 +1,4 @@ -.TH "unbound.conf" "5" "Nov 8, 2023" "NLnet Labs" "unbound 1.19.0" +.TH "unbound.conf" "5" "Feb 13, 2024" "NLnet Labs" "unbound 1.19.1" .\" .\" unbound.conf.5 -- unbound.conf manual .\" diff --git a/contrib/unbound/services/authzone.c b/contrib/unbound/services/authzone.c index 87844870a25a..761bcc6d9a75 100644 --- a/contrib/unbound/services/authzone.c +++ b/contrib/unbound/services/authzone.c @@ -7774,6 +7774,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, enum sec_status sec; struct val_env* ve; int m; + int verified = 0; m = modstack_find(mods, "validator"); if(m == -1) { auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have " @@ -7797,7 +7798,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, "zonemd: verify %s RRset with DNSKEY", typestr); } sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, - LDNS_SECTION_ANSWER, NULL); + LDNS_SECTION_ANSWER, NULL, &verified); if(sec == sec_status_secure) { return 1; } diff --git a/contrib/unbound/services/cache/dns.c b/contrib/unbound/services/cache/dns.c index 9b4ad5888721..7bc1b7b47bf1 100644 --- a/contrib/unbound/services/cache/dns.c +++ b/contrib/unbound/services/cache/dns.c @@ -690,6 +690,28 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, return msg; } +struct dns_msg* +dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region) +{ + size_t i; + struct dns_msg* res = NULL; + res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count); + if(!res) return NULL; + *res->rep = *origin->rep; + if(origin->rep->reason_bogus_str) { + res->rep->reason_bogus_str = regional_strdup(region, + origin->rep->reason_bogus_str); + } + for(i=0; i<res->rep->rrset_count; i++) { + res->rep->rrsets[i] = packed_rrset_copy_region( + origin->rep->rrsets[i], region, 0); + if(!res->rep->rrsets[i]) { + return NULL; + } + } + return res; +} + /** synthesize RRset-only response from cached RRset item */ static struct dns_msg* rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, diff --git a/contrib/unbound/services/cache/dns.h b/contrib/unbound/services/cache/dns.h index 147f992cbc74..c2bf23c6de54 100644 --- a/contrib/unbound/services/cache/dns.h +++ b/contrib/unbound/services/cache/dns.h @@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, struct regional* region, time_t now, int allow_expired, struct regional* scratch); +/** + * Deep copy a dns_msg to a region. + * @param origin: the dns_msg to copy. + * @param region: the region to copy all the data to. + * @return the new dns_msg or NULL on malloc error. + */ +struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin, + struct regional* region); + /** * Find cached message * @param env: module environment with the DNS cache. diff --git a/contrib/unbound/testdata/val_any_negcache.rpl b/contrib/unbound/testdata/val_any_negcache.rpl index 77aacba8cc13..8800a2140219 100644 --- a/contrib/unbound/testdata/val_any_negcache.rpl +++ b/contrib/unbound/testdata/val_any_negcache.rpl @@ -199,6 +199,9 @@ SECTION QUESTION example.com. IN ANY ENTRY_END +; Allow validation resuming for the RRSIGs +STEP 21 TIME_PASSES ELAPSE 0.05 + ; recursion happens here. STEP 30 CHECK_ANSWER ENTRY_BEGIN diff --git a/contrib/unbound/util/fptr_wlist.c b/contrib/unbound/util/fptr_wlist.c index 43d38dc3797d..a792a3429549 100644 --- a/contrib/unbound/util/fptr_wlist.c +++ b/contrib/unbound/util/fptr_wlist.c @@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*)) else if(fptr == &pending_udp_timer_delay_cb) return 1; else if(fptr == &worker_stat_timer_cb) return 1; else if(fptr == &worker_probe_timer_cb) return 1; + else if(fptr == &validate_suspend_timer_cb) return 1; #ifdef UB_ON_WINDOWS else if(fptr == &wsvc_cron_cb) return 1; #endif diff --git a/contrib/unbound/validator/val_nsec.c b/contrib/unbound/validator/val_nsec.c index 17c90d83f594..d0cc67ff5d0b 100644 --- a/contrib/unbound/validator/val_nsec.c +++ b/contrib/unbound/validator/val_nsec.c @@ -181,6 +181,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; + int verified = 0; if(!d) return 0; if(d->security == sec_status_secure) return 1; @@ -188,7 +189,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, if(d->security == sec_status_secure) return 1; d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, - reason_bogus, LDNS_SECTION_AUTHORITY, qstate); + reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified); if(d->security == sec_status_secure) { rrset_update_sec_status(env->rrset_cache, nsec, *env->now); return 1; diff --git a/contrib/unbound/validator/val_nsec3.c b/contrib/unbound/validator/val_nsec3.c index a2b3794f6019..95d1e4d7e4fe 100644 --- a/contrib/unbound/validator/val_nsec3.c +++ b/contrib/unbound/validator/val_nsec3.c @@ -57,6 +57,19 @@ /* we include nsec.h for the bitmap_has_type function */ #include "validator/val_nsec.h" #include "sldns/sbuffer.h" +#include "util/config_file.h" + +/** + * Max number of NSEC3 calculations at once, suspend query for later. + * 8 is low enough and allows for cases where multiple proofs are needed. + */ +#define MAX_NSEC3_CALCULATIONS 8 +/** + * When all allowed NSEC3 calculations at once resulted in error treat as + * bogus. NSEC3 hash errors are not cached and this helps breaks loops with + * erroneous data. + */ +#define MAX_NSEC3_ERRORS -1 /** * This function we get from ldns-compat or from base system @@ -532,6 +545,17 @@ nsec3_hash_cmp(const void* c1, const void* c2) return memcmp(s1, s2, s1len); } +int +nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region) +{ + if(ct->ct) return 1; + ct->ct = (rbtree_type*)regional_alloc(region, sizeof(*ct->ct)); + if(!ct->ct) return 0; + ct->region = region; + rbtree_init(ct->ct, &nsec3_hash_cmp); + return 1; +} + size_t nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max) @@ -646,7 +670,7 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf, c = (struct nsec3_cached_hash*)rbtree_search(table, &looki); if(c) { *hash = c; - return 1; + return 2; } /* create a new entry */ c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c)); @@ -658,10 +682,10 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf, c->dname_len = dname_len; r = nsec3_calc_hash(region, buf, c); if(r != 1) - return r; + return r; /* returns -1 or 0 */ r = nsec3_calc_b32(region, buf, c); if(r != 1) - return r; + return r; /* returns 0 */ #ifdef UNBOUND_DEBUG n = #else @@ -704,6 +728,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt, struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s) { uint8_t* nm = s->rk.dname; + if(!hash) return 0; /* please clang */ /* compare, does hash of name based on params in this NSEC3 * match the owner name of this NSEC3? * name must be: <hashlength>base32 . zone name @@ -730,34 +755,50 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt, * @param nmlen: length of name. * @param rrset: nsec3 that matches is returned here. * @param rr: rr number in nsec3 rrset that matches. + * @param calculations: current hash calculations. * @return true if a matching NSEC3 is found, false if not. */ static int find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, uint8_t* nm, size_t nmlen, - struct ub_packed_rrset_key** rrset, int* rr) + struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen, + struct ub_packed_rrset_key** rrset, int* rr, + int* calculations) { size_t i_rs; int i_rr; struct ub_packed_rrset_key* s; struct nsec3_cached_hash* hash = NULL; int r; + int calc_errors = 0; /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */ for(s=filter_first(flt, &i_rs, &i_rr); s; s=filter_next(flt, &i_rs, &i_rr)) { + /* check if we are allowed more calculations */ + if(*calculations >= MAX_NSEC3_CALCULATIONS) { + if(calc_errors == *calculations) { + *calculations = MAX_NSEC3_ERRORS; + } + break; + } /* get name hashed for this NSEC3 RR */ - r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer, + r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer, s, i_rr, nm, nmlen, &hash); if(r == 0) { log_err("nsec3: malloc failure"); break; /* alloc failure */ - } else if(r != 1) - continue; /* malformed NSEC3 */ - else if(nsec3_hash_matches_owner(flt, hash, s)) { - *rrset = s; /* rrset with this name */ - *rr = i_rr; /* matches hash with these parameters */ - return 1; + } else if(r < 0) { + /* malformed NSEC3 */ + calc_errors++; + (*calculations)++; + continue; + } else { + if(r == 1) (*calculations)++; + if(nsec3_hash_matches_owner(flt, hash, s)) { + *rrset = s; /* rrset with this name */ + *rr = i_rr; /* matches hash with these parameters */ + return 1; + } } } *rrset = NULL; @@ -775,6 +816,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen)) return 0; /* malformed RR proves nothing */ + if(!hash) return 0; /* please clang */ /* check the owner name is a hashed value . apex * base32 encoded values must have equal length. * hash_value and next hash value must have equal length. */ @@ -823,35 +865,51 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, * @param nmlen: length of name. * @param rrset: covering NSEC3 rrset is returned here. * @param rr: rr of cover is returned here. + * @param calculations: current hash calculations. * @return true if a covering NSEC3 is found, false if not. */ static int find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, uint8_t* nm, size_t nmlen, - struct ub_packed_rrset_key** rrset, int* rr) + struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen, + struct ub_packed_rrset_key** rrset, int* rr, + int* calculations) { size_t i_rs; int i_rr; struct ub_packed_rrset_key* s; struct nsec3_cached_hash* hash = NULL; int r; + int calc_errors = 0; /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */ for(s=filter_first(flt, &i_rs, &i_rr); s; s=filter_next(flt, &i_rs, &i_rr)) { + /* check if we are allowed more calculations */ + if(*calculations >= MAX_NSEC3_CALCULATIONS) { + if(calc_errors == *calculations) { + *calculations = MAX_NSEC3_ERRORS; + } + break; + } /* get name hashed for this NSEC3 RR */ - r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer, + r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer, s, i_rr, nm, nmlen, &hash); if(r == 0) { log_err("nsec3: malloc failure"); break; /* alloc failure */ - } else if(r != 1) - continue; /* malformed NSEC3 */ - else if(nsec3_covers(flt->zone, hash, s, i_rr, - env->scratch_buffer)) { - *rrset = s; /* rrset with this name */ - *rr = i_rr; /* covers hash with these parameters */ - return 1; + } else if(r < 0) { + /* malformed NSEC3 */ + calc_errors++; + (*calculations)++; + continue; + } else { + if(r == 1) (*calculations)++; + if(nsec3_covers(flt->zone, hash, s, i_rr, + env->scratch_buffer)) { + *rrset = s; /* rrset with this name */ + *rr = i_rr; /* covers hash with these parameters */ + return 1; + } } } *rrset = NULL; @@ -869,11 +927,13 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, * @param ct: cached hashes table. * @param qinfo: query that is verified for. * @param ce: closest encloser information is returned in here. + * @param calculations: current hash calculations. * @return true if a closest encloser candidate is found, false if not. */ static int -nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce) +nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, + struct nsec3_cache_table* ct, struct query_info* qinfo, + struct ce_response* ce, int* calculations) { uint8_t* nm = qinfo->qname; size_t nmlen = qinfo->qname_len; @@ -888,8 +948,12 @@ nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, * may be the case. */ while(dname_subdomain_c(nm, flt->zone)) { + if(*calculations >= MAX_NSEC3_CALCULATIONS || + *calculations == MAX_NSEC3_ERRORS) { + return 0; + } if(find_matching_nsec3(env, flt, ct, nm, nmlen, - &ce->ce_rrset, &ce->ce_rr)) { + &ce->ce_rrset, &ce->ce_rr, calculations)) { ce->ce = nm; ce->ce_len = nmlen; return 1; @@ -933,22 +997,38 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce, * If set true, and the return value is true, then you can be * certain that the ce.nc_rrset and ce.nc_rr are set properly. * @param ce: closest encloser information is returned in here. + * @param calculations: pointer to the current NSEC3 hash calculations. * @return bogus if no closest encloser could be proven. * secure if a closest encloser could be proven, ce is set. * insecure if the closest-encloser candidate turns out to prove * that an insecure delegation exists above the qname. + * unchecked if no more hash calculations are allowed at this point. */ static enum sec_status -nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist, - struct ce_response* ce) +nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, + struct nsec3_cache_table* ct, struct query_info* qinfo, + int prove_does_not_exist, struct ce_response* ce, int* calculations) { uint8_t* nc; size_t nc_len; /* robust: clean out ce, in case it gets abused later */ memset(ce, 0, sizeof(*ce)); - if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) { + if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce, calculations)) { + if(*calculations == MAX_NSEC3_ERRORS) { + verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " + "not find a candidate for the closest " + "encloser; all attempted hash calculations " + "were erroneous; bogus"); + return sec_status_bogus; + } else if(*calculations >= MAX_NSEC3_CALCULATIONS) { + verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " + "not find a candidate for the closest " + "encloser; reached MAX_NSEC3_CALCULATIONS " + "(%d); unchecked still", + MAX_NSEC3_CALCULATIONS); + return sec_status_unchecked; + } verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " "not find a candidate for the closest encloser."); return sec_status_bogus; @@ -989,9 +1069,23 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, /* Otherwise, we need to show that the next closer name is covered. */ next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len); if(!find_covering_nsec3(env, flt, ct, nc, nc_len, - &ce->nc_rrset, &ce->nc_rr)) { + &ce->nc_rrset, &ce->nc_rr, calculations)) { + if(*calculations == MAX_NSEC3_ERRORS) { + verbose(VERB_ALGO, "nsec3: Could not find proof that the " + "candidate encloser was the closest encloser; " + "all attempted hash calculations were " + "erroneous; bogus"); + return sec_status_bogus; + } else if(*calculations >= MAX_NSEC3_CALCULATIONS) { + verbose(VERB_ALGO, "nsec3: Could not find proof that the " + "candidate encloser was the closest encloser; " + "reached MAX_NSEC3_CALCULATIONS (%d); " + "unchecked still", + MAX_NSEC3_CALCULATIONS); + return sec_status_unchecked; + } verbose(VERB_ALGO, "nsec3: Could not find proof that the " - "candidate encloser was the closest encloser"); + "candidate encloser was the closest encloser"); return sec_status_bogus; } return sec_status_secure; @@ -1019,8 +1113,8 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen, /** Do the name error proof */ static enum sec_status -nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, struct query_info* qinfo) +nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, + struct nsec3_cache_table* ct, struct query_info* qinfo, int* calc) { struct ce_response ce; uint8_t* wc; @@ -1032,11 +1126,15 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, /* First locate and prove the closest encloser to qname. We will * use the variant that fails if the closest encloser turns out * to be qname. */ - sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce); + sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc); if(sec != sec_status_secure) { if(sec == sec_status_bogus) verbose(VERB_ALGO, "nsec3 nameerror proof: failed " "to prove a closest encloser"); + else if(sec == sec_status_unchecked) + verbose(VERB_ALGO, "nsec3 nameerror proof: will " + "continue proving closest encloser after " + "suspend"); else verbose(VERB_ALGO, "nsec3 nameerror proof: closest " "nsec3 is an insecure delegation"); return sec; @@ -1046,9 +1144,27 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, /* At this point, we know that qname does not exist. Now we need * to prove that the wildcard does not exist. */ log_assert(ce.ce); - wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen); - if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen, - &wc_rrset, &wc_rr)) { + wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen); + if(!wc) { + verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " + "that the applicable wildcard did not exist."); + return sec_status_bogus; + } + if(!find_covering_nsec3(env, flt, ct, wc, wclen, &wc_rrset, &wc_rr, calc)) { + if(*calc == MAX_NSEC3_ERRORS) { + verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " + "that the applicable wildcard did not exist; " + "all attempted hash calculations were " + "erroneous; bogus"); + return sec_status_bogus; + } else if(*calc >= MAX_NSEC3_CALCULATIONS) { + verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " + "that the applicable wildcard did not exist; " + "reached MAX_NSEC3_CALCULATIONS (%d); " + "unchecked still", + MAX_NSEC3_CALCULATIONS); + return sec_status_unchecked; + } verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " "that the applicable wildcard did not exist."); return sec_status_bogus; @@ -1064,14 +1180,13 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, enum sec_status nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, - struct query_info* qinfo, struct key_entry_key* kkey) + struct query_info* qinfo, struct key_entry_key* kkey, + struct nsec3_cache_table* ct, int* calc) { - rbtree_type ct; struct nsec3_filter flt; if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) return sec_status_bogus; /* no valid NSEC3s, bogus */ - rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ filter_init(&flt, list, num, qinfo); /* init RR iterator */ if(!flt.zone) return sec_status_bogus; /* no RRs */ @@ -1079,7 +1194,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, return sec_status_insecure; /* iteration count too high */ log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", flt.zone, 0, 0); - return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo); + return nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc); } /* @@ -1089,8 +1204,9 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, /** Do the nodata proof */ static enum sec_status -nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - rbtree_type* ct, struct query_info* qinfo) +nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, + struct nsec3_cache_table* ct, struct query_info* qinfo, + int* calc) { struct ce_response ce; uint8_t* wc; @@ -1100,7 +1216,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, enum sec_status sec; if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len, - &rrset, &rr)) { + &rrset, &rr, calc)) { /* cases 1 and 2 */ if(nsec3_has_type(rrset, rr, qinfo->qtype)) { verbose(VERB_ALGO, "proveNodata: Matching NSEC3 " @@ -1144,11 +1260,23 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, } return sec_status_secure; } + if(*calc == MAX_NSEC3_ERRORS) { + verbose(VERB_ALGO, "proveNodata: all attempted hash " + "calculations were erroneous while finding a matching " + "NSEC3, bogus"); + return sec_status_bogus; + } else if(*calc >= MAX_NSEC3_CALCULATIONS) { + verbose(VERB_ALGO, "proveNodata: reached " + "MAX_NSEC3_CALCULATIONS (%d) while finding a " *** 1723 LINES SKIPPED ***