Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 unbound (1.4.17-3+deb7u2) wheezy-security; urgency=medium
 .
    * Fix CVE-2014-8602: denial of service by making resolver chase endless
      series of delegations; closes: #772622.
Author: Robert Edmonds <edmonds@debian.org>
Bug-Debian: http://bugs.debian.org/772622

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- unbound-1.4.17.orig/acx_python.m4
+++ unbound-1.4.17/acx_python.m4
@@ -164,8 +164,11 @@ $ac_distutils_result])
         AC_MSG_CHECKING([consistency of all components of python development environment])
         AC_LANG_PUSH([C])
         # save current global flags
-        LIBS="$ac_save_LIBS $PYTHON_LDFLAGS"
-        CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
+        ac_save_LIBS="$LIBS"
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+        LIBS="$LIBS $PYTHON_LDFLAGS"
+        CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
         AC_TRY_LINK([
                 #include <Python.h>
         ],[
--- unbound-1.4.17.orig/configure.ac
+++ unbound-1.4.17/configure.ac
@@ -232,7 +232,11 @@ case "$debug_enabled" in
 		# nothing to do.
 		;;
 esac
-ACX_CHECK_FLTO
+case "`dpkg-architecture -qDEB_BUILD_ARCH 2>/dev/null`" in
+    amd64|i386)
+    ACX_CHECK_FLTO
+    ;;
+esac
 
 AC_C_INLINE
 ACX_CHECK_FORMAT_ATTRIBUTE
--- unbound-1.4.17.orig/daemon/daemon.c
+++ unbound-1.4.17/daemon/daemon.c
@@ -203,6 +203,10 @@ daemon_init(void)
 	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
 #ifdef HAVE_TZSET
 	/* init timezone info while we are not chrooted yet */
 	tzset();
@@ -555,6 +559,9 @@ daemon_delete(struct daemon* daemon)
 	ERR_remove_state(0);
 	ERR_free_strings();
 	RAND_cleanup();
+#  if defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+	ub_openssl_lock_delete();
+#  endif
 	checklock_stop();
 #ifdef USE_WINSOCK
 	if(WSACleanup() != 0) {
--- unbound-1.4.17.orig/daemon/unbound.c
+++ unbound-1.4.17/daemon/unbound.c
@@ -266,8 +266,6 @@ checkrlimits(struct config_file* cfg)
 				"ports in config to remove this warning");
 			return;
 		}
-		log_warn("increased limit(open files) from %u to %u",
-			(unsigned)avail, (unsigned)total+10);
 	}
 #else	
 	(void)cfg;
--- unbound-1.4.17.orig/doc/unbound.conf.5.in
+++ unbound-1.4.17/doc/unbound.conf.5.in
@@ -916,7 +916,7 @@ section for options.  To setup the corre
 \fIunbound\-control\-setup\fR(8) utility.
 .TP 5
 .B control\-enable:     \fI<yes or no>
-The option is used to enable remote control, default is "no".
+The option is used to enable remote control, default is "yes".
 If turned off, the server does not listen for control commands.
 .TP 5
 .B control\-interface: <ip address>
--- unbound-1.4.17.orig/iterator/iter_hints.c
+++ unbound-1.4.17/iterator/iter_hints.c
@@ -129,7 +129,7 @@ compile_time_root_prime(int do_ip4, int
 	if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4"))	return 0;
 	if(!ah(dp, "B.ROOT-SERVERS.NET.", "192.228.79.201")) return 0;
 	if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12"))	return 0;
-	if(!ah(dp, "D.ROOT-SERVERS.NET.", "128.8.10.90"))	return 0;
+	if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13"))	return 0;
 	if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) return 0;
 	if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241"))	return 0;
 	if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4"))	return 0;
--- unbound-1.4.17.orig/iterator/iterator.c
+++ unbound-1.4.17/iterator/iterator.c
@@ -117,6 +117,7 @@ iter_new(struct module_qstate* qstate, i
 	iq->query_restart_count = 0;
 	iq->referral_count = 0;
 	iq->sent_count = 0;
+	iq->target_count = NULL;
 	iq->wait_priming_stub = 0;
 	iq->refetch_glue = 0;
 	iq->dnssec_expected = 0;
@@ -444,6 +445,26 @@ handle_cname_response(struct module_qsta
 	return 1;
 }
 
+/** create target count structure for this query */
+static void
+target_count_create(struct iter_qstate* iq)
+{
+	if(!iq->target_count) {
+		iq->target_count = (int*)calloc(2, sizeof(int));
+		/* if calloc fails we simply do not track this number */
+		if(iq->target_count)
+			iq->target_count[0] = 1;
+	}
+}
+
+static void
+target_count_increase(struct iter_qstate* iq, int num)
+{
+	target_count_create(iq);
+	if(iq->target_count)
+		iq->target_count[1] += num;
+}
+
 /**
  * Generate a subrequest.
  * Generate a local request event. Local events are tied to this module, and
@@ -515,6 +536,10 @@ generate_sub_request(uint8_t* qname, siz
 		subiq = (struct iter_qstate*)subq->minfo[id];
 		memset(subiq, 0, sizeof(*subiq));
 		subiq->num_target_queries = 0;
+		target_count_create(iq);
+		subiq->target_count = iq->target_count;
+		if(iq->target_count)
+			iq->target_count[0] ++; /* extra reference */
 		subiq->num_current_queries = 0;
 		subiq->depth = iq->depth+1;
 		outbound_list_init(&subiq->outlist);
@@ -1341,6 +1366,12 @@ query_for_targets(struct module_qstate*
 
 	if(iq->depth == ie->max_dependency_depth)
 		return 0;
+	if(iq->depth > 0 && iq->target_count &&
+		iq->target_count[1] > MAX_TARGET_COUNT) {
+		verbose(VERB_QUERY, "request has exceeded the maximum "
+			"number of glue fetches %d", iq->target_count[1]);
+		return 0;
+	}
 
 	iter_mark_cycle_targets(qstate, iq->dp);
 	missing = (int)delegpt_count_missing_targets(iq->dp);
@@ -1470,6 +1501,7 @@ processLastResort(struct module_qstate*
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
 		}
 		iq->num_target_queries += qs;
+		target_count_increase(iq, qs);
 		if(qs != 0) {
 			qstate->ext_state[id] = module_wait_subquery;
 			return 0; /* and wait for them */
@@ -1479,6 +1511,12 @@ processLastResort(struct module_qstate*
 		verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
 	}
+	if(iq->depth > 0 && iq->target_count &&
+		iq->target_count[1] > MAX_TARGET_COUNT) {
+		verbose(VERB_QUERY, "request has exceeded the maximum "
+			"number of glue fetches %d", iq->target_count[1]);
+		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+	}
 	/* mark cycle targets for parent-side lookups */
 	iter_mark_pside_cycle_targets(qstate, iq->dp);
 	/* see if we can issue queries to get nameserver addresses */
@@ -1508,6 +1546,7 @@ processLastResort(struct module_qstate*
 		if(query_count != 0) { /* suspend to await results */
 			verbose(VERB_ALGO, "try parent-side glue lookup");
 			iq->num_target_queries += query_count;
+			target_count_increase(iq, query_count);
 			qstate->ext_state[id] = module_wait_subquery;
 			return 0;
 		}
@@ -1664,6 +1703,7 @@ processQueryTargets(struct module_qstate
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
 		}
 		iq->num_target_queries += extra;
+		target_count_increase(iq, extra);
 		if(iq->num_target_queries > 0) {
 			/* wait to get all targets, we want to try em */
 			verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -1704,6 +1744,7 @@ processQueryTargets(struct module_qstate
 		/* errors ignored, these targets are not strictly necessary for
 		 * this result, we do not have to reply with SERVFAIL */
 		iq->num_target_queries += extra;
+		target_count_increase(iq, extra);
 	}
 
 	/* Add the current set of unused targets to our queue. */
@@ -1749,6 +1790,7 @@ processQueryTargets(struct module_qstate
 					return 1;
 				}
 				iq->num_target_queries += qs;
+				target_count_increase(iq, qs);
 			}
 			/* Since a target query might have been made, we 
 			 * need to check again. */
@@ -2822,6 +2864,8 @@ iter_clear(struct module_qstate* qstate,
 	iq = (struct iter_qstate*)qstate->minfo[id];
 	if(iq) {
 		outbound_list_clear(&iq->outlist);
+		if(iq->target_count && --iq->target_count[0] == 0)
+			free(iq->target_count);
 		iq->num_current_queries = 0;
 	}
 	qstate->minfo[id] = NULL;
--- unbound-1.4.17.orig/iterator/iterator.h
+++ unbound-1.4.17/iterator/iterator.h
@@ -52,6 +52,8 @@ struct iter_donotq;
 struct iter_prep_list;
 struct iter_priv;
 
+/** max number of targets spawned for a query and its subqueries */
+#define MAX_TARGET_COUNT	32
 /** max number of query restarts. Determines max number of CNAME chain. */
 #define MAX_RESTART_COUNT       8
 /** max number of referrals. Makes sure resolver does not run away */
@@ -254,6 +256,10 @@ struct iter_qstate {
 
 	/** number of queries fired off */
 	int sent_count;
+	
+	/** number of target queries spawned in [1], for this query and its
+	 * subqueries, the malloced-array is shared, [0] refcount. */
+	int* target_count;
 
 	/**
 	 * The query must store NS records from referrals as parentside RRs
--- unbound-1.4.17.orig/smallapp/unbound-control-setup.sh
+++ unbound-1.4.17/smallapp/unbound-control-setup.sh
@@ -157,6 +157,6 @@ chmod o-rw $SVR_BASE.pem $SVR_BASE.key $
 rm -f request.cfg
 rm -f $CTL_BASE"_trust.pem" $SVR_BASE"_trust.pem" $SVR_BASE"_trust.srl"
 
-echo "Setup success. Certificates created. Enable in unbound.conf file to use"
+echo "Setup success. Certificates created."
 
 exit 0
--- unbound-1.4.17.orig/util/config_file.c
+++ unbound-1.4.17/util/config_file.c
@@ -133,7 +133,7 @@ config_create(void)
 	init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
 	if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
 #ifdef HAVE_CHROOT
-	if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
+	if(!(cfg->chrootdir = strdup(""))) goto error_exit;
 #endif
 	if(!(cfg->directory = strdup(RUN_DIR))) goto error_exit;
 	if(!(cfg->logfile = strdup(""))) goto error_exit;
@@ -192,7 +192,7 @@ config_create(void)
 	cfg->local_zones_nodefault = NULL;
 	cfg->local_data = NULL;
 	cfg->python_script = NULL;
-	cfg->remote_control_enable = 0;
+	cfg->remote_control_enable = 1;
 	cfg->control_ifs = NULL;
 	cfg->control_port = UNBOUND_CONTROL_PORT;
 	cfg->minimal_responses = 0;
--- unbound-1.4.17.orig/util/net_help.c
+++ unbound-1.4.17/util/net_help.c
@@ -697,3 +697,54 @@ void* outgoing_ssl_fd(void* sslctx, int
 	}
 	return ssl;
 }
+
+/** 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 */
+}
+
--- unbound-1.4.17.orig/util/net_help.h
+++ unbound-1.4.17/util/net_help.h
@@ -369,4 +369,15 @@ void* incoming_ssl_fd(void* sslctx, int
  */
 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 */
