mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-04 16:45:24 +00:00
[9.20] [CVE-2025-40775] sec: usr: Prevent assertion when processing TSIG algorithm
DNS messages that included a Transaction Signature (TSIG) containing an invalid value in the algorithm field caused :iscman:`named` to crash with an assertion failure. This has been fixed. :cve:`2025-40775` Backport of !793 See isc-projects/bind9#5300 Merge branch '5300-confidential-tsig-unknown-alg-bind-9.20' into 'v9.20.9-release' See merge request isc-private/bind9!795
This commit is contained in:
@@ -287,18 +287,16 @@ struct dns_message {
|
|||||||
ISC_LIST(dns_rdata_t) freerdata;
|
ISC_LIST(dns_rdata_t) freerdata;
|
||||||
ISC_LIST(dns_rdatalist_t) freerdatalist;
|
ISC_LIST(dns_rdatalist_t) freerdatalist;
|
||||||
|
|
||||||
dns_rcode_t tsigstatus;
|
dns_rcode_t tsigstatus;
|
||||||
dns_rcode_t querytsigstatus;
|
dns_rcode_t querytsigstatus;
|
||||||
dns_name_t *tsigname; /* Owner name of TSIG, if any
|
dns_name_t *tsigname; /* Owner name of TSIG, if any */
|
||||||
* */
|
|
||||||
dns_rdataset_t *querytsig;
|
dns_rdataset_t *querytsig;
|
||||||
dns_tsigkey_t *tsigkey;
|
dns_tsigkey_t *tsigkey;
|
||||||
dst_context_t *tsigctx;
|
dst_context_t *tsigctx;
|
||||||
int sigstart;
|
int sigstart;
|
||||||
int timeadjust;
|
int timeadjust;
|
||||||
|
|
||||||
dns_name_t *sig0name; /* Owner name of SIG0, if any
|
dns_name_t *sig0name; /* Owner name of SIG0, if any */
|
||||||
* */
|
|
||||||
dst_key_t *sig0key;
|
dst_key_t *sig0key;
|
||||||
dns_rcode_t sig0status;
|
dns_rcode_t sig0status;
|
||||||
isc_region_t query;
|
isc_region_t query;
|
||||||
|
@@ -79,12 +79,14 @@ struct dns_tsigkeyring {
|
|||||||
|
|
||||||
struct dns_tsigkey {
|
struct dns_tsigkey {
|
||||||
/* Unlocked */
|
/* Unlocked */
|
||||||
unsigned int magic; /*%< Magic number. */
|
unsigned int magic; /*%< Magic number. */
|
||||||
isc_mem_t *mctx;
|
isc_mem_t *mctx;
|
||||||
dst_key_t *key; /*%< Key */
|
dst_key_t *key; /*%< Key */
|
||||||
dns_fixedname_t fn;
|
dns_fixedname_t fn;
|
||||||
dns_name_t *name; /*%< Key name */
|
dns_name_t *name; /*%< Key name */
|
||||||
const dns_name_t *algorithm; /*%< Algorithm name */
|
dst_algorithm_t alg; /*< Algorithm */
|
||||||
|
dns_name_t algname; /*< Algorithm name, only used if
|
||||||
|
algorithm is DST_ALG_UNKNOWN */
|
||||||
dns_name_t *creator; /*%< name that created secret */
|
dns_name_t *creator; /*%< name that created secret */
|
||||||
bool generated : 1; /*%< key was auto-generated */
|
bool generated : 1; /*%< key was auto-generated */
|
||||||
bool restored : 1; /*%< key was restored at startup */
|
bool restored : 1; /*%< key was restored at startup */
|
||||||
@@ -240,6 +242,16 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkeyp, const dns_name_t *name,
|
|||||||
*\li #ISC_R_NOTFOUND
|
*\li #ISC_R_NOTFOUND
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const dns_name_t *
|
||||||
|
dns_tsigkey_algorithm(dns_tsigkey_t *tkey);
|
||||||
|
/*%<
|
||||||
|
* Returns the key algorithm associated with a tsigkey object.
|
||||||
|
*
|
||||||
|
* Note that when a tsigkey object is created with algorithm
|
||||||
|
* DST_ALG_UNKNOWN, the unknown algorithm's name must be cloned
|
||||||
|
* into tsigkey->algname.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp);
|
dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp);
|
||||||
/*%<
|
/*%<
|
||||||
|
@@ -687,12 +687,11 @@ msgreset(dns_message_t *msg, bool everything) {
|
|||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
spacefortsig(dns_tsigkey_t *key, int otherlen) {
|
spacefortsig(dns_tsigkey_t *key, int otherlen) {
|
||||||
isc_region_t r1, r2;
|
isc_region_t r1 = { 0 }, r2 = { 0 };
|
||||||
unsigned int x;
|
unsigned int x = 0;
|
||||||
isc_result_t result;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The space required for an TSIG record is:
|
* The space required for a TSIG record is:
|
||||||
*
|
*
|
||||||
* n1 bytes for the name
|
* n1 bytes for the name
|
||||||
* 2 bytes for the type
|
* 2 bytes for the type
|
||||||
@@ -713,11 +712,11 @@ spacefortsig(dns_tsigkey_t *key, int otherlen) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
dns_name_toregion(key->name, &r1);
|
dns_name_toregion(key->name, &r1);
|
||||||
dns_name_toregion(key->algorithm, &r2);
|
if (key->alg != DST_ALG_UNKNOWN) {
|
||||||
if (key->key == NULL) {
|
dns_name_toregion(dns_tsigkey_algorithm(key), &r2);
|
||||||
x = 0;
|
}
|
||||||
} else {
|
if (key->key != NULL) {
|
||||||
result = dst_key_sigsize(key->key, &x);
|
isc_result_t result = dst_key_sigsize(key->key, &x);
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (result != ISC_R_SUCCESS) {
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
|
@@ -205,28 +205,6 @@ adjust_lru(dns_tsigkey_t *tkey) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const dns_name_t *
|
|
||||||
namefromalg(dst_algorithm_t alg) {
|
|
||||||
switch (alg) {
|
|
||||||
case DST_ALG_HMACMD5:
|
|
||||||
return dns_tsig_hmacmd5_name;
|
|
||||||
case DST_ALG_HMACSHA1:
|
|
||||||
return dns_tsig_hmacsha1_name;
|
|
||||||
case DST_ALG_HMACSHA224:
|
|
||||||
return dns_tsig_hmacsha224_name;
|
|
||||||
case DST_ALG_HMACSHA256:
|
|
||||||
return dns_tsig_hmacsha256_name;
|
|
||||||
case DST_ALG_HMACSHA384:
|
|
||||||
return dns_tsig_hmacsha384_name;
|
|
||||||
case DST_ALG_HMACSHA512:
|
|
||||||
return dns_tsig_hmacsha512_name;
|
|
||||||
case DST_ALG_GSSAPI:
|
|
||||||
return dns_tsig_gssapi_name;
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm,
|
dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm,
|
||||||
dst_key_t *dstkey, bool generated, bool restored,
|
dst_key_t *dstkey, bool generated, bool restored,
|
||||||
@@ -246,6 +224,8 @@ dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm,
|
|||||||
.restored = restored,
|
.restored = restored,
|
||||||
.inception = inception,
|
.inception = inception,
|
||||||
.expire = expire,
|
.expire = expire,
|
||||||
|
.alg = algorithm,
|
||||||
|
.algname = DNS_NAME_INITEMPTY,
|
||||||
.link = ISC_LINK_INITIALIZER,
|
.link = ISC_LINK_INITIALIZER,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -263,8 +243,6 @@ dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm,
|
|||||||
goto cleanup_name;
|
goto cleanup_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
tkey->algorithm = namefromalg(algorithm);
|
|
||||||
|
|
||||||
if (creator != NULL) {
|
if (creator != NULL) {
|
||||||
tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
|
tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
|
||||||
dns_name_init(tkey->creator, NULL);
|
dns_name_init(tkey->creator, NULL);
|
||||||
@@ -448,7 +426,8 @@ dump_key(dns_tsigkey_t *tkey, FILE *fp) {
|
|||||||
|
|
||||||
dns_name_format(tkey->name, namestr, sizeof(namestr));
|
dns_name_format(tkey->name, namestr, sizeof(namestr));
|
||||||
dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
|
dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
|
||||||
dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr));
|
dns_name_format(dns_tsigkey_algorithm(tkey), algorithmstr,
|
||||||
|
sizeof(algorithmstr));
|
||||||
result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
|
result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
|
||||||
if (result == ISC_R_SUCCESS) {
|
if (result == ISC_R_SUCCESS) {
|
||||||
fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
|
fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
|
||||||
@@ -621,7 +600,7 @@ dns_tsig_sign(dns_message_t *msg) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dns_name_init(&tsig.algorithm, NULL);
|
dns_name_init(&tsig.algorithm, NULL);
|
||||||
dns_name_clone(key->algorithm, &tsig.algorithm);
|
dns_name_clone(dns_tsigkey_algorithm(key), &tsig.algorithm);
|
||||||
|
|
||||||
isc_buffer_init(&databuf, data, sizeof(data));
|
isc_buffer_init(&databuf, data, sizeof(data));
|
||||||
|
|
||||||
@@ -978,12 +957,17 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|||||||
}
|
}
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (result != ISC_R_SUCCESS) {
|
||||||
msg->tsigstatus = dns_tsigerror_badkey;
|
msg->tsigstatus = dns_tsigerror_badkey;
|
||||||
result = dns_tsigkey_create(
|
alg = dns__tsig_algfromname(&tsig.algorithm);
|
||||||
keyname, dns__tsig_algfromname(&tsig.algorithm),
|
result = dns_tsigkey_create(keyname, alg, NULL, 0, mctx,
|
||||||
NULL, 0, mctx, &msg->tsigkey);
|
&msg->tsigkey);
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (result != ISC_R_SUCCESS) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (alg == DST_ALG_UNKNOWN) {
|
||||||
|
dns_name_clone(&tsig.algorithm,
|
||||||
|
&msg->tsigkey->algname);
|
||||||
|
}
|
||||||
|
|
||||||
tsig_log(msg->tsigkey, 2, "unknown key");
|
tsig_log(msg->tsigkey, 2, "unknown key");
|
||||||
return DNS_R_TSIGVERIFYFAILURE;
|
return DNS_R_TSIGVERIFYFAILURE;
|
||||||
}
|
}
|
||||||
@@ -1107,7 +1091,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|||||||
/*
|
/*
|
||||||
* Digest the key algorithm.
|
* Digest the key algorithm.
|
||||||
*/
|
*/
|
||||||
dns_name_toregion(tsigkey->algorithm, &r);
|
dns_name_toregion(dns_tsigkey_algorithm(tsigkey), &r);
|
||||||
result = dst_context_adddata(ctx, &r);
|
result = dst_context_adddata(ctx, &r);
|
||||||
if (result != ISC_R_SUCCESS) {
|
if (result != ISC_R_SUCCESS) {
|
||||||
goto cleanup_context;
|
goto cleanup_context;
|
||||||
@@ -1555,7 +1539,8 @@ again:
|
|||||||
RWUNLOCK(&ring->lock, locktype);
|
RWUNLOCK(&ring->lock, locktype);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
|
|
||||||
|
if (algorithm != NULL && key->alg != dns__tsig_algfromname(algorithm)) {
|
||||||
RWUNLOCK(&ring->lock, locktype);
|
RWUNLOCK(&ring->lock, locktype);
|
||||||
return ISC_R_NOTFOUND;
|
return ISC_R_NOTFOUND;
|
||||||
}
|
}
|
||||||
@@ -1581,6 +1566,39 @@ again:
|
|||||||
return ISC_R_SUCCESS;
|
return ISC_R_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dns_name_t *
|
||||||
|
dns_tsigkey_algorithm(dns_tsigkey_t *tkey) {
|
||||||
|
REQUIRE(VALID_TSIGKEY(tkey));
|
||||||
|
|
||||||
|
switch (tkey->alg) {
|
||||||
|
case DST_ALG_HMACMD5:
|
||||||
|
return dns_tsig_hmacmd5_name;
|
||||||
|
case DST_ALG_HMACSHA1:
|
||||||
|
return dns_tsig_hmacsha1_name;
|
||||||
|
case DST_ALG_HMACSHA224:
|
||||||
|
return dns_tsig_hmacsha224_name;
|
||||||
|
case DST_ALG_HMACSHA256:
|
||||||
|
return dns_tsig_hmacsha256_name;
|
||||||
|
case DST_ALG_HMACSHA384:
|
||||||
|
return dns_tsig_hmacsha384_name;
|
||||||
|
case DST_ALG_HMACSHA512:
|
||||||
|
return dns_tsig_hmacsha512_name;
|
||||||
|
case DST_ALG_GSSAPI:
|
||||||
|
return dns_tsig_gssapi_name;
|
||||||
|
|
||||||
|
case DST_ALG_UNKNOWN:
|
||||||
|
/*
|
||||||
|
* If the tsigkey object was created with an
|
||||||
|
* unknown algorithm, then we cloned
|
||||||
|
* the algorithm name here.
|
||||||
|
*/
|
||||||
|
return &tkey->algname;
|
||||||
|
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp) {
|
dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp) {
|
||||||
dns_tsigkeyring_t *ring = NULL;
|
dns_tsigkeyring_t *ring = NULL;
|
||||||
|
@@ -118,7 +118,7 @@ add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target,
|
|||||||
tsig.common.rdtype = dns_rdatatype_tsig;
|
tsig.common.rdtype = dns_rdatatype_tsig;
|
||||||
ISC_LINK_INIT(&tsig.common, link);
|
ISC_LINK_INIT(&tsig.common, link);
|
||||||
dns_name_init(&tsig.algorithm, NULL);
|
dns_name_init(&tsig.algorithm, NULL);
|
||||||
dns_name_clone(key->algorithm, &tsig.algorithm);
|
dns_name_clone(dns_tsigkey_algorithm(key), &tsig.algorithm);
|
||||||
|
|
||||||
tsig.timesigned = now;
|
tsig.timesigned = now;
|
||||||
tsig.fudge = DNS_TSIG_FUDGE;
|
tsig.fudge = DNS_TSIG_FUDGE;
|
||||||
|
Reference in New Issue
Block a user