[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1070154: marked as done (bullseye-pu: qtbase-opensource-src/5.15.2+dfsg-9+deb11u1)



Your message dated Sat, 29 Jun 2024 10:47:47 +0000
with message-id <E1sNVcR-002brz-Ib@coccia.debian.org>
and subject line Released with 11.10
has caused the Debian Bug report #1070154,
regarding bullseye-pu: qtbase-opensource-src/5.15.2+dfsg-9+deb11u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1070154: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1070154
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu


The attached debdiff for qtbase-opensource-src fixes several CVEs in Bullseye. All CVEs are marked as no-dsa by the security team.

  Thorsten
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/changelog qtbase-opensource-src-5.15.2+dfsg/debian/changelog
--- qtbase-opensource-src-5.15.2+dfsg/debian/changelog	2021-07-02 17:58:04.000000000 +0200
+++ qtbase-opensource-src-5.15.2+dfsg/debian/changelog	2024-04-28 22:48:02.000000000 +0200
@@ -1,3 +1,33 @@
+qtbase-opensource-src (5.15.2+dfsg-9+deb11u1) bullseye; urgency=medium
+
+  * Non-maintainer upload by the LTS Team.
+  * CVE-2024-25580 (Closes: #1064053)
+    fix buffer overflow due to crafted KTX image file
+  * CVE-2023-32763 (Closes: #1036702)
+    fix QTextLayout buffer overflow due to crafted SVG file
+  * CVE-2022-25255
+    prevent QProcess from execution of a binary from the current working
+    directory when not found in the PATH
+  * CVE-2023-24607 (Closes: #1031872)
+    fix denial of service via a crafted string when the SQL ODBC driver
+    plugin is used
+  * fix regression caused by patch for CVE-2023-24607
+  * CVE-2023-32762
+    prevent incorrect parsing of the strict-transport-security (HSTS) header
+  * CVE-2023-51714 (Closes: #1060694)
+    fix incorrect HPack integer overflow check.
+  * CVE-2023-38197 (Closes: #1041105)
+    fix infinite loop in recursive entity expansion
+  * CVE-2023-37369 (Closes: #1059302)
+    fix crash of application in QXmlStreamReader due to crafted XML string
+  * CVE-2023-34410 (Closes: #1037210)
+    fix checking during TLS whether root of the chain really is a
+    configured CA certificate
+  * CVE-2023-33285 (Closes: #1036848)
+    fix buffer overflow in QDnsLookup
+
+ -- Thorsten Alteholz <debian@alteholz.de>  Sun, 28 Apr 2024 22:48:02 +0200
+
 qtbase-opensource-src (5.15.2+dfsg-9) unstable; urgency=medium
 
   * Revert adding fix-misplacement-of-placeholder-text-in-QLineEdit.diff.
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2022-25255.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2022-25255.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2022-25255.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2022-25255.diff	2024-03-05 13:22:01.000000000 +0100
@@ -0,0 +1,96 @@
+Description: QProcess: ensure we don't accidentally execute something from CWD
+ Unless "." (or the empty string) is in $PATH, we're not supposed to find
+ executables in the current directory. This is how the Unix shells behave
+ and we match their behavior. It's also the behavior Qt had prior to 5.9
+ (commit 28666d167aa8e602c0bea25ebc4d51b55005db13). On Windows, searching
+ the current directory is the norm, so we keep that behavior.
+ .
+ This commit does not add an explicit check for an empty return from
+ QStandardPaths::findExecutable(). Instead, we allow that empty string to
+ go all the way to execve(2), which will fail with ENOENT. We could catch
+ it early, before fork(2), but why add code for the error case?
+ .
+ See https://kde.org/info/security/advisory-20220131-1.txt
+Origin: upstream, https://download.qt.io/official_releases/qt/5.15/CVE-2022-25255-qprocess5-15.diff
+Last-Update: 2022-02-21
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/io/qprocess_unix.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/io/qprocess_unix.cpp	2024-03-05 13:21:06.432881985 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/io/qprocess_unix.cpp	2024-03-05 13:21:06.428881981 +0100
+@@ -1,7 +1,7 @@
+ /****************************************************************************
+ **
+ ** Copyright (C) 2016 The Qt Company Ltd.
+-** Copyright (C) 2016 Intel Corporation.
++** Copyright (C) 2022 Intel Corporation.
+ ** Contact: https://www.qt.io/licensing/
+ **
+ ** This file is part of the QtCore module of the Qt Toolkit.
+@@ -422,14 +422,15 @@
+     // Add the program name to the argument list.
+     argv[0] = nullptr;
+     if (!program.contains(QLatin1Char('/'))) {
++        // findExecutable() returns its argument if it's an absolute path,
++        // otherwise it searches $PATH; returns empty if not found (we handle
++        // that case much later)
+         const QString &exeFilePath = QStandardPaths::findExecutable(program);
+-        if (!exeFilePath.isEmpty()) {
+-            const QByteArray &tmp = QFile::encodeName(exeFilePath);
+-            argv[0] = ::strdup(tmp.constData());
+-        }
+-    }
+-    if (!argv[0])
++        const QByteArray &tmp = QFile::encodeName(exeFilePath);
++        argv[0] = ::strdup(tmp.constData());
++    } else {
+         argv[0] = ::strdup(encodedProgramName.constData());
++    }
+ 
+     // Add every argument to the list
+     for (int i = 0; i < arguments.count(); ++i)
+@@ -983,15 +984,16 @@
+                 envp = _q_dupEnvironment(environment.d.constData()->vars, &envc);
+             }
+ 
+-            QByteArray tmp;
+             if (!program.contains(QLatin1Char('/'))) {
++                // findExecutable() returns its argument if it's an absolute path,
++                // otherwise it searches $PATH; returns empty if not found (we handle
++                // that case much later)
+                 const QString &exeFilePath = QStandardPaths::findExecutable(program);
+-                if (!exeFilePath.isEmpty())
+-                    tmp = QFile::encodeName(exeFilePath);
++                const QByteArray &tmp = QFile::encodeName(exeFilePath);
++                argv[0] = ::strdup(tmp.constData());
++            } else {
++                argv[0] = ::strdup(QFile::encodeName(program));
+             }
+-            if (tmp.isEmpty())
+-                tmp = QFile::encodeName(program);
+-            argv[0] = tmp.data();
+ 
+             if (envp)
+                 qt_safe_execve(argv[0], argv, envp);
+Index: qtbase-opensource-src-5.15.2+dfsg/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp	2024-03-05 13:21:06.432881985 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp	2024-03-05 13:21:57.744931492 +0100
+@@ -1449,7 +1449,7 @@
+ {
+ #if QT_CONFIG(process)
+     QProcess testProcess;
+-    testProcess.start("desktopsettingsaware_helper");
++    testProcess.start("./desktopsettingsaware_helper");
+     QVERIFY2(testProcess.waitForStarted(),
+              qPrintable(QString::fromLatin1("Cannot start 'desktopsettingsaware_helper': %1").arg(testProcess.errorString())));
+     QVERIFY(testProcess.waitForFinished(10000));
+@@ -2365,7 +2365,7 @@
+ #if QT_CONFIG(process)
+     QProcess testProcess;
+     QStringList arguments;
+-    testProcess.start("modal_helper", arguments);
++    testProcess.start("./modal_helper", arguments);
+     QVERIFY2(testProcess.waitForStarted(),
+              qPrintable(QString::fromLatin1("Cannot start 'modal_helper': %1").arg(testProcess.errorString())));
+     QVERIFY(testProcess.waitForFinished(20000));
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-24607.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-24607.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-24607.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-24607.diff	2024-03-05 13:24:50.000000000 +0100
@@ -0,0 +1,332 @@
+Description: Fix denial-of-service in Qt SQL ODBC driver plugin
+Origin: upstream, https://download.qt.io/official_releases/qt/5.15/CVE-2023-24607-qtbase-5.15.diff
+Last-Update: 2023-02-26
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-03-05 13:24:44.661090169 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-03-05 13:24:44.657090165 +0100
+@@ -92,23 +92,39 @@
+     return result;
+ }
+ 
++template <size_t SizeOfChar = sizeof(SQLTCHAR)>
++void toSQLTCHARImpl(QVarLengthArray<SQLTCHAR> &result, const QString &input); // primary template undefined
++
++template <typename Container>
++void do_append(QVarLengthArray<SQLTCHAR> &result, const Container &c)
++{
++    result.append(reinterpret_cast<const SQLTCHAR *>(c.data()), c.size());
++}
++
++template <>
++void toSQLTCHARImpl<1>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
++{
++    const auto u8 = input.toUtf8();
++    do_append(result, u8);
++}
++
++template <>
++void toSQLTCHARImpl<2>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
++{
++    do_append(result, input);
++}
++
++template <>
++void toSQLTCHARImpl<4>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
++{
++    const auto u32 = input.toUcs4();
++    do_append(result, u32);
++}
++
+ inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
+ {
+     QVarLengthArray<SQLTCHAR> result;
+-    result.resize(input.size());
+-    switch(sizeof(SQLTCHAR)) {
+-        case 1:
+-            memcpy(result.data(), input.toUtf8().data(), input.size());
+-            break;
+-        case 2:
+-            memcpy(result.data(), input.unicode(), input.size() * 2);
+-            break;
+-        case 4:
+-            memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
+-            break;
+-        default:
+-            qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
+-    }
++    toSQLTCHARImpl(result, input);
+     result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
+     return result;
+ }
+@@ -763,6 +779,14 @@
+     return quote;
+ }
+ 
++static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, const QString &val)
++{
++    auto encoded = toSQLTCHAR(val);
++    return SQLSetConnectAttr(handle, attr,
++                             encoded.data(),
++                             SQLINTEGER(encoded.size() * sizeof(SQLTCHAR))); // size in bytes
++}
++
+ 
+ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
+ {
+@@ -798,10 +822,7 @@
+             v = val.toUInt();
+             r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
+         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
+-            val.utf16(); // 0 terminate
+-            r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
+-                                    toSQLTCHAR(val).data(),
+-                                    val.length()*sizeof(SQLTCHAR));
++            r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
+         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
+             if (val.toUpper() == QLatin1String("SQL_TRUE")) {
+                 v = SQL_TRUE;
+@@ -816,10 +837,7 @@
+             v = val.toUInt();
+             r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
+         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
+-            val.utf16(); // 0 terminate
+-            r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
+-                                    toSQLTCHAR(val).data(),
+-                                    val.length()*sizeof(SQLTCHAR));
++            r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
+         } else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
+             if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
+                 v = SQL_OPT_TRACE_OFF;
+@@ -1022,9 +1040,12 @@
+         return false;
+     }
+ 
+-    r = SQLExecDirect(d->hStmt,
+-                       toSQLTCHAR(query).data(),
+-                       (SQLINTEGER) query.length());
++    {
++        auto encoded = toSQLTCHAR(query);
++        r = SQLExecDirect(d->hStmt,
++                          encoded.data(),
++                          SQLINTEGER(encoded.size()));
++    }
+     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
+         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+                      "Unable to execute statement"), QSqlError::StatementError, d));
+@@ -1370,9 +1391,12 @@
+         return false;
+     }
+ 
+-    r = SQLPrepare(d->hStmt,
+-                    toSQLTCHAR(query).data(),
+-                    (SQLINTEGER) query.length());
++    {
++        auto encoded = toSQLTCHAR(query);
++        r = SQLPrepare(d->hStmt,
++                       encoded.data(),
++                       SQLINTEGER(encoded.size()));
++    }
+ 
+     if (r != SQL_SUCCESS) {
+         setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
+@@ -1400,7 +1424,7 @@
+         SQLCloseCursor(d->hStmt);
+ 
+     QVector<QVariant>& values = boundValues();
+-    QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
++    QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // targets for SQLBindParameter()
+     QVarLengthArray<SQLLEN, 32> indicators(values.count());
+     memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
+ 
+@@ -1579,35 +1603,36 @@
+             case QVariant::String:
+                 if (d->unicode) {
+                     QByteArray &ba = tmpStorage[i];
+-                    QString str = val.toString();
++                    {
++                        const auto encoded = toSQLTCHAR(val.toString());
++                        ba = QByteArray(reinterpret_cast<const char *>(encoded.data()),
++                                        encoded.size() * sizeof(SQLTCHAR));
++                    }
++
+                     if (*ind != SQL_NULL_DATA)
+-                        *ind = str.length() * sizeof(SQLTCHAR);
+-                    int strSize = str.length() * sizeof(SQLTCHAR);
++                        *ind = ba.size();
+ 
+                     if (bindValueType(i) & QSql::Out) {
+-                        const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
+-                        ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
+                         r = SQLBindParameter(d->hStmt,
+                                             i + 1,
+                                             qParamType[bindValueType(i) & QSql::InOut],
+                                             SQL_C_TCHAR,
+-                                            strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
++                                            ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+                                             0, // god knows... don't change this!
+                                             0,
+-                                            ba.data(),
++                                            const_cast<char *>(ba.constData()), // don't detach
+                                             ba.size(),
+                                             ind);
+                         break;
+                     }
+-                    ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
+                     r = SQLBindParameter(d->hStmt,
+                                           i + 1,
+                                           qParamType[bindValueType(i) & QSql::InOut],
+                                           SQL_C_TCHAR,
+-                                          strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
+-                                          strSize,
++                                          ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
++                                          ba.size(),
+                                           0,
+-                                          const_cast<char *>(ba.constData()),
++                                          const_cast<char *>(ba.constData()), // don't detach
+                                           ba.size(),
+                                           ind);
+                     break;
+@@ -1715,10 +1740,11 @@
+             case QVariant::String:
+                 if (d->unicode) {
+                     if (bindValueType(i) & QSql::Out) {
+-                        const QByteArray &first = tmpStorage.at(i);
+-                        QVarLengthArray<SQLTCHAR> array;
+-                        array.append((const SQLTCHAR *)first.constData(), first.size());
+-                        values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
++                        const QByteArray &bytes = tmpStorage.at(i);
++                        const auto strSize = bytes.size() / int(sizeof(SQLTCHAR));
++                        QVarLengthArray<SQLTCHAR> string(strSize);
++                        memcpy(string.data(), bytes.data(), strSize * sizeof(SQLTCHAR));
++                        values[i] = fromSQLTCHAR(string);
+                     }
+                     break;
+                 }
+@@ -1965,14 +1991,16 @@
+     SQLSMALLINT cb;
+     QVarLengthArray<SQLTCHAR> connOut(1024);
+     memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
+-    r = SQLDriverConnect(d->hDbc,
+-                          NULL,
+-                          toSQLTCHAR(connQStr).data(),
+-                          (SQLSMALLINT)connQStr.length(),
+-                          connOut.data(),
+-                          1024,
+-                          &cb,
+-                          /*SQL_DRIVER_NOPROMPT*/0);
++    {
++        auto encoded = toSQLTCHAR(connQStr);
++        r = SQLDriverConnect(d->hDbc,
++                             nullptr,
++                             encoded.data(), SQLSMALLINT(encoded.size()),
++                             connOut.data(),
++                             1024,
++                             &cb,
++                             /*SQL_DRIVER_NOPROMPT*/0);
++    }
+ 
+     if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+         setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
+@@ -2351,17 +2379,15 @@
+     if (tableType.isEmpty())
+         return tl;
+ 
+-    QString joinedTableTypeString = tableType.join(QLatin1Char(','));
++    {
++        auto joinedTableTypeString = toSQLTCHAR(tableType.join(u','));
+ 
+-    r = SQLTables(hStmt,
+-                   NULL,
+-                   0,
+-                   NULL,
+-                   0,
+-                   NULL,
+-                   0,
+-                   toSQLTCHAR(joinedTableTypeString).data(),
+-                   joinedTableTypeString.length() /* characters, not bytes */);
++        r = SQLTables(hStmt,
++                      nullptr, 0,
++                      nullptr, 0,
++                      nullptr, 0,
++                      joinedTableTypeString.data(), joinedTableTypeString.size());
++    }
+ 
+     if (r != SQL_SUCCESS)
+         qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
+@@ -2435,28 +2461,30 @@
+                         SQL_ATTR_CURSOR_TYPE,
+                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+                         SQL_IS_UINTEGER);
+-    r = SQLPrimaryKeys(hStmt,
+-                        catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+-                        catalog.length(),
+-                        schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+-                        schema.length(),
+-                        toSQLTCHAR(table).data(),
+-                        table.length() /* in characters, not in bytes */);
++    {
++        auto c = toSQLTCHAR(catalog);
++        auto s = toSQLTCHAR(schema);
++        auto t = toSQLTCHAR(table);
++        r = SQLPrimaryKeys(hStmt,
++                           catalog.isEmpty() ? nullptr : c.data(), c.size(),
++                           schema.isEmpty()  ? nullptr : s.data(), s.size(),
++                           t.data(), t.size());
++    }
+ 
+     // if the SQLPrimaryKeys() call does not succeed (e.g the driver
+     // does not support it) - try an alternative method to get hold of
+     // the primary index (e.g MS Access and FoxPro)
+     if (r != SQL_SUCCESS) {
+-            r = SQLSpecialColumns(hStmt,
+-                        SQL_BEST_ROWID,
+-                        catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+-                        catalog.length(),
+-                        schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+-                        schema.length(),
+-                        toSQLTCHAR(table).data(),
+-                        table.length(),
+-                        SQL_SCOPE_CURROW,
+-                        SQL_NULLABLE);
++        auto c = toSQLTCHAR(catalog);
++        auto s = toSQLTCHAR(schema);
++        auto t = toSQLTCHAR(table);
++        r = SQLSpecialColumns(hStmt,
++                              SQL_BEST_ROWID,
++                              catalog.isEmpty() ? nullptr : c.data(), c.size(),
++                              schema.isEmpty()  ? nullptr : s.data(), s.size(),
++                              t.data(), t.size(),
++                              SQL_SCOPE_CURROW,
++                              SQL_NULLABLE);
+ 
+             if (r != SQL_SUCCESS) {
+                 qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
+@@ -2537,15 +2565,17 @@
+                         SQL_ATTR_CURSOR_TYPE,
+                         (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+                         SQL_IS_UINTEGER);
+-    r =  SQLColumns(hStmt,
+-                     catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
+-                     catalog.length(),
+-                     schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
+-                     schema.length(),
+-                     toSQLTCHAR(table).data(),
+-                     table.length(),
+-                     NULL,
+-                     0);
++    {
++        auto c = toSQLTCHAR(catalog);
++        auto s = toSQLTCHAR(schema);
++        auto t = toSQLTCHAR(table);
++        r =  SQLColumns(hStmt,
++                        catalog.isEmpty() ? nullptr : c.data(), c.size(),
++                        schema.isEmpty()  ? nullptr : s.data(), s.size(),
++                        t.data(), t.size(),
++                        nullptr,
++                        0);
++    }
+     if (r != SQL_SUCCESS)
+         qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
+ 
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32762.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32762.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32762.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32762.diff	2024-03-05 13:48:39.000000000 +0100
@@ -0,0 +1,47 @@
+commit 1b736a815be0222f4b24289cf17575fc15707305
+Author: Mårten Nordheim <marten.nordheim@qt.io>
+Date:   Fri May 5 11:07:26 2023 +0200
+
+    Hsts: match header names case insensitively
+    
+    Header field names are always considered to be case-insensitive.
+    
+    Pick-to: 6.5 6.5.1 6.2 5.15
+    Fixes: QTBUG-113392
+    Change-Id: Ifb4def4bb7f2ac070416cdc76581a769f1e52b43
+    Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
+    Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
+    Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/network/access/qhsts.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/network/access/qhsts.cpp	2024-03-05 13:48:37.054356050 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/src/network/access/qhsts.cpp	2024-03-05 13:48:37.054356050 +0100
+@@ -364,8 +364,8 @@
+ 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:
+             //
+Index: qtbase-opensource-src-5.15.2+dfsg/tests/auto/network/access/hsts/tst_qhsts.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/tests/auto/network/access/hsts/tst_qhsts.cpp	2024-03-05 13:48:37.054356050 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/tests/auto/network/access/hsts/tst_qhsts.cpp	2024-03-05 13:48:37.054356050 +0100
+@@ -242,6 +242,12 @@
+     QVERIFY(parser.includeSubDomains());
+ 
+     list.pop_back();
++    list << Header("strict-transport-security", "includeSubDomains;max-age=1000");
++    QVERIFY(parser.parse(list));
++    QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc());
++    QVERIFY(parser.includeSubDomains());
++
++    list.pop_back();
+     // Invalid (includeSubDomains twice):
+     list << Header("Strict-Transport-Security", "max-age = 1000 ; includeSubDomains;includeSubDomains");
+     QVERIFY(!parser.parse(list));
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32763.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32763.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32763.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-32763.diff	2024-03-05 12:57:24.000000000 +0100
@@ -0,0 +1,54 @@
+Description: fix buffer overflow in Qt SVG
+ Adds qAddOverflow and qMulOverflow definitions to QFixed.
+Origin: upstream, https://download.qt.io/official_releases/qt/5.15/CVE-2023-32763-qtbase-5.15.diff
+Last-Update: 2023-05-22
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/gui/painting/qfixed_p.h
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/gui/painting/qfixed_p.h	2024-03-05 12:57:22.447571651 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/src/gui/painting/qfixed_p.h	2024-03-05 12:57:22.443571651 +0100
+@@ -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>(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(); }
+Index: qtbase-opensource-src-5.15.2+dfsg/src/gui/text/qtextlayout.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/gui/text/qtextlayout.cpp	2024-03-05 12:57:22.447571651 +0100
++++ qtbase-opensource-src-5.15.2+dfsg/src/gui/text/qtextlayout.cpp	2024-03-05 12:57:22.443571651 +0100
+@@ -2138,11 +2138,14 @@
+         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) {
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-33285.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-33285.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-33285.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-33285.diff	2023-05-25 12:45:05.000000000 +0200
@@ -0,0 +1,77 @@
+Description: QDnsLookup/Unix: make sure we don't overflow the buffer
+ 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.
+Origin: upstream, https://code.qt.io/cgit/qt/qtbase.git/commit/?id=7dba2c87619d558a
+Last-Update: 2023-05-25
+
+--- a/src/network/kernel/qdnslookup_unix.cpp
++++ b/src/network/kernel/qdnslookup_unix.cpp
+@@ -227,7 +227,6 @@ void QDnsLookupRunnable::query(const int
+     // 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
+         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
+         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
+         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) {
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-34410.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-34410.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-34410.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-34410.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,56 @@
+Index: qtbase-opensource-src-5.15.2+dfsg/src/network/ssl/qsslsocket_schannel.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/network/ssl/qsslsocket_schannel.cpp	2024-04-25 14:19:26.756392964 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/network/ssl/qsslsocket_schannel.cpp	2024-04-25 14:19:26.752392971 +0200
+@@ -1877,6 +1877,28 @@
+     if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
+         verifyDepth = DWORD(configuration.peerVerifyDepth);
+ 
++    const auto &caCertificates = q->sslConfiguration().caCertificates();
++
++    if (!rootCertOnDemandLoadingAllowed()
++            && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
++            && (q->peerVerifyMode() == QSslSocket::VerifyPeer
++                    || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
++        // When verifying a peer Windows "helpfully" builds a chain that
++        // may include roots from the system store. But we don't want that if
++        // the user has set their own CA certificates.
++        // Since Windows claims this is not a partial chain the root is included
++        // and we have to check that it is one of our configured CAs.
++        CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
++        QSslCertificate certificate = getCertificateFromChainElement(element);
++        if (!caCertificates.contains(certificate)) {
++            auto error = QSslError(QSslError::CertificateUntrusted, certificate);
++            sslErrors += error;
++            emit q->peerVerifyError(error);
++            if (q->state() != QAbstractSocket::ConnectedState)
++                return false;
++        }
++    }
++
+     for (DWORD i = 0; i < verifyDepth; i++) {
+         CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
+         QSslCertificate certificate = getCertificateFromChainElement(element);
+Index: qtbase-opensource-src-5.15.2+dfsg/src/network/ssl/qsslsocket.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/network/ssl/qsslsocket.cpp	2024-04-25 14:19:26.756392964 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/network/ssl/qsslsocket.cpp	2024-04-25 14:19:26.752392971 +0200
+@@ -2221,6 +2221,10 @@
+     , flushTriggered(false)
+ {
+     QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
++    // If the global configuration doesn't allow root certificates to be loaded
++    // on demand then we have to disable it for this socket as well.
++    if (!configuration.allowRootCertOnDemandLoading)
++        allowRootCertOnDemandLoading = false;
+ }
+ 
+ /*!
+@@ -2470,6 +2474,7 @@
+     ptr->sessionProtocol = global->sessionProtocol;
+     ptr->ciphers = global->ciphers;
+     ptr->caCertificates = global->caCertificates;
++    ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
+     ptr->protocol = global->protocol;
+     ptr->peerVerifyMode = global->peerVerifyMode;
+     ptr->peerVerifyDepth = global->peerVerifyDepth;
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-37369.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-37369.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-37369.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-37369.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,202 @@
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/serialization/qxmlstream.cpp	2024-04-26 13:23:27.490939469 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.cpp	2024-04-26 13:24:24.074800856 +0200
+@@ -1302,11 +1302,19 @@
+     return n;
+ }
+ 
+-inline int QXmlStreamReaderPrivate::fastScanName(int *prefix)
++// Fast scan an XML attribute name (e.g. "xml:lang").
++inline QXmlStreamReaderPrivate::FastScanNameResult
++QXmlStreamReaderPrivate::fastScanName(Value *val)
+ {
+     int n = 0;
+     uint c;
+     while ((c = getChar()) != StreamEOF) {
++        if (n >= 4096) {
++            // This is too long to be a sensible name, and
++            // can exhaust memory, or the range of decltype(*prefix)
++            raiseNamePrefixTooLongError();
++            return {};
++        }
+         switch (c) {
+         case '\n':
+         case ' ':
+@@ -1334,23 +1342,23 @@
+         case '+':
+         case '*':
+             putChar(c);
+-            if (prefix && *prefix == n+1) {
+-                *prefix = 0;
++            if (val && val->prefix == n + 1) {
++                val->prefix = 0;
+                 putChar(':');
+                 --n;
+             }
+-            return n;
++            return FastScanNameResult(n);
+         case ':':
+-            if (prefix) {
+-                if (*prefix == 0) {
+-                    *prefix = n+2;
++            if (val) {
++                if (val->prefix == 0) {
++                    val->prefix = n + 2;
+                 } else { // only one colon allowed according to the namespace spec.
+                     putChar(c);
+-                    return n;
++                    return FastScanNameResult(n);
+                 }
+             } else {
+                 putChar(c);
+-                return n;
++                return FastScanNameResult(n);
+             }
+             Q_FALLTHROUGH();
+         default:
+@@ -1359,12 +1367,12 @@
+         }
+     }
+ 
+-    if (prefix)
+-        *prefix = 0;
++    if (val)
++        val->prefix = 0;
+     int pos = textBuffer.size() - n;
+     putString(textBuffer, pos);
+     textBuffer.resize(pos);
+-    return 0;
++    return FastScanNameResult(0);
+ }
+ 
+ enum NameChar { NameBeginning, NameNotBeginning, NotName };
+@@ -1873,6 +1881,14 @@
+     raiseError(QXmlStreamReader::NotWellFormedError, message);
+ }
+ 
++void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
++{
++    // TODO: add a ImplementationLimitsExceededError and use it instead
++    raiseError(QXmlStreamReader::NotWellFormedError,
++               QXmlStream::tr("Length of XML attribute name exceeds implemnetation limits (4KiB "
++                              "characters)."));
++}
++
+ void QXmlStreamReaderPrivate::parseError()
+ {
+ 
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.g
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/serialization/qxmlstream.g	2024-04-26 13:23:27.490939469 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.g	2024-04-26 13:23:27.486939479 +0200
+@@ -516,7 +516,16 @@
+     int fastScanLiteralContent();
+     int fastScanSpace();
+     int fastScanContentCharList();
+-    int fastScanName(int *prefix = nullptr);
++
++    struct FastScanNameResult {
++        FastScanNameResult() : ok(false) {}
++        explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
++        operator bool() { return ok; }
++        int operator*() { Q_ASSERT(ok); return addToLen; }
++        int addToLen;
++        bool ok;
++    };
++    FastScanNameResult fastScanName(Value *val = nullptr);
+     inline int fastScanNMTOKEN();
+ 
+ 
+@@ -525,6 +534,7 @@
+ 
+     void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
+     void raiseWellFormedError(const QString &message);
++    void raiseNamePrefixTooLongError();
+ 
+     QXmlStreamEntityResolver *entityResolver;
+ 
+@@ -1809,7 +1819,12 @@
+ qname ::= LETTER;
+ /.
+         case $rule_number: {
+-            sym(1).len += fastScanName(&sym(1).prefix);
++            Value &val = sym(1);
++            if (auto res = fastScanName(&val))
++                val.len += *res;
++            else
++                return false;
++
+             if (atEnd) {
+                 resume($rule_number);
+                 return false;
+@@ -1820,7 +1835,11 @@
+ name ::= LETTER;
+ /.
+         case $rule_number:
+-            sym(1).len += fastScanName();
++            if (auto res = fastScanName())
++                sym(1).len += *res;
++            else
++                return false;
++
+             if (atEnd) {
+                 resume($rule_number);
+                 return false;
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream_p.h
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/serialization/qxmlstream_p.h	2024-04-26 13:23:27.490939469 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream_p.h	2024-04-26 13:23:27.486939479 +0200
+@@ -1005,7 +1005,16 @@
+     int fastScanLiteralContent();
+     int fastScanSpace();
+     int fastScanContentCharList();
+-    int fastScanName(int *prefix = nullptr);
++
++    struct FastScanNameResult {
++        FastScanNameResult() : ok(false) {}
++        explicit FastScanNameResult(int len) : addToLen(len), ok(true) { }
++        operator bool() { return ok; }
++        int operator*() { Q_ASSERT(ok); return addToLen; }
++        int addToLen;
++        bool ok;
++    };
++    FastScanNameResult fastScanName(Value *val = nullptr);
+     inline int fastScanNMTOKEN();
+ 
+ 
+@@ -1014,6 +1023,7 @@
+ 
+     void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
+     void raiseWellFormedError(const QString &message);
++    void raiseNamePrefixTooLongError();
+ 
+     QXmlStreamEntityResolver *entityResolver;
+ 
+@@ -1937,7 +1947,12 @@
+         break;
+ 
+         case 262: {
+-            sym(1).len += fastScanName(&sym(1).prefix);
++            Value &val = sym(1);
++            if (auto res = fastScanName(&val))
++                val.len += *res;
++            else
++                return false;
++
+             if (atEnd) {
+                 resume(262);
+                 return false;
+@@ -1945,7 +1960,11 @@
+         } break;
+ 
+         case 263:
+-            sym(1).len += fastScanName();
++            if (auto res = fastScanName())
++                sym(1).len += *res;
++            else
++                return false;
++
+             if (atEnd) {
+                 resume(263);
+                 return false;
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-38197.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-38197.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-38197.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-38197.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,219 @@
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/serialization/qxmlstream.cpp	2024-04-25 08:25:46.389994553 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream.cpp	2024-04-25 08:25:46.385994556 +0200
+@@ -160,7 +160,7 @@
+     addData() or by waiting for it to arrive on the device().
+ 
+     \value UnexpectedElementError The parser encountered an element
+-    that was different to those it expected.
++    or token that was different to those it expected.
+ 
+ */
+ 
+@@ -295,13 +295,34 @@
+ 
+   QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
+   include external parsed entities. As long as no error occurs, the
+-  application code can thus be assured that the data provided by the
+-  stream reader satisfies the W3C's criteria for well-formed XML. For
+-  example, you can be certain that all tags are indeed nested and
+-  closed properly, that references to internal entities have been
+-  replaced with the correct replacement text, and that attributes have
+-  been normalized or added according to the internal subset of the
+-  DTD.
++  application code can thus be assured, that
++  \list
++  \li the data provided by the stream reader satisfies the W3C's
++      criteria for well-formed XML,
++  \li tokens are provided in a valid order.
++  \endlist
++
++  Unless QXmlStreamReader raises an error, it guarantees the following:
++  \list
++  \li All tags are nested and closed properly.
++  \li References to internal entities have been replaced with the
++      correct replacement text.
++  \li Attributes have been normalized or added according to the
++      internal subset of the \l DTD.
++  \li Tokens of type \l StartDocument happen before all others,
++      aside from comments and processing instructions.
++  \li At most one DOCTYPE element (a token of type \l DTD) is present.
++  \li If present, the DOCTYPE appears before all other elements,
++      aside from StartDocument, comments and processing instructions.
++  \endlist
++
++  In particular, once any token of type \l StartElement, \l EndElement,
++  \l Characters, \l EntityReference or \l EndDocument is seen, no
++  tokens of type StartDocument or DTD will be seen. If one is present in
++  the input stream, out of order, an error is raised.
++
++  \note The token types \l Comment and \l ProcessingInstruction may appear
++  anywhere in the stream.
+ 
+   If an error occurs while parsing, atEnd() and hasError() return
+   true, and error() returns the error that occurred. The functions
+@@ -620,6 +641,7 @@
+         d->token = -1;
+         return readNext();
+     }
++    d->checkToken();
+     return d->type;
+ }
+ 
+@@ -740,6 +762,14 @@
+ };
+ 
+ 
++static const char QXmlStreamReader_XmlContextString[] =
++    "Prolog\0"
++    "Body\0";
++
++static const short QXmlStreamReader_XmlContextString_indices[] = {
++    0, 7
++};
++
+ /*!
+     \property  QXmlStreamReader::namespaceProcessing
+     The namespace-processing flag of the stream reader
+@@ -775,6 +805,16 @@
+                          QXmlStreamReader_tokenTypeString_indices[d->type]);
+ }
+ 
++/*!
++   \internal
++   \return \param ctxt (Prolog/Body) as a string.
++ */
++QString contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
++{
++    return QLatin1String(QXmlStreamReader_XmlContextString +
++                         QXmlStreamReader_XmlContextString_indices[static_cast<int>(ctxt)]);
++}
++
+ #endif // QT_NO_XMLSTREAMREADER
+ 
+ QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
+@@ -866,6 +906,8 @@
+ 
+     type = QXmlStreamReader::NoToken;
+     error = QXmlStreamReader::NoError;
++    currentContext = XmlContext::Prolog;
++    foundDTD = false;
+ }
+ 
+ /*
+@@ -4059,6 +4101,92 @@
+     }
+ }
+ 
++static bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
++                                               QXmlStreamReaderPrivate::XmlContext loc)
++{
++    switch (type) {
++    case QXmlStreamReader::StartDocument:
++    case QXmlStreamReader::DTD:
++        return loc == QXmlStreamReaderPrivate::XmlContext::Prolog;
++
++    case QXmlStreamReader::StartElement:
++    case QXmlStreamReader::EndElement:
++    case QXmlStreamReader::Characters:
++    case QXmlStreamReader::EntityReference:
++    case QXmlStreamReader::EndDocument:
++        return loc == QXmlStreamReaderPrivate::XmlContext::Body;
++
++    case QXmlStreamReader::Comment:
++    case QXmlStreamReader::ProcessingInstruction:
++        return true;
++
++    case QXmlStreamReader::NoToken:
++    case QXmlStreamReader::Invalid:
++        return false;
++    default:
++        return false;
++    }
++}
++
++/*!
++   \internal
++   \brief QXmlStreamReader::isValidToken
++   \return \c true if \param type is a valid token type.
++   \return \c false if \param type is an unexpected token,
++   which indicates a non-well-formed or invalid XML stream.
++ */
++bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
++{
++    // Don't change currentContext, if Invalid or NoToken occur in the prolog
++    if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
++        return false;
++
++    // If a token type gets rejected in the body, there is no recovery
++    const bool result = isTokenAllowedInContext(type, currentContext);
++    if (result || currentContext == XmlContext::Body)
++        return result;
++
++    // First non-Prolog token observed => switch context to body and check again.
++    currentContext = XmlContext::Body;
++    return isTokenAllowedInContext(type, currentContext);
++}
++
++/*!
++   \internal
++   Checks token type and raises an error, if it is invalid
++   in the current context (prolog/body).
++ */
++void QXmlStreamReaderPrivate::checkToken()
++{
++    Q_Q(QXmlStreamReader);
++
++    // The token type must be consumed, to keep track if the body has been reached.
++    const XmlContext context = currentContext;
++    const bool ok = isValidToken(type);
++
++    // Do nothing if an error has been raised already (going along with an unexpected token)
++    if (error != QXmlStreamReader::Error::NoError)
++        return;
++
++    if (!ok) {
++        raiseError(QXmlStreamReader::UnexpectedElementError,
++                   QLatin1String("Unexpected token type %1 in %2.")
++                   .arg(q->tokenString(), contextString(context)));
++        return;
++    }
++
++    if (type != QXmlStreamReader::DTD)
++        return;
++
++    // Raise error on multiple DTD tokens
++    if (foundDTD) {
++        raiseError(QXmlStreamReader::UnexpectedElementError,
++                   QLatin1String("Found second DTD token in %1.").arg(contextString(context)));
++    } else {
++        foundDTD = true;
++    }
++}
++
+ /*!
+  \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
+  \since 4.5
+Index: qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream_p.h
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/corelib/serialization/qxmlstream_p.h	2024-04-25 08:25:46.389994553 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/corelib/serialization/qxmlstream_p.h	2024-04-25 08:25:46.385994556 +0200
+@@ -804,6 +804,17 @@
+ #endif
+     bool atEnd;
+ 
++    enum class XmlContext
++    {
++        Prolog,
++        Body,
++    };
++
++    XmlContext currentContext = XmlContext::Prolog;
++    bool foundDTD = false;
++    bool isValidToken(QXmlStreamReader::TokenType type);
++    void checkToken();
++
+     /*!
+       \sa setType()
+      */
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-51714.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-51714.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-51714.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2023-51714.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,61 @@
+From 23c3fc483e8b6e21012a61f0bea884446f727776 Mon Sep 17 00:00:00 2001
+From: Marc Mutz <marc.mutz@qt.io>
+Date: Tue, 12 Dec 2023 22:08:07 +0100
+Subject: [PATCH] HPack: fix incorrect integer overflow check
+
+This code never worked:
+
+For the comparison with max() - 32 to trigger, on 32-bit platforms (or
+Qt 5) signed interger overflow would have had to happen in the
+addition of the two sizes. The compiler can therefore remove the
+overflow check as dead code.
+
+On Qt 6 and 64-bit platforms, the signed integer addition would be
+very unlikely to overflow, but the following truncation to uint32
+would yield the correct result only in a narrow 32-value window just
+below UINT_MAX, if even that.
+
+Fix by using the proper tool, qAddOverflow.
+
+Manual conflict resolutions:
+ - qAddOverflow doesn't exist in Qt 5, use private add_overflow
+   predecessor API instead
+
+Change-Id: I7599f2e75ff7f488077b0c60b81022591005661c
+Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
+(cherry picked from commit ee5da1f2eaf8932aeca02ffea6e4c618585e29e3)
+Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
+(cherry picked from commit debeb8878da2dc706ead04b6072ecbe7e5313860)
+Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
+Reviewed-by: Marc Mutz <marc.mutz@qt.io>
+(cherry picked from commit 811b9eef6d08d929af8708adbf2a5effb0eb62d7)
+(cherry picked from commit f931facd077ce945f1e42eaa3bead208822d3e00)
+(cherry picked from commit 9ef4ca5ecfed771dab890856130e93ef5ceabef5)
+Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
+---
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/network/access/http2/hpacktable.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/network/access/http2/hpacktable.cpp	2024-04-24 16:05:41.491907436 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/network/access/http2/hpacktable.cpp	2024-04-24 16:07:20.779882496 +0200
+@@ -40,6 +40,7 @@
+ #include "hpacktable_p.h"
+ 
+ #include <QtCore/qdebug.h>
++#include <QtCore/private/qnumeric_p.h>
+ 
+ #include <algorithm>
+ #include <cstddef>
+@@ -62,8 +63,10 @@
+     // for counting the number of references to the name and value would have
+     // 32 octets of overhead."
+ 
+-    const unsigned sum = unsigned(name.size() + value.size());
+-    if (std::numeric_limits<unsigned>::max() - 32 < sum)
++    size_t sum;
++    if (add_overflow(size_t(name.size()), size_t(value.size()), &sum))
++        return HeaderSize();
++    if (sum > (std::numeric_limits<unsigned>::max() - 32))
+         return HeaderSize();
+     return HeaderSize(true, quint32(sum + 32));
+ }
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2024-25580.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2024-25580.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2024-25580.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/CVE-2024-25580.diff	2024-02-27 23:25:41.000000000 +0100
@@ -0,0 +1,197 @@
+diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
+index 0d98e97453..6a79e55109 100644
+--- a/src/gui/util/qktxhandler.cpp
++++ b/src/gui/util/qktxhandler.cpp
+@@ -73,7 +73,7 @@ struct KTXHeader {
+     quint32 bytesOfKeyValueData;
+ };
+ 
+-static const quint32 headerSize = sizeof(KTXHeader);
++static constexpr quint32 qktxh_headerSize = sizeof(KTXHeader);
+ 
+ // Currently unused, declared for future reference
+ struct KTXKeyValuePairItem {
+@@ -103,11 +103,36 @@ struct KTXMipmapLevel {
+     */
+ };
+ 
+-bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
++static bool qAddOverflow(quint32 v1, quint32 v2, quint32 *r) {
++    // unsigned additions are well-defined
++    *r = v1 + v2;
++    return v1 > quint32(v1 + v2);
++}
++
++// Returns the nearest multiple of 4 greater than or equal to 'value'
++static bool nearestMultipleOf4(quint32 value, quint32 *result)
++{
++    constexpr quint32 rounding = 4;
++    *result = 0;
++    if (qAddOverflow(value, rounding - 1, result))
++        return true;
++    *result &= ~(rounding - 1);
++    return false;
++}
++
++// Returns a slice with prechecked bounds
++static QByteArray safeSlice(const QByteArray& array, quint32 start, quint32 length)
+ {
+-    Q_UNUSED(suffix)
++    quint32 end = 0;
++    if (qAddOverflow(start, length, &end) || end > quint32(array.length()))
++        return {};
++    return QByteArray(array.data() + start, length);
++}
+ 
+-    return (qstrncmp(block.constData(), ktxIdentifier, KTX_IDENTIFIER_LENGTH) == 0);
++bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
++{
++    Q_UNUSED(suffix);
++    return block.startsWith(QByteArray::fromRawData(ktxIdentifier, KTX_IDENTIFIER_LENGTH));
+ }
+ 
+ QTextureFileData QKtxHandler::read()
+@@ -115,42 +140,97 @@ QTextureFileData QKtxHandler::read()
+     if (!device())
+         return QTextureFileData();
+ 
+-    QByteArray buf = device()->readAll();
+-    const quint32 dataSize = quint32(buf.size());
+-    if (dataSize < headerSize || !canRead(QByteArray(), buf)) {
+-        qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
++    const QByteArray buf = device()->readAll();
++    if (size_t(buf.size()) > std::numeric_limits<quint32>::max()) {
++        qWarning(lcQtGuiTextureIO, "Too big KTX file %s", logName().constData());
++        return QTextureFileData();
++    }
++
++    if (!canRead(QByteArray(), buf)) {
++        qWarning(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
++        return QTextureFileData();
++    }
++
++    if (buf.size() < qsizetype(qktxh_headerSize)) {
++        qWarning(lcQtGuiTextureIO, "Invalid KTX header size in %s", logName().constData());
+         return QTextureFileData();
+     }
+ 
+-    const KTXHeader *header = reinterpret_cast<const KTXHeader *>(buf.constData());
+-    if (!checkHeader(*header)) {
+-        qCDebug(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
++    KTXHeader header;
++    memcpy(&header, buf.data(), qktxh_headerSize);
++    if (!checkHeader(header)) {
++        qWarning(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
+         return QTextureFileData();
+     }
+ 
+     QTextureFileData texData;
+     texData.setData(buf);
+ 
+-    texData.setSize(QSize(decode(header->pixelWidth), decode(header->pixelHeight)));
+-    texData.setGLFormat(decode(header->glFormat));
+-    texData.setGLInternalFormat(decode(header->glInternalFormat));
+-    texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
+-
+-    texData.setNumLevels(decode(header->numberOfMipmapLevels));
+-    quint32 offset = headerSize + decode(header->bytesOfKeyValueData);
+-    const int maxLevels = qMin(texData.numLevels(), 32);               // Cap iterations in case of corrupt file.
+-    for (int i = 0; i < maxLevels; i++) {
+-        if (offset + sizeof(KTXMipmapLevel) > dataSize)                // Corrupt file; avoid oob read
+-            break;
+-        const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset);
+-        quint32 levelLen = decode(level->imageSize);
+-        texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i);
+-        texData.setDataLength(levelLen, i);
+-        offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4));
++    texData.setSize(QSize(decode(header.pixelWidth), decode(header.pixelHeight)));
++    texData.setGLFormat(decode(header.glFormat));
++    texData.setGLInternalFormat(decode(header.glInternalFormat));
++    texData.setGLBaseInternalFormat(decode(header.glBaseInternalFormat));
++
++    texData.setNumLevels(decode(header.numberOfMipmapLevels));
++
++    const quint32 bytesOfKeyValueData = decode(header.bytesOfKeyValueData);
++    quint32 headerKeyValueSize;
++    if (qAddOverflow(qktxh_headerSize, bytesOfKeyValueData, &headerKeyValueSize)) {
++        qWarning(lcQtGuiTextureIO, "Overflow in size of key value data in header of KTX file %s",
++                 logName().constData());
++        return QTextureFileData();
++    }
++
++    if (headerKeyValueSize >= quint32(buf.size())) {
++        qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
++        return QTextureFileData();
++    }
++
++    // Technically, any number of levels is allowed but if the value is bigger than
++    // what is possible in KTX V2 (and what makes sense) we return an error.
++    // maxLevels = log2(max(width, height, depth))
++    const int maxLevels = (sizeof(quint32) * 8)
++            - qCountLeadingZeroBits(std::max(
++                    { header.pixelWidth, header.pixelHeight, header.pixelDepth }));
++
++    if (texData.numLevels() > maxLevels) {
++        qWarning(lcQtGuiTextureIO, "Too many levels in KTX file %s", logName().constData());
++        return QTextureFileData();
++    }
++
++    quint32 offset = headerKeyValueSize;
++    for (int level = 0; level < texData.numLevels(); level++) {
++        const auto imageSizeSlice = safeSlice(buf, offset, sizeof(quint32));
++        if (imageSizeSlice.isEmpty()) {
++            qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
++            return QTextureFileData();
++        }
++
++        const quint32 imageSize = decode(qFromUnaligned<quint32>(imageSizeSlice.data()));
++        offset += sizeof(quint32); // overflow checked indirectly above
++
++        texData.setDataOffset(offset, level);
++        texData.setDataLength(imageSize, level);
++
++        // Add image data and padding to offset
++        quint32 padded = 0;
++        if (nearestMultipleOf4(imageSize, &padded)) {
++            qWarning(lcQtGuiTextureIO, "Overflow in KTX file %s", logName().constData());
++            return QTextureFileData();
++        }
++
++        quint32 offsetNext;
++        if (qAddOverflow(offset, padded, &offsetNext)) {
++            qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
++            return QTextureFileData();
++        }
++
++        offset = offsetNext;
+     }
+ 
+     if (!texData.isValid()) {
+-        qCDebug(lcQtGuiTextureIO, "Invalid values in header of KTX file %s", logName().constData());
++        qWarning(lcQtGuiTextureIO, "Invalid values in header of KTX file %s",
++                 logName().constData());
+         return QTextureFileData();
+     }
+ 
+@@ -191,7 +271,7 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
+             (decode(header.numberOfFaces) == 1));
+ }
+ 
+-quint32 QKtxHandler::decode(quint32 val)
++quint32 QKtxHandler::decode(quint32 val) const
+ {
+     return inverseEndian ? qbswap<quint32>(val) : val;
+ }
+diff --git a/src/gui/util/qktxhandler_p.h b/src/gui/util/qktxhandler_p.h
+index f831e59d95..cdf1b2eaf8 100644
+--- a/src/gui/util/qktxhandler_p.h
++++ b/src/gui/util/qktxhandler_p.h
+@@ -68,7 +68,7 @@ public:
+ 
+ private:
+     bool checkHeader(const KTXHeader &header);
+-    quint32 decode(quint32 val);
++    quint32 decode(quint32 val) const;
+ 
+     bool inverseEndian = false;
+ };
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/series qtbase-opensource-src-5.15.2+dfsg/debian/patches/series
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/series	2021-07-02 17:58:04.000000000 +0200
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/series	2024-04-28 22:48:02.000000000 +0200
@@ -6,6 +6,19 @@
 mime_globs.diff
 fix-invalid-pointer-return-with-QGridLayout.diff
 
+CVE-2024-25580.diff
+CVE-2023-32763.diff
+CVE-2022-25255.diff
+CVE-2023-24607.diff
+sql_odbc_fix_unicode_check.diff
+sql_odbc_more_unicode_checks.diff
+CVE-2023-32762.diff
+CVE-2023-51714.diff
+CVE-2023-37369.diff
+CVE-2023-38197.diff
+CVE-2023-34410.diff
+CVE-2023-33285.diff
+
 # Debian specific.
 gnukfreebsd.diff
 no_htmlinfo_example.diff
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_fix_unicode_check.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_fix_unicode_check.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_fix_unicode_check.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_fix_unicode_check.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,24 @@
+Description: QSQL/ODBC: fix regression (trailing NUL)
+ When we fixed the callers of toSQLTCHAR() to use the result's size()
+ instead of the input's (which differ, if sizeof(SQLTCHAR) != 2), we
+ exposed callers to the append(0), which changes the size() of the
+ result QVLA. Callers that don't rely on NUL-termination (all?) now saw
+ an additional training NUL.
+ .
+ Fix by not NUL-terminating, and changing the only user of SQL_NTS to
+ use an explicit length.
+Origin: upstream, https://code.qt.io/cgit/qt/qtbase.git/commit/?id=9020034b3b6a3a81
+Last-Update: 2023-06-30
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-04-28 17:51:58.976069584 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-04-28 17:51:58.972069583 +0200
+@@ -125,7 +125,6 @@
+ {
+     QVarLengthArray<SQLTCHAR> result;
+     toSQLTCHARImpl(result, input);
+-    result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
+     return result;
+ }
+ 
diff -Nru qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_more_unicode_checks.diff qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_more_unicode_checks.diff
--- qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_more_unicode_checks.diff	1970-01-01 01:00:00.000000000 +0100
+++ qtbase-opensource-src-5.15.2+dfsg/debian/patches/sql_odbc_more_unicode_checks.diff	2024-04-28 22:48:02.000000000 +0200
@@ -0,0 +1,37 @@
+Description: SQL/ODBC: add another check to detect unicode availability in driver
+ Since ODBC does not have a direct way finding out if unicode is
+ supported by the underlying driver the ODBC plugin does some checks. As
+ a last resort a sql statement is executed which returns a string. But
+ even this may fail because the select statement has no FROM part which
+ is rejected by at least Oracle does not allow. Therefore add another
+ query which is correct for Oracle & DB2 as a workaround. The question
+ why the first three statements to check for unicode availability fail
+ is still open but can't be checked since I've no access to an oracle
+ database.
+Origin: upstream, https://code.qt.io/cgit/qt/qtbase.git/commit/?id=f19320748d282b1e
+Last-Update: 2023-06-30
+
+Index: qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+===================================================================
+--- qtbase-opensource-src-5.15.2+dfsg.orig/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-04-28 17:59:07.172222178 +0200
++++ qtbase-opensource-src-5.15.2+dfsg/src/plugins/sqldrivers/odbc/qsql_odbc.cpp	2024-04-28 17:59:07.172222178 +0200
+@@ -2109,7 +2109,18 @@
+                                   hDbc,
+                                   &hStmt);
+ 
+-    r = SQLExecDirect(hStmt, toSQLTCHAR(QLatin1String("select 'test'")).data(), SQL_NTS);
++    // for databases which do not return something useful in SQLGetInfo and are picky about a
++    // 'SELECT' statement without 'FROM' but support VALUE(foo) statement like e.g. DB2 or Oracle
++    const auto statements = {
++        QLatin1String("select 'test'"),
++        QLatin1String("values('test')"),
++        QLatin1String("select 'test' from dual"),
++    };
++    for (const auto &statement : statements) {
++        r = SQLExecDirect(hStmt, toSQLTCHAR(statement).data(), SQL_NTS);
++        if (r == SQL_SUCCESS)
++            break;
++    }
+     if(r == SQL_SUCCESS) {
+         r = SQLFetch(hStmt);
+         if(r == SQL_SUCCESS) {

--- End Message ---
--- Begin Message ---
Version: 11.10

The upload requested in this bug has been released as part of 11.10.

--- End Message ---

Reply to: