Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qt6-httpserver for openSUSE:Factory 
checked in at 2026-11-05 18:28:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qt6-httpserver (Old)
 and      /work/SRC/openSUSE:Factory/.qt6-httpserver.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qt6-httpserver"

Thu Nov  5 18:28:31 2026 rev:31 rq:1394836 version:6.12.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qt6-httpserver/qt6-httpserver.changes    
2026-10-18 19:21:27.852133524 +0200
+++ 
/work/SRC/openSUSE:Factory/.qt6-httpserver.new.3759290/qt6-httpserver.changes   
    2026-11-05 18:28:34.387351472 +0100
@@ -1,0 +2,6 @@
+Wed Nov  4 07:47:28 UTC 2026 - Christophe Marin <[email protected]>
+
+- Add upstream change (CVE-2026-110944)
+  * CVE-2026-110944-qthttpserver-6.12-0001.diff
+
+-------------------------------------------------------------------

New:
----
  CVE-2026-110944-qthttpserver-6.12-0001.diff

----------(New B)----------
  New:- Add upstream change (CVE-2026-110944)
  * CVE-2026-110944-qthttpserver-6.12-0001.diff
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qt6-httpserver.spec ++++++
--- /var/tmp/diff_new_pack.4rc4NP/_old  2026-11-05 18:28:35.421394470 +0100
+++ /var/tmp/diff_new_pack.4rc4NP/_new  2026-11-05 18:28:35.424394594 +0100
@@ -33,6 +33,8 @@
 License:        GPL-3.0-only
 URL:            https://www.qt.io
 Source0:        
https://download.qt.io/official_releases/qt/%{short_version}/%{real_version}%{tar_suffix}/submodules/%{tar_name}-%{real_version}%{tar_suffix}.tar.xz
+# PATCH-FIX-UPSTREAM
+Patch0:         CVE-2026-110944-qthttpserver-6.12-0001.diff
 BuildRequires:  pkgconfig
 BuildRequires:  cmake(Qt6Concurrent) = %{real_version}
 BuildRequires:  cmake(Qt6Core) = %{real_version}

++++++ CVE-2026-110944-qthttpserver-6.12-0001.diff ++++++
>From d0b683915dd1d29a161366e074aae50ba932c24f Mon Sep 17 00:00:00 2001
From: Mate Barany <[email protected]>
Date: Tue, 08 Sep 2026 17:15:25 +0200
Subject: [PATCH] Cap chunk-size line length to prevent memory exhaustion

getChunkSize() appended the chunk-size line into the shared fragment
buffer byte by byte with no ceiling, and the body-size limit never
applies (it gates decoded body bytes only). A chunked request with an
endless hex string or unterminated chunk-extension thus grew fragment
until OOM.

Bound it per byte via isHeaderFieldSizeAllowed() (48 KiB),
sending 400 and returning -1.

Fixes: QTBUG-150270
Pick-to: 6.12.0 6.11
Change-Id: I104d2adca36710ca812e58024dfc5544dcba52af
Reviewed-by: MÃ¥rten Nordheim <[email protected]>
Reviewed-by: Thiago Macieira <[email protected]>
(cherry picked from commit 988f1d72679f4fe55442af4f431d1c5b11171656)
Reviewed-by: Qt Cherry-pick Bot <[email protected]>
---

diff --git a/src/httpserver/qhttpserverparser.cpp 
b/src/httpserver/qhttpserverparser.cpp
index 4fbec04..dd5b563 100644
--- a/src/httpserver/qhttpserverparser.cpp
+++ b/src/httpserver/qhttpserverparser.cpp
@@ -563,7 +563,10 @@
             }
             // Note that chunk size gets stored in currentChunkSize, what is 
returned is the bytes
             // read
-            bytes += getChunkSize(socket, &currentChunkSize);
+            const qsizetype chunkSizeBytes = getChunkSize(socket, 
&currentChunkSize);
+            if (chunkSizeBytes < 0)
+                return -1;
+            bytes += chunkSizeBytes;
             if (currentChunkSize == -1)
                 break;
             if (!filter->isBodySizeAllowed(bodyBuffer.byteAmount() + 
currentChunkSize)) {
@@ -643,6 +646,14 @@
 
             bytes += haveRead;
             fragment.append(c);
+            if (!filter->isHeaderFieldSizeAllowed(fragment.size())) {
+                sendError(socket, 
QHttpServerResponder::StatusCode::BadRequest);
+                socket->skip(socket->bytesAvailable());
+                qCDebug(lcHttpServerParser) << "Chunk size line too long at" 
<< fragment.size()
+                                            << "bytes from client" << 
getClientIpAddressAndPort();
+                fragment.clear();
+                return -1;
+            }
         }
     }
 
diff --git a/tests/auto/qabstracthttpserver/tst_qabstracthttpserver.cpp 
b/tests/auto/qabstracthttpserver/tst_qabstracthttpserver.cpp
index 1ef3fc2..39ac8dc 100644
--- a/tests/auto/qabstracthttpserver/tst_qabstracthttpserver.cpp
+++ b/tests/auto/qabstracthttpserver/tst_qabstracthttpserver.cpp
@@ -154,6 +154,8 @@
     void http2request();
     void socketDisconnected();
     void keepAliveTimeout();
+    void chunkedRequest();
+    void chunkedSizeLineTooLong();
 
 private:
 #if QT_CONFIG(ssl)
@@ -990,6 +992,90 @@
 #endif // QT_CONFIG(ssl)
 }
 
+void tst_QAbstractHttpServer::chunkedRequest()
+{
+    struct HttpServer : QAbstractHttpServer
+    {
+        QByteArray body;
+        bool handleRequest(const QHttpServerRequest &request,
+                           QHttpServerResponder &responder) override
+        {
+            body = request.body();
+            auto _responder = std::move(responder);
+            return true;
+        }
+
+        void missingHandler(const QHttpServerRequest &, QHttpServerResponder 
&) override { }
+    } server;
+
+    QTcpServer tcpServer;
+    QVERIFY(tcpServer.listen());
+    server.bind(&tcpServer);
+
+    QTcpSocket client;
+    client.connectToHost(QHostAddress::LocalHost, tcpServer.serverPort());
+    QVERIFY(client.waitForConnected());
+
+    // A well-formed chunked request body must be decoded and delivered.
+    client.write("POST / HTTP/1.1\r\n"
+                 "Host: localhost\r\n"
+                 "Transfer-Encoding: chunked\r\n"
+                 "\r\n"
+                 "5\r\nHello\r\n"
+                 "6\r\n World\r\n"
+                 "0\r\n\r\n");
+    QVERIFY(client.waitForBytesWritten());
+
+    QTRY_COMPARE(server.body, QByteArray("Hello World"));
+}
+
+void tst_QAbstractHttpServer::chunkedSizeLineTooLong()
+{
+    struct HttpServer : QAbstractHttpServer
+    {
+        bool handleRequestCalled = false;
+        bool handleRequest(const QHttpServerRequest &, QHttpServerResponder 
&responder) override
+        {
+            handleRequestCalled = true;
+            auto _responder = std::move(responder);
+            return true;
+        }
+
+        void missingHandler(const QHttpServerRequest &, QHttpServerResponder 
&) override { }
+    } server;
+
+    QTcpServer tcpServer;
+    QVERIFY(tcpServer.listen());
+    server.bind(&tcpServer);
+
+    // Lower the per-field limit (default 48 KiB) so a few hundred bytes trip 
the
+    // size-line cap
+    QHttpServerConfiguration config;
+    config.setMaximumHeaderFieldSize(256);
+    server.setConfiguration(config);
+
+    QTcpSocket client;
+    client.connectToHost(QHostAddress::LocalHost, tcpServer.serverPort());
+    QVERIFY(client.waitForConnected());
+
+    // Send a chunk-size line that never terminates: a run of digits with no 
CRLF.
+    // This is not a valid chunk. The parser must bound the size-line buffer,
+    // reply 400, and close.
+    QByteArray request = "POST / HTTP/1.1\r\n"
+                         "Host: localhost\r\n"
+                         "Transfer-Encoding: chunked\r\n"
+                         "\r\n";
+    request += QByteArray(512, '0'); // exceeds the 256-byte size-line cap, no 
CRLF
+    client.write(request);
+    QVERIFY(client.waitForBytesWritten());
+
+    // waitForDisconnected() would only wait on the client socket and time out
+    QTRY_COMPARE(client.state(), QAbstractSocket::UnconnectedState);
+    const QByteArray response = client.readAll();
+    QVERIFY2(response.startsWith("HTTP/1.1 400"), response.constData());
+    QVERIFY(!server.handleRequestCalled);
+}
+
 QT_END_NAMESPACE
 
 QTEST_MAIN(tst_QAbstractHttpServer)

Reply via email to