2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 23:25:38 +00:00

Use dns_name_copynf() with dns_message_gettempname() when needed

dns_message_gettempname() returns an initialized name with a dedicated
buffer, associated with a dns_fixedname object.  Using dns_name_copynf()
to write a name into this object will actually copy the name data
from a source name. dns_name_clone() merely points target->ndata to
source->ndata, so it is faster, but it can lead to a use-after-free if
the source is freed before the target object is released via
dns_message_puttempname().

In a few places, clone was being used where copynf should have been;
this is now fixed.

As a side note, no memory was lost, because the ndata buffer used in
the dns_fixedname_t is internal to the structure, and is freed when
the dns_fixedname_t is freed regardless of the .ndata contents.
This commit is contained in:
Ondřej Surý
2021-05-21 15:30:00 +02:00
committed by Evan Hunt
parent 10ced46739
commit ce3e1abc1d
5 changed files with 31 additions and 17 deletions

View File

@@ -638,7 +638,7 @@ dns_name_clone(const dns_name_t *source, dns_name_t *target);
* Notes: * Notes:
* *
* \li 'target' refers to the same memory as 'source', so 'source' * \li 'target' refers to the same memory as 'source', so 'source'
* must not be changed while 'target' is still in use. * must not be changed or freed while 'target' is still in use.
* *
* \li This call is functionally equivalent to: * \li This call is functionally equivalent to:
* *
@@ -1242,22 +1242,17 @@ dns_name_settotextfilter(dns_name_totextfilter_t *proc);
isc_result_t isc_result_t
dns_name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target); dns_name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target);
void
dns_name_copynf(const dns_name_t *source, dns_name_t *dest);
/*%< /*%<
* Makes 'dest' refer to a copy of the name in 'source'. The data are either * Copies the name in 'source' into 'dest'. The name data is copied to
* copied to 'target' or in case of dns_name_copynf the dedicated buffer in * the 'target' buffer, which is then set as the buffer for 'dest'.
* 'dest'.
* *
* Requires: * Requires:
* \li 'source' is a valid name. * \li 'source' is a valid name.
* *
* \li 'dest' is an initialized name with a dedicated buffer. * \li 'dest' is an initialized name.
* *
* \li 'target' is an initialized buffer. * \li 'target' is an initialized buffer.
* *
* \li Either dest has a dedicated buffer or target != NULL.
*
* Ensures: * Ensures:
* *
*\li On success, the used space in target is updated. *\li On success, the used space in target is updated.
@@ -1267,6 +1262,18 @@ dns_name_copynf(const dns_name_t *source, dns_name_t *dest);
*\li #ISC_R_NOSPACE *\li #ISC_R_NOSPACE
*/ */
void
dns_name_copynf(const dns_name_t *source, dns_name_t *dest);
/*%<
* Copies the name in 'source' into 'dest'. The name data is copied to
* the dedicated buffer for 'dest'.
*
* Requires:
* \li 'source' is a valid name.
*
* \li 'dest' is an initialized name with a dedicated buffer.
*/
bool bool
dns_name_ishostname(const dns_name_t *name, bool wildcard); dns_name_ishostname(const dns_name_t *name, bool wildcard);
/*%< /*%<

View File

@@ -2464,7 +2464,7 @@ dns_name_fromstring2(dns_name_t *target, const char *src,
static isc_result_t static isc_result_t
name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
unsigned char *ndata; unsigned char *ndata = NULL;
/* /*
* Make dest a copy of source. * Make dest a copy of source.
@@ -2496,7 +2496,7 @@ name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
} }
if (dest->labels > 0 && dest->offsets != NULL) { if (dest->labels > 0 && dest->offsets != NULL) {
if (source->offsets != NULL) { if (source->offsets != NULL && source->labels != 0) {
memmove(dest->offsets, source->offsets, source->labels); memmove(dest->offsets, source->offsets, source->labels);
} else { } else {
set_offsets(dest, dest->offsets, NULL); set_offsets(dest, dest->offsets, NULL);

View File

@@ -180,7 +180,7 @@ add_rdata_to_list(dns_message_t *msg, dns_name_t *name, dns_rdata_t *rdata,
dns_message_takebuffer(msg, &tmprdatabuf); dns_message_takebuffer(msg, &tmprdatabuf);
RETERR(dns_message_gettempname(msg, &newname)); RETERR(dns_message_gettempname(msg, &newname));
dns_name_clone(name, newname); dns_name_copynf(name, newname);
RETERR(dns_message_gettemprdatalist(msg, &newlist)); RETERR(dns_message_gettemprdatalist(msg, &newlist));
newlist->rdclass = newrdata->rdclass; newlist->rdclass = newrdata->rdclass;

View File

@@ -1020,7 +1020,7 @@ dns_tsig_sign(dns_message_t *msg) {
if (ret != ISC_R_SUCCESS) { if (ret != ISC_R_SUCCESS) {
goto cleanup_rdata; goto cleanup_rdata;
} }
dns_name_clone(&key->name, owner); dns_name_copynf(&key->name, owner);
ret = dns_message_gettemprdatalist(msg, &datalist); ret = dns_message_gettemprdatalist(msg, &datalist);
if (ret != ISC_R_SUCCESS) { if (ret != ISC_R_SUCCESS) {

View File

@@ -9804,7 +9804,7 @@ query_synthcnamewildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_rdata_reset(&rdata); dns_rdata_reset(&rdata);
dns_name_clone(&cname.cname, tname); dns_name_copynf(&cname.cname, tname);
dns_rdata_freestruct(&cname); dns_rdata_freestruct(&cname);
ns_client_qnamereplace(qctx->client, tname); ns_client_qnamereplace(qctx->client, tname);
@@ -10416,7 +10416,7 @@ query_cname(query_ctx_t *qctx) {
RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_rdata_reset(&rdata); dns_rdata_reset(&rdata);
dns_name_clone(&cname.cname, tname); dns_name_copynf(&cname.cname, tname);
dns_rdata_freestruct(&cname); dns_rdata_freestruct(&cname);
ns_client_qnamereplace(qctx->client, tname); ns_client_qnamereplace(qctx->client, tname);
@@ -10518,7 +10518,7 @@ query_dname(query_ctx_t *qctx) {
RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_rdata_reset(&rdata); dns_rdata_reset(&rdata);
dns_name_clone(&dname.dname, tname); dns_name_copynf(&dname.dname, tname);
dns_rdata_freestruct(&dname); dns_rdata_freestruct(&dname);
/* /*
@@ -10616,7 +10616,8 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
return (result); return (result);
} }
dns_name_clone(client->query.qname, aname);
dns_name_copynf(client->query.qname, aname);
result = dns_message_gettemprdatalist(client->message, &rdatalist); result = dns_message_gettemprdatalist(client->message, &rdatalist);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
@@ -10751,7 +10752,13 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
return (result); return (result);
} }
/*
* We'll be releasing 'name' before returning, so it's safe to
* use clone instead of copying here.
*/
dns_name_clone(dns_db_origin(qctx->db), name); dns_name_clone(dns_db_origin(qctx->db), name);
rdataset = ns_client_newrdataset(client); rdataset = ns_client_newrdataset(client);
if (rdataset == NULL) { if (rdataset == NULL) {
CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset"); CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset");