malmond / rpms / unbound

Forked from rpms/unbound 3 years ago
Clone

Blame SOURCES/unbound-1.4.20-CVE-2014-8602.patch

9d429a
Index: iterator/iterator.c
9d429a
===================================================================
9d429a
--- iterator/iterator.c	(revision 3272)
9d429a
+++ iterator/iterator.c	(working copy)
9d429a
@@ -120,6 +120,7 @@
9d429a
 	iq->query_restart_count = 0;
9d429a
 	iq->referral_count = 0;
9d429a
 	iq->sent_count = 0;
9d429a
+	iq->target_count = NULL;
9d429a
 	iq->wait_priming_stub = 0;
9d429a
 	iq->refetch_glue = 0;
9d429a
 	iq->dnssec_expected = 0;
9d429a
@@ -453,6 +454,26 @@
9d429a
 	return 1;
9d429a
 }
9d429a
 
9d429a
+/** create target count structure for this query */
9d429a
+static void
9d429a
+target_count_create(struct iter_qstate* iq)
9d429a
+{
9d429a
+	if(!iq->target_count) {
9d429a
+		iq->target_count = (int*)calloc(2, sizeof(int));
9d429a
+		/* if calloc fails we simply do not track this number */
9d429a
+		if(iq->target_count)
9d429a
+			iq->target_count[0] = 1;
9d429a
+	}
9d429a
+}
9d429a
+
9d429a
+static void
9d429a
+target_count_increase(struct iter_qstate* iq, int num)
9d429a
+{
9d429a
+	target_count_create(iq);
9d429a
+	if(iq->target_count)
9d429a
+		iq->target_count[1] += num;
9d429a
+}
9d429a
+
9d429a
 /**
9d429a
  * Generate a subrequest.
9d429a
  * Generate a local request event. Local events are tied to this module, and
9d429a
@@ -524,6 +545,10 @@
9d429a
 		subiq = (struct iter_qstate*)subq->minfo[id];
9d429a
 		memset(subiq, 0, sizeof(*subiq));
9d429a
 		subiq->num_target_queries = 0;
9d429a
+		target_count_create(iq);
9d429a
+		subiq->target_count = iq->target_count;
9d429a
+		if(iq->target_count)
9d429a
+			iq->target_count[0] ++; /* extra reference */
9d429a
 		subiq->num_current_queries = 0;
9d429a
 		subiq->depth = iq->depth+1;
9d429a
 		outbound_list_init(&subiq->outlist);
9d429a
@@ -1350,6 +1375,12 @@
9d429a
 
9d429a
 	if(iq->depth == ie->max_dependency_depth)
9d429a
 		return 0;
9d429a
+	if(iq->depth > 0 && iq->target_count &&
9d429a
+		iq->target_count[1] > MAX_TARGET_COUNT) {
9d429a
+		verbose(VERB_QUERY, "request has exceeded the maximum "
9d429a
+			"number of glue fetches %d", iq->target_count[1]);
9d429a
+		return 0;
9d429a
+	}
9d429a
 
9d429a
 	iter_mark_cycle_targets(qstate, iq->dp);
9d429a
 	missing = (int)delegpt_count_missing_targets(iq->dp);
9d429a
@@ -1532,6 +1563,7 @@
9d429a
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
9d429a
 		}
9d429a
 		iq->num_target_queries += qs;
9d429a
+		target_count_increase(iq, qs);
9d429a
 		if(qs != 0) {
9d429a
 			qstate->ext_state[id] = module_wait_subquery;
9d429a
 			return 0; /* and wait for them */
9d429a
@@ -1541,6 +1573,12 @@
9d429a
 		verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
9d429a
 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
9d429a
 	}
9d429a
+	if(iq->depth > 0 && iq->target_count &&
9d429a
+		iq->target_count[1] > MAX_TARGET_COUNT) {
9d429a
+		verbose(VERB_QUERY, "request has exceeded the maximum "
9d429a
+			"number of glue fetches %d", iq->target_count[1]);
9d429a
+		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
9d429a
+	}
9d429a
 	/* mark cycle targets for parent-side lookups */
9d429a
 	iter_mark_pside_cycle_targets(qstate, iq->dp);
9d429a
 	/* see if we can issue queries to get nameserver addresses */
9d429a
@@ -1570,6 +1608,7 @@
9d429a
 		if(query_count != 0) { /* suspend to await results */
9d429a
 			verbose(VERB_ALGO, "try parent-side glue lookup");
9d429a
 			iq->num_target_queries += query_count;
9d429a
+			target_count_increase(iq, query_count);
9d429a
 			qstate->ext_state[id] = module_wait_subquery;
9d429a
 			return 0;
9d429a
 		}
9d429a
@@ -1725,6 +1764,7 @@
9d429a
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
9d429a
 		}
9d429a
 		iq->num_target_queries += extra;
9d429a
+		target_count_increase(iq, extra);
9d429a
 		if(iq->num_target_queries > 0) {
9d429a
 			/* wait to get all targets, we want to try em */
9d429a
 			verbose(VERB_ALGO, "wait for all targets for fallback");
9d429a
@@ -1765,6 +1805,7 @@
9d429a
 		/* errors ignored, these targets are not strictly necessary for
9d429a
 		 * this result, we do not have to reply with SERVFAIL */
9d429a
 		iq->num_target_queries += extra;
9d429a
+		target_count_increase(iq, extra);
9d429a
 	}
9d429a
 
9d429a
 	/* Add the current set of unused targets to our queue. */
9d429a
@@ -1810,6 +1851,7 @@
9d429a
 					return 1;
9d429a
 				}
9d429a
 				iq->num_target_queries += qs;
9d429a
+				target_count_increase(iq, qs);
9d429a
 			}
9d429a
 			/* Since a target query might have been made, we 
9d429a
 			 * need to check again. */
9d429a
@@ -2921,6 +2963,8 @@
9d429a
 	iq = (struct iter_qstate*)qstate->minfo[id];
9d429a
 	if(iq) {
9d429a
 		outbound_list_clear(&iq->outlist);
9d429a
+		if(iq->target_count && --iq->target_count[0] == 0)
9d429a
+			free(iq->target_count);
9d429a
 		iq->num_current_queries = 0;
9d429a
 	}
9d429a
 	qstate->minfo[id] = NULL;
9d429a
Index: iterator/iterator.h
9d429a
===================================================================
9d429a
--- iterator/iterator.h	(revision 3272)
9d429a
+++ iterator/iterator.h	(working copy)
9d429a
@@ -52,6 +52,8 @@
9d429a
 struct iter_prep_list;
9d429a
 struct iter_priv;
9d429a
 
9d429a
+/** max number of targets spawned for a query and its subqueries */
9d429a
+#define MAX_TARGET_COUNT	32
9d429a
 /** max number of query restarts. Determines max number of CNAME chain. */
9d429a
 #define MAX_RESTART_COUNT       8
9d429a
 /** max number of referrals. Makes sure resolver does not run away */
9d429a
@@ -251,6 +253,10 @@
9d429a
 
9d429a
 	/** number of queries fired off */
9d429a
 	int sent_count;
9d429a
+	
9d429a
+	/** number of target queries spawned in [1], for this query and its
9d429a
+	 * subqueries, the malloced-array is shared, [0] refcount. */
9d429a
+	int* target_count;
9d429a
 
9d429a
 	/**
9d429a
 	 * The query must store NS records from referrals as parentside RRs