Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Hi,

Please unblock unbound 1.4.22-3.  This version addresses CVE-2014-8602,
"denial of service by making resolver chase endless series of
delegations", based on upstream's patch:

    http://unbound.net/downloads/CVE-2014-8602.txt

Actually, I cherry picked upstream's svn r3289 and applied it against
the version of unbound in testing:

    
http://anonscm.debian.org/cgit/users/edmonds/unbound.git/commit/?h=branches/1.4.22%2bjessie&id=15037ee5f483ad5ef10ad7c99221b3b77018413b

The Debian bug tracking this issue is #772622.

This issue was found in at least three recursive DNS servers: BIND,
Unbound, and PowerDNS Recursor and was fixed in coordinated releases.
See also:

    https://kb.isc.org/article/AA-01216/
        "A Defect in Delegation Handling Can Be Exploited to Crash BIND"
        [CVE-2014-8500]

        (And Debian #772610.)

    http://doc.powerdns.com/md/security/powerdns-advisory-2014-02/
        "PowerDNS Recursor 3.6.1 and earlier can be made to provide bad service"
        [CVE-2014-8601]

The debdiff is below.

Thanks!

diff -Nru unbound-1.4.22/debian/changelog unbound-1.4.22/debian/changelog
--- unbound-1.4.22/debian/changelog     2014-08-18 16:22:31.000000000 -0400
+++ unbound-1.4.22/debian/changelog     2014-12-09 17:55:16.000000000 -0500
@@ -1,3 +1,10 @@
+unbound (1.4.22-3) unstable; urgency=medium
+
+  * Fix CVE-2014-8602: denial of service by making resolver chase endless
+    series of delegations; closes: #772622.
+
+ -- Robert Edmonds <edmo...@debian.org>  Tue, 09 Dec 2014 17:52:08 -0500
+
 unbound (1.4.22-2) unstable; urgency=medium
 
   * Drop unneeded Build-Dependency on doxygen.
diff -Nru unbound-1.4.22/debian/patches/debian-changes 
unbound-1.4.22/debian/patches/debian-changes
--- unbound-1.4.22/debian/patches/debian-changes        2014-08-18 
16:23:10.000000000 -0400
+++ unbound-1.4.22/debian/patches/debian-changes        2014-12-09 
17:58:56.000000000 -0500
@@ -5,15 +5,12 @@
  information below has been extracted from the changelog. Adjust it or drop
  it.
  .
- unbound (1.4.22-2) unstable; urgency=medium
+ unbound (1.4.22-3) unstable; urgency=medium
  .
-   * Drop unneeded Build-Dependency on doxygen.
-   * Drop unneeded Build-Dependency on automake. (Unbound does not use
-     automake.)
-   * Use dh_autotools-dev_updateconfig to update the config.{guess,sub} files
-     at build time; closes: #746313.
-Author: Robert S. Edmonds <edmo...@debian.org>
-Bug-Debian: http://bugs.debian.org/746313
+   * Fix CVE-2014-8602: denial of service by making resolver chase endless
+     series of delegations; closes: #772622.
+Author: Robert Edmonds <edmo...@debian.org>
+Bug-Debian: http://bugs.debian.org/772622
 
 ---
 The information above should follow the Patch Tagging Guidelines, please
@@ -66,6 +63,151 @@
  If turned off, the server does not listen for control commands.
  .TP 5
  .B control\-interface: <ip address>
+--- unbound-1.4.22.orig/iterator/iterator.c
++++ unbound-1.4.22/iterator/iterator.c
+@@ -120,6 +120,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;
+@@ -445,6 +446,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
+@@ -516,6 +537,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);
+@@ -1342,6 +1367,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);
+@@ -1524,6 +1555,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 */
+@@ -1533,6 +1565,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 */
+@@ -1562,6 +1600,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;
+               }
+@@ -1717,6 +1756,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");
+@@ -1757,6 +1797,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. */
+@@ -1802,6 +1843,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. */
+@@ -2894,6 +2936,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.22.orig/iterator/iterator.h
++++ unbound-1.4.22/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.22.orig/smallapp/unbound-control-setup.sh
 +++ unbound-1.4.22/smallapp/unbound-control-setup.sh
 @@ -157,6 +157,6 @@ chmod o-rw $SVR_BASE.pem $SVR_BASE.key $

-- 
Robert Edmonds
edmo...@debian.org


-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to