From bf43d2e9657788c4c8656b96c40da6f309b84918 Mon Sep 17 00:00:00 2001
From: Marc Mutz <marc.mutz@qt.io>
Date: Wed, 17 Jun 2026 10:58:05 +0200
Subject: [PATCH] QCborValue: fix buffer overread in fromCbor()

Another brown paper bag left-over from the int → qsizetype port, this
one unfortunately with grave impact (if users parse 2GiB+)

CBOR uses explicit length prefixes, so input that is well-formed within
the first `len` bytes still decodes to the same value. But if int(len)
is negative, QByteArray falls back to strlen(): for NUL-free content it
reads past the end of the buffer and copies the trailing bytes into the
QByteArray. That has two consequences. First, the strlen()/memcpy walks
off the buffer and crashes if no NUL byte is found before the next
unmapped page. Second, and worse, a crafted CBOR string-length prefix
placed near the end of `len` can point into the over-read region; the
parser then reads those out-of-bounds bytes and returns them in the
resulting QCborValue. The decoded string data is deep-copied into the
value, so it outlives the temporary QByteArray and is handed to the
caller, which may publish it.

[ChangeLog][QtCore][QCborValue] Fixed a bug on 64-bit platforms that
would mishandle data passed to the (ptr, len, error) overloads if len ≥
2Gi, leading to incorrect decoding errors or an overread of ptr past
len: the bytes following the buffer are copied into a heap-allocated
buffer and, for crafted input, can be returned to the caller in the
decoded value (out-of-bounds read / information disclosure). You need to
recompile users of this function for the fix to take effect; updating Qt
alone is not sufficient. A backwards-compatible fix that does not
require a Qt update is to construct the QByteArray from (ptr, len)
yourself and using the fromCbor(QByteArray) overload. This preserves the
length.

Amends 92e472302a0ef8390f60fd91cac7f360b199a1e4 (5.12), but really the
port of QByteArray from int to qsizetype size_type (6.0).

Found and fixed by yours truly, but severity was only really exposed by
Claude repeatedly reviewing the patch.

Pick-to: 6.5
Change-Id: Iec6cb64bb54691605c064f1fcd9f57606b991b0c
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 64f07e1ee05f22447a6bd1d74ec3293419c93c5d)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit dd3bfad6ded67d075bbe931ea7231e42fb1d19b8)
(cherry picked from commit b8c274c569eea7e3d0f146f9369e24420eebd4f3)
---

diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
index 1ec48bc..374926a 100644
--- a/src/corelib/serialization/qcborvalue.h
+++ b/src/corelib/serialization/qcborvalue.h
@@ -238,9 +238,9 @@
     static QCborValue fromCbor(QCborStreamReader &reader);
     static QCborValue fromCbor(const QByteArray &ba, QCborParserError *error = nullptr);
     static QCborValue fromCbor(const char *data, qsizetype len, QCborParserError *error = nullptr)
-    { return fromCbor(QByteArray(data, int(len)), error); }
+    { return fromCbor(QByteArray(data, len), error); }
     static QCborValue fromCbor(const quint8 *data, qsizetype len, QCborParserError *error = nullptr)
-    { return fromCbor(QByteArray(reinterpret_cast<const char *>(data), int(len)), error); }
+    { return fromCbor(QByteArray(reinterpret_cast<const char *>(data), len), error); }
 #endif // QT_CONFIG(cborstreamreader)
 #if QT_CONFIG(cborstreamwriter)
     QByteArray toCbor(EncodingOptions opt = NoTransformation) const;
