Fix specific overflow in qtextlayout

Fix incorrect parsing of the strict-transport-security (HSTS) header
Fix buffer over-read via a crafted reply from a DNS server
Resolves: bz#2209492
This commit is contained in:
Jan Grulich 2023-05-24 12:48:45 +02:00
parent 868fca9fc0
commit b347b50161
4 changed files with 174 additions and 1 deletions

View File

@ -0,0 +1,13 @@
--- a/src/network/access/qhsts.cpp
+++ b/src/network/access/qhsts.cpp
@@ -364,8 +364,8 @@ quoted-pair = "\" CHAR
bool QHstsHeaderParser::parse(const QList<QPair<QByteArray, QByteArray>> &headers)
{
for (const auto &h : headers) {
- // We use '==' since header name was already 'trimmed' for us:
- if (h.first == "Strict-Transport-Security") {
+ // We compare directly because header name was already 'trimmed' for us:
+ if (h.first.compare("Strict-Transport-Security", Qt::CaseInsensitive) == 0) {
header = h.second;
// RFC6797, 8.1:
//

View File

@ -0,0 +1,49 @@
diff --git a/src/gui/painting/qfixed_p.h b/src/gui/painting/qfixed_p.h
index 84659288..57d750a4 100644
--- a/src/gui/painting/qfixed_p.h
+++ b/src/gui/painting/qfixed_p.h
@@ -54,6 +54,7 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qdebug.h"
#include "QtCore/qpoint.h"
+#include <QtCore/private/qnumeric_p.h>
#include "QtCore/qsize.h"
QT_BEGIN_NAMESPACE
@@ -182,6 +183,14 @@ Q_DECL_CONSTEXPR inline bool operator<(int i, const QFixed &f) { return i * 64 <
Q_DECL_CONSTEXPR inline bool operator>(const QFixed &f, int i) { return f.value() > i * 64; }
Q_DECL_CONSTEXPR inline bool operator>(int i, const QFixed &f) { return i * 64 > f.value(); }
+inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r)
+{
+ int val;
+ bool result = add_overflow(v1.value(), v2.value(), &val);
+ r->setValue(val);
+ return result;
+}
+
#ifndef QT_NO_DEBUG_STREAM
inline QDebug &operator<<(QDebug &dbg, const QFixed &f)
{ return dbg << f.toReal(); }
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 26ac37b0..f6c69ff4 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -2150,11 +2150,14 @@ found:
eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
} else {
eng->minWidth = qMax(eng->minWidth, lbh.minw);
- eng->maxWidth += line.textWidth;
+ if (qAddOverflow(eng->maxWidth, line.textWidth, &eng->maxWidth))
+ eng->maxWidth = QFIXED_MAX;
}
- if (line.textWidth > 0 && item < eng->layoutData->items.size())
- eng->maxWidth += lbh.spaceData.textWidth;
+ if (line.textWidth > 0 && item < eng->layoutData->items.size()) {
+ if (qAddOverflow(eng->maxWidth, lbh.spaceData.textWidth, &eng->maxWidth))
+ eng->maxWidth = QFIXED_MAX;
+ }
line.textWidth += trailingSpace;
if (lbh.spaceData.length) {

View File

@ -0,0 +1,97 @@
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) {

View File

@ -57,7 +57,7 @@ BuildRequires: pkgconfig(libsystemd)
Name: qt5-qtbase
Summary: Qt5 - QtBase components
Version: 5.15.9
Release: 3%{?dist}
Release: 4%{?dist}
# See LGPL_EXCEPTIONS.txt, for exception details
@ -143,6 +143,10 @@ Source100: kde-5.15-rollup-20230411.patch.gz
Patch101: qtbase-5.15.8-fix-missing-qtsan-include.patch
Patch110: CVE-2023-32762-qtbase-5.15.patch
Patch111: CVE-2023-32763-qtbase-5.15.patch
Patch112: CVE-2023-33285-qtbase-5.15.patch
# gating related patches
Patch200: qtbase-disable-tests-not-working-in-gating.patch
@ -425,6 +429,10 @@ Qt5 libraries used for drawing widgets and OpenGL items.
%patch -P100 -p1
%patch -P101 -p1
%patch -P110 -p1
%patch -P111 -p1
%patch -P112 -p1
## gating related patches
%patch -P200 -p1 -b .disable-tests-not-working-in-gating
@ -1124,6 +1132,12 @@ fi
%changelog
* Wed May 24 2023 Jan Grulich <jgrulich@redhat.com> - 5.15.9-4
- Fix specific overflow in qtextlayout
- Fix incorrect parsing of the strict-transport-security (HSTS) header
- Fix buffer over-read via a crafted reply from a DNS server
Resolves: bz#2209492
* Wed Apr 26 2023 Jan Grulich <jgrulich@redhat.com> - 5.15.9-3
- Rebuild (elfutils#2188064)
Resolves: bz#2175727