From: W.C.A. Wijngaards Date: Wed, 17 Jun 2026 13:11:42 +0000 (+0200) Subject: - Fix that unbound-checkconf checks if an auth-zone download X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b47b1d048d22d8e0d5138a0f5272266adde761a2;p=thirdparty%2Funbound.git - Fix that unbound-checkconf checks if an auth-zone download can overwrite another file, by filename collision. Thanks to Qifan Zhang, Palo Alto Networks, for the report. --- diff --git a/config.h.in b/config.h.in index b601dbe61..1785ae5c0 100644 --- a/config.h.in +++ b/config.h.in @@ -299,6 +299,12 @@ /* Define to 1 if you have the `FIPS_mode' function. */ #undef HAVE_FIPS_MODE +/* Define to 1 if you have the `fnmatch' function. */ +#undef HAVE_FNMATCH + +/* Define to 1 if you have the header file. */ +#undef HAVE_FNMATCH_H + /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK diff --git a/configure b/configure index 64c784fac..71eb3a3b2 100755 --- a/configure +++ b/configure @@ -16005,6 +16005,13 @@ if test "x$ac_cv_header_glob_h" = xyes then : printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default +" +if test "x$ac_cv_header_fnmatch_h" = xyes +then : + printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default " @@ -23848,6 +23855,12 @@ if test "x$ac_cv_func_glob" = xyes then : printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch" +if test "x$ac_cv_func_fnmatch" = xyes +then : + printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups" if test "x$ac_cv_func_initgroups" = xyes diff --git a/configure.ac b/configure.ac index 212b45f28..7cdf5803f 100644 --- a/configure.ac +++ b/configure.ac @@ -483,7 +483,7 @@ PKG_PROG_PKG_CONFIG fi # Checks for header files. -AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h fnmatch.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT]) # net/if.h portability for Darwin see: # https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html AC_CHECK_HEADERS([net/if.h],,, [ @@ -1923,7 +1923,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([ AC_MSG_RESULT(no)) AC_SEARCH_LIBS([setusercontext], [util]) -AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid]) +AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid]) AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])]) AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])]) diff --git a/doc/Changelog b/doc/Changelog index 8b084e806..266c84897 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -4,6 +4,9 @@ auth_transfer_limit test to use a forwarder for each type of failure, so the one is not blocked by the other waiting. - Fix to remove debug from auth_transfer_limit test. + - Fix that unbound-checkconf checks if an auth-zone download + can overwrite another file, by filename collision. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. 16 June 2026: Wouter - Fix to disallow $INCLUDE for secondary zones. Start up diff --git a/smallapp/unbound-checkconf.c b/smallapp/unbound-checkconf.c index a8e19241f..41cc2a050 100644 --- a/smallapp/unbound-checkconf.c +++ b/smallapp/unbound-checkconf.c @@ -73,6 +73,9 @@ #ifdef HAVE_GLOB_H #include #endif +#ifdef HAVE_FNMATCH_H +#include +#endif #ifdef WITH_PYTHONMODULE #include "pythonmod/pythonmod.h" #endif @@ -728,6 +731,120 @@ check_modules_exist(const char* module_conf) } } +/** Compare filename with string, true if it matches the name. */ +static int +file_string_matches(char* str, char* fname, struct config_file* cfg) +{ + char* f; + if(!str || str[0] == 0) + return 0; + /* compare name after chroot and working dir are applied */ + f = fname_after_chroot(str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } + free(f); + return 0; +} + +/** Compare filename with list of files, true if list contains the name. */ +static int +file_list_contains(struct config_strlist* list, char* fname, + struct config_file* cfg) +{ + struct config_strlist* s; + char* f; + for(s = list; s; s = s->next) { + if(!s->str || s->str[0] == 0) + continue; /* skip if no file name */ + /* compare names after chroot and working dir are applied */ + f = fname_after_chroot(s->str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } + free(f); + } + return 0; +} + +/** Compare filename with list of files, true if list contains the name, + * with glob compare. */ +static int +file_list_contains_wild(struct config_strlist* list, char* fname, + struct config_file* cfg) +{ + struct config_strlist* s; + char* f; + for(s = list; s; s = s->next) { + if(!s->str || s->str[0] == 0) + continue; /* skip if no file name */ + /* compare names after chroot and working dir are applied */ + f = fname_after_chroot(s->str, cfg, 1); + if(!f) fatal_exit("out of memory"); + if(strcmp(fname, f) == 0) { + free(f); + return 1; + } +#ifdef HAVE_FNMATCH + if(fnmatch(f, fname, 0) == 0) { + log_err("trusted-keys-file: \"%s\" matches zonefile '%s'", + s->str, fname); + free(f); + return 1; + } +#endif + free(f); + } + return 0; +} + +/** Check if the auth-zone/rpz zonefile: conflicts with other files, + * so it would overwrite that file. Refuse it aliasing any read-side bootstrap + * file. */ +static void +check_file_clobber(struct config_file* cfg) +{ + struct config_auth* p; + char* zfile, *sourceopt = NULL; + for(p = cfg->auths; p; p = p->next) { + if(!p->name || p->name[0] == 0) + continue; /* skip if no name */ + if(!p->zonefile || p->zonefile[0]==0) + continue; /* no zone file */ + zfile = fname_after_chroot(p->zonefile, cfg, 1); + if(!zfile) fatal_exit("out of memory"); + if(file_list_contains(cfg->auto_trust_anchor_file_list, zfile, + cfg)) + sourceopt = "auto-trust-anchor-file"; + else if(file_list_contains(cfg->trust_anchor_file_list, zfile, + cfg)) + sourceopt = "trust-anchor-file"; + else if(file_list_contains_wild(cfg->trusted_keys_file_list, + zfile, cfg)) + sourceopt = "trusted-keys-file"; + else if(file_list_contains(cfg->root_hints, zfile, cfg)) + sourceopt = "root-hints"; + else if(file_list_contains(cfg->tls_session_ticket_keys.first, + zfile, cfg)) + sourceopt = "tls-session-ticket-keys"; +#ifdef USE_IPSECMOD + if(cfg->ipsecmod_enabled && + file_string_matches(cfg->ipsecmod_hook, zfile, cfg)) + sourceopt = "ipsecmod-hook"; +#endif + if(sourceopt) + fatal_exit("auth-zone '%s': zonefile \"%s\" " + "is the same path as a %s option. " + "The auth-zone transfer would overwrite it.", + p->name, p->zonefile, sourceopt); + free(zfile); + } +} + /** check configuration for errors */ static void morechecks(struct config_file* cfg) @@ -822,6 +939,7 @@ morechecks(struct config_file* cfg) cfg->chrootdir, cfg); } #endif + check_file_clobber(cfg); /* remove chroot setting so that modules are not stripping pathnames */ free(cfg->chrootdir); cfg->chrootdir = NULL;