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.6 6.5 6.2 5.15
Change-Id: Ib24cf9218c06a3a05185723c77d4313611c2dd40
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 0808beace332631f8100b5700577f10f63e4630c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-01-27 09:17:57 +01:00 committed by Qt Cherry-pick Bot
parent c86002f7ab
commit d61a333705
2 changed files with 13 additions and 0 deletions

View File

@ -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) {

View File

@ -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();