qt5-qtbase/SOURCES/CVE-2023-33285-qtbase-5.15....

98 lines
3.9 KiB
Diff

From 2103f2487f709dd9546c503820d9ad509e9a63b3 Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
Date: Thu, 11 May 2023 21:40:15 -0700
Subject: QDnsLookup/Unix: make sure we don't overflow the buffer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The DNS Records are variable length and encode their size in 16 bits
before the Record Data (RDATA). Ensure that both the RDATA and the
Record header fields before it fall inside the buffer we have.
Additionally reject any replies containing more than one query records.
[ChangeLog][QtNetwork][QDnsLookup] Fixed a bug that could cause a buffer
overflow in Unix systems while parsing corrupt, malicious, or truncated
replies.
Pick-to: 5.15 6.2 6.5 6.5.1
Change-Id: I3e3bfef633af4130a03afffd175e4b9547654b95
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Jani Heikkinen <jani.heikkinen@qt.io>
(cherry picked from commit 7dba2c87619d558a61a30eb30cc1d9c3fe6df94c)
* asturmlechner 2023-05-18: Resolve conflict with dev branch commit
68b625901f9eb7c34e3d7aa302e1c0a454d3190b
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 12b40fc35d..99e999d436 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -227,7 +227,6 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
// responseLength in case of error, we still can extract the
// exact error code from the response.
HEADER *header = (HEADER*)response;
- const int answerCount = ntohs(header->ancount);
switch (header->rcode) {
case NOERROR:
break;
@@ -260,18 +259,31 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
return;
}
- // Skip the query host, type (2 bytes) and class (2 bytes).
char host[PACKETSZ], answer[PACKETSZ];
unsigned char *p = response + sizeof(HEADER);
- int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
- if (status < 0) {
+ int status;
+
+ if (ntohs(header->qdcount) == 1) {
+ // Skip the query host, type (2 bytes) and class (2 bytes).
+ status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
+ if (status < 0) {
+ reply->error = QDnsLookup::InvalidReplyError;
+ reply->errorString = tr("Could not expand domain name");
+ return;
+ }
+ if ((p - response) + status + 4 >= responseLength)
+ header->qdcount = 0xffff; // invalid reply below
+ else
+ p += status + 4;
+ }
+ if (ntohs(header->qdcount) > 1) {
reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Could not expand domain name");
+ reply->errorString = tr("Invalid reply received");
return;
}
- p += status + 4;
// Extract results.
+ const int answerCount = ntohs(header->ancount);
int answerIndex = 0;
while ((p < response + responseLength) && (answerIndex < answerCount)) {
status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
@@ -283,6 +295,11 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
const QString name = QUrl::fromAce(host);
p += status;
+
+ if ((p - response) + 10 > responseLength) {
+ // probably just a truncated reply, return what we have
+ return;
+ }
const quint16 type = (p[0] << 8) | p[1];
p += 2; // RR type
p += 2; // RR class
@@ -290,6 +307,8 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
p += 4;
const quint16 size = (p[0] << 8) | p[1];
p += 2;
+ if ((p - response) + size > responseLength)
+ return; // truncated
if (type == QDnsLookup::A) {
if (size != 4) {