- Fix CVE-2026-46582, A wildcard replay, as another piece of data,

triggers poisoning in the serve expired reply path. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
This commit is contained in:
W.C.A. Wijngaards
2026-07-22 10:07:52 +02:00
parent 87d59bfced
commit fea0ff550b
2 changed files with 42 additions and 4 deletions
+12 -3
View File
@@ -439,10 +439,15 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
* only improves security status
* and bogus is set only once, even if we rechecked the status */
if(sec > d->security) {
int wc_expanded = 0;
d->security = sec;
if(sec == sec_status_secure)
if(sec == sec_status_secure) {
uint8_t* wc = NULL;
size_t wclen = 0;
d->trust = rrset_trust_validated;
else if(sec == sec_status_bogus) {
if(val_rrset_wildcard(rrset, &wc, &wclen) && wc)
wc_expanded = 1;
} else if(sec == sec_status_bogus) {
size_t i;
/* update ttl for rrset to fixed value. */
d->ttl = ve->bogus_ttl;
@@ -455,7 +460,11 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
lock_basic_unlock(&ve->bogus_lock);
}
/* if status updated - store in cache for reuse */
rrset_update_sec_status(env->rrset_cache, rrset, *env->now);
/* For a wildcard rrset, that is secure, do not store this
* into the cache, because it changes proofs around the
* item. */
if(!wc_expanded)
rrset_update_sec_status(env->rrset_cache, rrset, *env->now);
}
return sec;
+30 -1
View File
@@ -1044,6 +1044,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
size_t wl;
int wc_cached = 0;
int wc_NSEC_ok = 0;
/* This is used to update the RRset cache, with the combination
* of the dname expansion and this wildcard, for security status. */
struct ub_packed_rrset_key* wc_rrset = NULL;
int nsec3s_seen = 0;
size_t i;
struct ub_packed_rrset_key* s;
@@ -1062,6 +1065,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return;
}
if(wc && !wc_cached && env->cfg->aggressive_nsec) {
@@ -1069,7 +1075,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
env->alloc, *env->now);
wc_cached = 1;
}
if(wc) wc_rrset = s;
}
/* validate the AUTHORITY section as well - this will generally be
@@ -1126,6 +1132,9 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return;
}
@@ -1527,6 +1536,16 @@ validate_any_response(struct module_env* env, struct val_env* ve,
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
/* Make the expanded name and wildcard RRSIG rrsets bogus */
for(i=0; i<chase_reply->an_numrrsets; i++) {
uint8_t* cwc = NULL;
size_t cwl = 0;
s = chase_reply->rrsets[i];
if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) {
((struct packed_rrset_data*)s->
entry.data)->security = sec_status_bogus;
}
}
return;
}
@@ -1564,6 +1583,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
uint8_t* wc = NULL;
size_t wl;
int wc_NSEC_ok = 0;
/* This is used to update the RRset cache, with the combination
* of the dname expansion and this wildcard, for security status. */
struct ub_packed_rrset_key* wc_rrset = NULL;
int nsec3s_seen = 0;
size_t i;
struct ub_packed_rrset_key* s;
@@ -1584,6 +1606,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return;
}
if(wc) wc_rrset = s;
/* Refuse wildcarded DNAMEs rfc 4597.
* Do not follow a wildcarded DNAME because
@@ -1595,6 +1618,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return;
}
@@ -1659,6 +1685,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
"did not exist");
chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return;
}