From: Mark Andrews Date: Thu, 12 Dec 2013 01:50:37 +0000 (+1100) Subject: 3688. [bug] loadnode could return a freed node on out of memory. X-Git-Tag: v9.8.7b1~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=640ca0e048efaac6b2db0de4da89fa1e17a93a57;p=thirdparty%2Fbind9.git 3688. [bug] loadnode could return a freed node on out of memory. [RT #35106] --- diff --git a/CHANGES b/CHANGES index 011537dccef..a9035341a17 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3688. [bug] loadnode could return a freed node on out of memory. + [RT #35106] + --- 9.8.7b1 released --- 3683. [cleanup] Add a more detailed "not found" message to rndc diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index b87625c005b..ddd4ce463c0 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -6867,28 +6867,21 @@ 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); - -#ifdef BIND9 - if (noderesult == ISC_R_SUCCESS && rbtdb->rpz_cidr != NULL) - dns_rpz_cidr_addip(rbtdb->rpz_cidr, name); -#endif + isc_result_t noderesult, nsecresult, tmpresult; + dns_rbtnode_t *nsecnode = NULL, *node = NULL; + noderesult = dns_rbt_addnode(rbtdb->tree, name, &node); 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. @@ -6898,12 +6891,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) { @@ -6914,21 +6906,41 @@ 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)); + + } + + /* + * Set the error condition to be returned. + */ + noderesult = nsecresult; + + done: +#ifdef BIND9 + if (noderesult == ISC_R_SUCCESS && rbtdb->rpz_cidr != NULL) + dns_rpz_cidr_addip(rbtdb->rpz_cidr, name); +#endif + if (noderesult == ISC_R_SUCCESS || noderesult == ISC_R_EXISTS) + *nodep = node; + return (noderesult); }