Fix CVE-2026-10846: Query reply spoofing
Resolves: RHEL-210693
This commit is contained in:
parent
1c25a6d614
commit
edfb79b26d
184
ldns-1.8.3-CVE-2026-10846.patch
Normal file
184
ldns-1.8.3-CVE-2026-10846.patch
Normal file
@ -0,0 +1,184 @@
|
||||
diff --git a/ldns-1.8.3/error.c b/ldns-1.8.3/error.c
|
||||
index e3fd121..f046c96 100644
|
||||
--- a/ldns-1.8.3/error.c
|
||||
+++ b/ldns-1.8.3/error.c
|
||||
@@ -184,6 +184,12 @@ ldns_lookup_table ldns_error_str[] = {
|
||||
{ LDNS_STATUS_INVALID_SVCPARAM_VALUE,
|
||||
"Invalid wireformat of a value "
|
||||
"in the ServiceParam rdata field of SVCB or HTTPS RR" },
|
||||
+ { LDNS_STATUS_ID_DID_NOT_MATCH,
|
||||
+ "Response ID did not match the query ID" },
|
||||
+ { LDNS_STATUS_QDCOUNT_MUST_BE_ONE,
|
||||
+ "The query section MUST contain exactly one question" },
|
||||
+ { LDNS_STATUS_QUERY_DID_NOT_MATCH,
|
||||
+ "The question in the response did not match the query" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
diff --git a/ldns-1.8.3/ldns/error.h b/ldns-1.8.3/ldns/error.h
|
||||
index 2429b77..5754f5a 100644
|
||||
--- a/ldns-1.8.3/ldns/error.h
|
||||
+++ b/ldns-1.8.3/ldns/error.h
|
||||
@@ -141,7 +141,10 @@ enum ldns_enum_status {
|
||||
LDNS_STATUS_RESERVED_SVCPARAM_KEY,
|
||||
LDNS_STATUS_NO_SVCPARAM_VALUE_EXPECTED,
|
||||
LDNS_STATUS_SVCPARAM_KEY_MORE_THAN_ONCE,
|
||||
- LDNS_STATUS_INVALID_SVCPARAM_VALUE
|
||||
+ LDNS_STATUS_INVALID_SVCPARAM_VALUE,
|
||||
+ LDNS_STATUS_ID_DID_NOT_MATCH,
|
||||
+ LDNS_STATUS_QDCOUNT_MUST_BE_ONE,
|
||||
+ LDNS_STATUS_QUERY_DID_NOT_MATCH
|
||||
};
|
||||
typedef enum ldns_enum_status ldns_status;
|
||||
|
||||
diff --git a/ldns-1.8.3/net.c b/ldns-1.8.3/net.c
|
||||
index 57d4dff..215c0ca 100644
|
||||
--- a/ldns-1.8.3/net.c
|
||||
+++ b/ldns-1.8.3/net.c
|
||||
@@ -441,6 +441,50 @@ ldns_udp_bgsend2(ldns_buffer *qbin,
|
||||
return ldns_udp_bgsend_from(qbin, to, tolen, NULL, 0, timeout);
|
||||
}
|
||||
|
||||
+/** helper sockaddr compare function. returns -1, 0 or 1. */
|
||||
+static int
|
||||
+ldns_sockaddr_cmp(const struct sockaddr_storage* addr1, socklen_t len1,
|
||||
+ const struct sockaddr_storage* addr2, socklen_t len2)
|
||||
+{
|
||||
+ struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
|
||||
+ struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
|
||||
+ struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
|
||||
+ struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
|
||||
+ if(len1 < len2)
|
||||
+ return -1;
|
||||
+ if(len1 > len2)
|
||||
+ return 1;
|
||||
+ assert(len1 == len2);
|
||||
+ if( p1_in->sin_family < p2_in->sin_family)
|
||||
+ return -1;
|
||||
+ if( p1_in->sin_family > p2_in->sin_family)
|
||||
+ return 1;
|
||||
+ assert( p1_in->sin_family == p2_in->sin_family );
|
||||
+ /* compare ip4 */
|
||||
+ if( p1_in->sin_family == AF_INET ) {
|
||||
+ /* just order it, ntohs not required */
|
||||
+ if(p1_in->sin_port < p2_in->sin_port)
|
||||
+ return -1;
|
||||
+ if(p1_in->sin_port > p2_in->sin_port)
|
||||
+ return 1;
|
||||
+ assert(p1_in->sin_port == p2_in->sin_port);
|
||||
+ return memcmp(&p1_in->sin_addr, &p2_in->sin_addr,
|
||||
+ sizeof(p1_in->sin_addr));
|
||||
+ } else if (p1_in6->sin6_family == AF_INET6) {
|
||||
+ /* just order it, ntohs not required */
|
||||
+ if(p1_in6->sin6_port < p2_in6->sin6_port)
|
||||
+ return -1;
|
||||
+ if(p1_in6->sin6_port > p2_in6->sin6_port)
|
||||
+ return 1;
|
||||
+ assert(p1_in6->sin6_port == p2_in6->sin6_port);
|
||||
+ return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
|
||||
+ sizeof(p1_in6->sin6_addr));
|
||||
+ } else {
|
||||
+ /* eek unknown type, perform this comparison for sanity. */
|
||||
+ return memcmp(addr1, addr2, len1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static ldns_status
|
||||
ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
|
||||
const struct sockaddr_storage *to , socklen_t tolen,
|
||||
@@ -449,6 +493,8 @@ ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
|
||||
{
|
||||
int sockfd;
|
||||
uint8_t *answer;
|
||||
+ struct sockaddr_storage reply_addr;
|
||||
+ socklen_t reply_addr_len;
|
||||
|
||||
sockfd = ldns_udp_bgsend_from(qbin, to, tolen, from, fromlen, timeout);
|
||||
|
||||
@@ -467,13 +513,21 @@ ldns_udp_send_from(uint8_t **result, ldns_buffer *qbin,
|
||||
* but returns a 'NETWORK_ERROR' much like a timeout. */
|
||||
ldns_sock_nonblock(sockfd);
|
||||
|
||||
- answer = ldns_udp_read_wire(sockfd, answer_size, NULL, NULL);
|
||||
+ reply_addr_len = sizeof(reply_addr);
|
||||
+ memset(&reply_addr, 0, reply_addr_len);
|
||||
+ answer = ldns_udp_read_wire(sockfd, answer_size, &reply_addr,
|
||||
+ &reply_addr_len);
|
||||
close_socket(sockfd);
|
||||
|
||||
if (!answer) {
|
||||
/* oops */
|
||||
return LDNS_STATUS_NETWORK_ERR;
|
||||
}
|
||||
+ /* Check that the reply came from the to addr. */
|
||||
+ if(ldns_sockaddr_cmp(to, tolen, &reply_addr, reply_addr_len) != 0) {
|
||||
+ free(answer);
|
||||
+ return LDNS_STATUS_NETWORK_ERR;
|
||||
+ }
|
||||
|
||||
*result = answer;
|
||||
return LDNS_STATUS_OK;
|
||||
@@ -512,6 +566,10 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
|
||||
|
||||
assert(r != NULL);
|
||||
|
||||
+ /* The query should at least have one question */
|
||||
+ if(ldns_buffer_limit(qb) < 6 || ldns_buffer_read_u16_at(qb, 4) != 1)
|
||||
+ return LDNS_STATUS_QDCOUNT_MUST_BE_ONE;
|
||||
+
|
||||
status = LDNS_STATUS_OK;
|
||||
rtt = ldns_resolver_rtt(r);
|
||||
ns_array = ldns_resolver_nameservers(r);
|
||||
@@ -599,6 +657,16 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
|
||||
ldns_resolver_set_nameserver_rtt(r, i, LDNS_RESOLV_RTT_INF);
|
||||
status = send_status;
|
||||
}
|
||||
+ if(reply_bytes && ldns_buffer_limit(qb) >= 2) {
|
||||
+ uint16_t txid = ldns_buffer_read_u16_at(qb, 0);
|
||||
+ if(reply_size < 2 ||
|
||||
+ ldns_read_uint16(reply_bytes) != txid) {
|
||||
+ status = LDNS_STATUS_ID_DID_NOT_MATCH;
|
||||
+ LDNS_FREE(reply_bytes);
|
||||
+ reply_bytes = NULL;
|
||||
+ reply_size = 0;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* obey the fail directive */
|
||||
if (!reply_bytes) {
|
||||
@@ -608,7 +676,7 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
|
||||
LDNS_FREE(src);
|
||||
}
|
||||
LDNS_FREE(ns);
|
||||
- return LDNS_STATUS_ERR;
|
||||
+ return status ? status : LDNS_STATUS_ERR;
|
||||
} else {
|
||||
LDNS_FREE(ns);
|
||||
continue;
|
||||
@@ -670,6 +738,26 @@ ldns_send_buffer(ldns_pkt **result, ldns_resolver *r, ldns_buffer *qb, ldns_rdf
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
LDNS_FREE(reply_bytes);
|
||||
+ if (reply) {
|
||||
+ ldns_pkt *query = NULL;
|
||||
+
|
||||
+ if(ldns_pkt_qdcount(reply) != 1) {
|
||||
+ status = LDNS_STATUS_QDCOUNT_MUST_BE_ONE;
|
||||
+ ldns_pkt_free(reply);
|
||||
+ reply = NULL;
|
||||
+
|
||||
+ } else if(ldns_wire2pkt(&query
|
||||
+ , ldns_buffer_begin(qb)
|
||||
+ , ldns_buffer_position(qb)) != LDNS_STATUS_OK
|
||||
+ || ldns_pkt_qdcount(query) != 1
|
||||
+ || ldns_rr_compare(ldns_rr_list_rr(ldns_pkt_question(query),0)
|
||||
+ ,ldns_rr_list_rr(ldns_pkt_question(reply),0))){
|
||||
+ status = LDNS_STATUS_QUERY_DID_NOT_MATCH;
|
||||
+ ldns_pkt_free(reply);
|
||||
+ reply = NULL;
|
||||
+ }
|
||||
+ ldns_pkt_free(query);
|
||||
+ }
|
||||
if (result) {
|
||||
*result = reply;
|
||||
}
|
||||
@ -37,7 +37,7 @@
|
||||
Summary: Low-level DNS(SEC) library with API
|
||||
Name: ldns
|
||||
Version: 1.8.3
|
||||
Release: 18%{?dist}
|
||||
Release: 19%{?dist}
|
||||
|
||||
License: BSD-3-Clause
|
||||
Url: https://www.nlnetlabs.nl/%{name}/
|
||||
@ -60,6 +60,8 @@ Patch6: ldns-1.8-openssl-engine.patch
|
||||
# https://github.com/NLnetLabs/ldns/pull/256
|
||||
# https://github.com/NLnetLabs/ldns/pull/257
|
||||
Patch7: ldns-1.8.3-swig-4.3.patch
|
||||
# https://nlnetlabs.nl/downloads/ldns/patch_cve_2026-10846.diff
|
||||
Patch8: ldns-1.8.3-CVE-2026-10846.patch
|
||||
|
||||
BuildRequires: libtool
|
||||
BuildRequires: autoconf
|
||||
@ -367,6 +369,10 @@ rm -rf doc/man
|
||||
%doc doc
|
||||
|
||||
%changelog
|
||||
* Tue Aug 04 2026 Fedor Vorobev <fvorobev@redhat.com> - 1.8.3-19
|
||||
- Fix CVE-2026-10846: Off-path poisoning attacks due to insufficient
|
||||
query-response matching (RHEL-210693)
|
||||
|
||||
* Tue Oct 29 2024 Jitka Plesnikova <jplesnik@redhat.com> - 1.8.3-18
|
||||
- Fix for SWIG 4.3.0
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user