summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2024-01-27 09:17:57 +0100
committerMarc Mutz <marc.mutz@qt.io>2024-01-31 21:18:47 +0100
commit0808beace332631f8100b5700577f10f63e4630c (patch)
tree93accea50f363e25f77c8cc74922c977c4aafeb8
parent40a87ca1b421457fc2a31cf385eb5a0eda83486f (diff)
QBitArray: fix potential truncation in QDataStream op>>()
In Qt 5, a QBitArray could not contain more than INT_MAX bits, because the then-size_type, int, cannot represent more, even if the underlying storage could hold 8x as much, and the serialisation format, using unsigned int, could represent 2x. Therefore, reject old formats with sizes that exceed INT_MAX elements as corrupt. Likewise, the Qt 6 serialisation format unconditionally uses 64-bit sizes, but 32-bit platforms still cannot represent more than numeric_limits<qsizetype>::max() (= INT_MAX) bits in memory. This is a valid stream for 64-bit platforms, though, so ideally, this should be using SizeLimitsExeeded, which, however, is only available from Qt 6.7. So, for now, and until we have SizeLimitsExeeded, mark the stream as corrupt here, too. [ChangeLog][QtCore][QBitArray] Fixed undetected overflows in the deserialisation (opertor>>()) from QDataStream. Pick-to: 6.7 6.6 6.5 6.2 5.15 Change-Id: Ib24cf9218c06a3a05185723c77d4313611c2dd40 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/tools/qbitarray.cpp11
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp2
2 files changed, 13 insertions, 0 deletions
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index cc3b8a15cf..ef30b97a6c 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -7,6 +7,9 @@
#include <qdatastream.h>
#include <qdebug.h>
#include <qendian.h>
+
+#include <limits>
+
#include <string.h>
QT_BEGIN_NAMESPACE
@@ -921,10 +924,18 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
if (in.version() < QDataStream::Qt_6_0) {
quint32 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint32((std::numeric_limits<qint32>::max)()))) {
+ in.setStatus(QDataStream::ReadCorruptData);
+ return in;
+ }
len = tmp;
} else {
quint64 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint64((std::numeric_limits<qsizetype>::max)()))) {
+ in.setStatus(QDataStream::ReadCorruptData); // ### SizeLimitExeeded
+ return in;
+ }
len = tmp;
}
if (len == 0) {
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index 8051924dce..c6d9d5d4ab 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -2984,6 +2984,8 @@ void tst_QDataStream::status_QBitArray_data()
QTest::newRow("badsize 16") << QDataStream::Qt_5_15 << QByteArray("\x00\x00\x00\x10\xff", 5) << (int) QDataStream::ReadPastEnd << QBitArray();
QTest::newRow("badsize 17") << QDataStream::Qt_5_15 << QByteArray("\x00\x00\x00\x11\xff\xff", 6) << (int) QDataStream::ReadPastEnd << QBitArray();
QTest::newRow("badsize 32") << QDataStream::Qt_5_15 << QByteArray("\x00\x00\x00\x20\xff\xff\xff", 7) << (int) QDataStream::ReadPastEnd << QBitArray();
+ QTest::newRow("badsize INT_MAX") << QDataStream::Qt_5_15 << QByteArray("\x7f\xff\xff\xff\xff\xff\xff", 7) << int(QDataStream::ReadPastEnd) << QBitArray(); // size accepted
+ QTest::addRow("badsize INT_MAX + 1") << QDataStream::Qt_5_15 << QByteArray("\x80\x00\x00\x01" "\xff\xff\xff", 7) << int(QDataStream::ReadCorruptData) << QBitArray(); // size rejected
QTest::newRow("new badsize 0") << QDataStream::Qt_6_0 << QByteArray("\x00\x00\x00\x00", 4) << (int) QDataStream::ReadPastEnd << QBitArray();
QTest::newRow("new badsize 9") << QDataStream::Qt_6_0 << QByteArray("\x00\x00\x00\x00\x00\x00\x00\x09\xff", 9) << (int) QDataStream::ReadPastEnd << QBitArray();
QTest::newRow("new badsize 0x10000") << QDataStream::Qt_6_0 << QByteArray("\x00\x00\x00\x01\x00\x00\x00\x00\x00", 9) << (int) QDataStream::ReadPastEnd << QBitArray();