]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3688. [bug] loadnode could return a freed node on out of memory.
authorMark Andrews <marka@isc.org>
Thu, 12 Dec 2013 01:49:44 +0000 (12:49 +1100)
committerMark Andrews <marka@isc.org>
Thu, 12 Dec 2013 01:49:44 +0000 (12:49 +1100)
                        [RT #35106]

CHANGES
lib/dns/rbtdb.c

diff --git a/CHANGES b/CHANGES
index 4047f383d96ff87e338aaa42c82a1d2538b90c88..38acd889277f84fa08d34e1b53877b3eb7546334 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3688.  [bug]           loadnode could return a freed node on out of memory.
+                       [RT #35106]
+
 3687.  [bug]           Address null pointer dereference in zone_xfrdone.
                        [RT #35042]
 
index 966aebb784069b5d2e7b16b60f4f372eb2c1b188..827865e4473591303595a2ea6d627e8f16475051 100644 (file)
@@ -6834,27 +6834,42 @@ static isc_result_t
 loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep,
         isc_boolean_t hasnsec)
 {
-       isc_result_t noderesult, nsecresult;
-       dns_rbtnode_t *nsecnode;
-
-       noderesult = dns_rbt_addnode(rbtdb->tree, name, nodep);
+       isc_result_t noderesult, nsecresult, tmpresult;
+       dns_rbtnode_t *nsecnode = NULL, *node = NULL;
 
-       if (rbtdb->rpzs != NULL && noderesult == ISC_R_SUCCESS)
+       noderesult = dns_rbt_addnode(rbtdb->tree, name, &node);
+       if (rbtdb->rpzs != NULL && noderesult == ISC_R_SUCCESS) {
                noderesult = dns_rpz_add(rbtdb->load_rpzs, rbtdb->rpz_num,
                                         name);
-
+               if (noderesult != ISC_R_SUCCESS) {
+                       /*
+                        * Remove the node we just added above.
+                        */
+                       tmpresult = dns_rbt_deletenode(rbtdb->tree, node,
+                                                      ISC_FALSE);
+                       if (tmpresult != ISC_R_SUCCESS)
+                               isc_log_write(dns_lctx,
+                                             DNS_LOGCATEGORY_DATABASE,
+                                             DNS_LOGMODULE_CACHE,
+                                             ISC_LOG_WARNING,
+                                             "loading_addrdataset: "
+                                             "dns_rbt_deletenode: %s after "
+                                             "dns_rbt_addnode(NSEC): %s",
+                                             isc_result_totext(tmpresult),
+                                             isc_result_totext(ISC_R_SUCCESS));
+               }
+       }
        if (!hasnsec)
-               return (noderesult);
+               goto done;
        if (noderesult == ISC_R_EXISTS) {
                /*
                 * Add a node to the auxiliary NSEC tree for an old node
                 * just now getting an NSEC record.
                 */
-               if ((*nodep)->nsec == DNS_RBT_NSEC_HAS_NSEC)
-                       return (noderesult);
-       } else if (noderesult != ISC_R_SUCCESS) {
-               return (noderesult);
-       }
+               if (node->nsec == DNS_RBT_NSEC_HAS_NSEC)
+                       goto done;
+       } else if (noderesult != ISC_R_SUCCESS)
+               goto done;
 
        /*
         * Build the auxiliary tree for NSECs as we go.
@@ -6864,12 +6879,11 @@ loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep,
         * Add nodes to the auxiliary tree after corresponding nodes have
         * been added to the main tree.
         */
-       nsecnode = NULL;
        nsecresult = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode);
        if (nsecresult == ISC_R_SUCCESS) {
                nsecnode->nsec = DNS_RBT_NSEC_NSEC;
-               (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC;
-               return (noderesult);
+               node->nsec = DNS_RBT_NSEC_HAS_NSEC;
+               goto done;
        }
 
        if (nsecresult == ISC_R_EXISTS) {
@@ -6880,21 +6894,38 @@ loadnode(dns_rbtdb_t *rbtdb, dns_name_t *name, dns_rbtnode_t **nodep,
                              ISC_LOG_WARNING,
                              "addnode: NSEC node already exists");
 #endif
-               (*nodep)->nsec = DNS_RBT_NSEC_HAS_NSEC;
-               return (noderesult);
+               node->nsec = DNS_RBT_NSEC_HAS_NSEC;
+               goto done;
        }
 
-       nsecresult = dns_rbt_deletenode(rbtdb->tree, *nodep, ISC_FALSE);
-       if (nsecresult != ISC_R_SUCCESS)
-               isc_log_write(dns_lctx,
-                             DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE,
-                             ISC_LOG_WARNING,
-                             "loading_addrdataset: "
-                             "dns_rbt_deletenode: %s after "
-                             "dns_rbt_addnode(NSEC): %s",
-                             isc_result_totext(nsecresult),
-                             isc_result_totext(noderesult));
+       if (noderesult == ISC_R_SUCCESS) {
+               /*
+                * Remove the node we just added above.
+                */
+               tmpresult = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+               if (tmpresult != ISC_R_SUCCESS)
+                       isc_log_write(dns_lctx,
+                                     DNS_LOGCATEGORY_DATABASE,
+                                     DNS_LOGMODULE_CACHE,
+                                     ISC_LOG_WARNING,
+                                     "loading_addrdataset: "
+                                     "dns_rbt_deletenode: %s after "
+                                     "dns_rbt_addnode(NSEC): %s",
+                                     isc_result_totext(tmpresult),
+                                     isc_result_totext(noderesult));
+               if (rbtdb->rpzs != NULL && noderesult == ISC_R_SUCCESS)
+                       dns_rpz_delete(rbtdb->rpzs, rbtdb->rpz_num, name);
+       }
+
+       /*
+        * Set the error condition to be returned.
+        */
+       noderesult = nsecresult;
+
+ done:
+       if (noderesult == ISC_R_SUCCESS || noderesult == ISC_R_EXISTS)
+               *nodep = node;
+
        return (noderesult);
 }