Package: unbound Version: 1.4.18-1 Severity: normal Tags: upstream patch Unbound crashes under high query load (while doing DNSSEC validation) if "num-threads" configuration setting is higher than 1.
A simple workaround is to reduce the amount of threads to 1 (which is the default). There is a gdb backtrace of the crash at: https://unbound.net/pipermail/unbound-users/2012-October/002653.html A detailed description of the problem is available at: https://unbound.net/pipermail/unbound-users/2012-September/002571.html There is a patch included at the end of that message. I am attaching it also to this bug report. The fix is committed in Unbound SVN repository at r2733. It will be included in the next Unbound version. I have filed also Ubuntu bug report at: https://bugs.launchpad.net/ubuntu/+source/unbound/+bug/1070247 -- System Information: Debian Release: wheezy/sid APT prefers unstable APT policy: (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 3.2.0-3-amd64 (SMP w/2 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages unbound depends on: ii adduser 3.113+nmu3 ii libc6 2.13-35 ii libevent-2.0-5 2.0.19-stable-3 ii libgcc1 1:4.7.2-4 ii libldns1 1.6.13-3 ii libpython2.7 2.7.3-5 ii libssl1.0.0 1.0.1c-4 ii openssl 1.0.1c-4 ii unbound-anchor 1.4.18-1 unbound recommends no packages. unbound suggests no packages. -- Configuration Files: /etc/unbound/unbound.conf changed: server: # The following line will configure unbound to perform cryptographic # DNSSEC validation using the root trust anchor. auto-trust-anchor-file: "/var/lib/unbound/root.key" num-threads: 2 -- no debconf information
Index: daemon/daemon.c =================================================================== --- daemon/daemon.c (revision 2732) +++ daemon/daemon.c (revision 2733) @@ -209,6 +209,10 @@ comp_meth = (void*)SSL_COMP_get_compression_methods(); # endif (void)SSL_library_init(); +# if defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) + if(!ub_openssl_lock_init()) + fatal_exit("could not init openssl locks"); +# endif #elif defined(HAVE_NSS) if(NSS_NoDB_Init(NULL) != SECSuccess) fatal_exit("could not init NSS"); @@ -568,6 +572,9 @@ ERR_remove_state(0); ERR_free_strings(); RAND_cleanup(); +# if defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) + ub_openssl_lock_delete(); +# endif #elif defined(HAVE_NSS) NSS_Shutdown(); #endif /* HAVE_SSL or HAVE_NSS */ Index: util/net_help.c =================================================================== --- util/net_help.c (revision 2732) +++ util/net_help.c (revision 2733) @@ -725,3 +725,54 @@ return NULL; #endif } + +/** global lock list for openssl locks */ +static lock_basic_t *ub_openssl_locks = NULL; + +/** callback that gets thread id for openssl */ +static unsigned long +ub_crypto_id_cb(void) +{ + return (unsigned long)ub_thread_self(); +} + +static void +ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file), + int ATTR_UNUSED(line)) +{ + if((mode&CRYPTO_LOCK)) { + lock_basic_lock(&ub_openssl_locks[type]); + } else { + lock_basic_unlock(&ub_openssl_locks[type]); + } +} + +int ub_openssl_lock_init(void) +{ +#ifdef OPENSSL_THREADS + size_t i; + ub_openssl_locks = (lock_basic_t*)malloc( + sizeof(lock_basic_t)*CRYPTO_num_locks()); + if(!ub_openssl_locks) + return 0; + for(i=0; i<CRYPTO_num_locks(); i++) { + lock_basic_init(&ub_openssl_locks[i]); + } + CRYPTO_set_id_callback(&ub_crypto_id_cb); + CRYPTO_set_locking_callback(&ub_crypto_lock_cb); +#endif /* OPENSSL_THREADS */ + return 1; +} + +void ub_openssl_lock_delete(void) +{ +#ifdef OPENSSL_THREADS + size_t i; + if(!ub_openssl_locks) + return; + for(i=0; i<CRYPTO_num_locks(); i++) { + lock_basic_destroy(&ub_openssl_locks[i]); + } +#endif /* OPENSSL_THREADS */ +} + Index: util/net_help.h =================================================================== --- util/net_help.h (revision 2732) +++ util/net_help.h (revision 2733) @@ -369,4 +369,15 @@ */ void* outgoing_ssl_fd(void* sslctx, int fd); +/** + * Initialize openssl locking for thread safety + * @return false on failure (alloc failure). + */ +int ub_openssl_lock_init(void); + +/** + * De-init the allocated openssl locks + */ +void ub_openssl_lock_delete(void); + #endif /* NET_HELP_H */